216 lines
6.6 KiB
JavaScript
216 lines
6.6 KiB
JavaScript
import { moveUp, moveDown, moveLeft, moveRight } from "./cursor.js";
|
|
import { hasSelection, selectedRange, clearSelection, deleteSelection } from "./selection.js";
|
|
import { elementToPos } from "./mouse.js";
|
|
|
|
export function setupInput(buffer, cursor, selection, onChange) {
|
|
let isMouseDown = false;
|
|
|
|
function startDrag(e) {
|
|
if (!e.target.closest("#text")) return;
|
|
isMouseDown = true;
|
|
const pos = elementToPos(e.clientX, e.clientY, buffer);
|
|
cursor.line = pos.line;
|
|
cursor.col = pos.col;
|
|
selection.anchor = { ...pos };
|
|
selection.head = { ...pos };
|
|
onChange();
|
|
}
|
|
|
|
function drag(e) {
|
|
if (!isMouseDown) return;
|
|
const pos = elementToPos(e.clientX, e.clientY, buffer);
|
|
cursor.line = pos.line;
|
|
cursor.col = pos.col;
|
|
selection.head = { ...pos };
|
|
onChange();
|
|
}
|
|
|
|
function endDrag() {
|
|
isMouseDown = false;
|
|
}
|
|
|
|
function selectWord(e) {
|
|
if (!e.target.closest("#text")) return;
|
|
const pos = elementToPos(e.clientX, e.clientY, buffer);
|
|
const line = buffer[pos.line];
|
|
let start = pos.col;
|
|
let end = pos.col;
|
|
while (start > 0 && /\w/.test(line[start - 1])) start--;
|
|
while (end < line.length && /\w/.test(line[end])) end++;
|
|
cursor.line = pos.line;
|
|
cursor.col = end;
|
|
selection.anchor = { line: pos.line, col: start };
|
|
selection.head = { line: pos.line, col: end };
|
|
onChange();
|
|
}
|
|
|
|
function moveCursor(newLine, newCol, extending) {
|
|
if (extending) {
|
|
if (selection.anchor === null)
|
|
selection.anchor = { line: cursor.line, col: cursor.col };
|
|
selection.head = { line: newLine, col: newCol };
|
|
} else {
|
|
clearSelection(selection);
|
|
}
|
|
cursor.line = newLine;
|
|
cursor.col = newCol;
|
|
}
|
|
|
|
function getSelectedText() {
|
|
const range = selectedRange(selection);
|
|
if (!range) return "";
|
|
const { start, end } = range;
|
|
if (start.line === end.line)
|
|
return buffer[start.line].slice(start.col, end.col);
|
|
const lines = [buffer[start.line].slice(start.col)];
|
|
for (let i = start.line + 1; i < end.line; i++)
|
|
lines.push(buffer[i]);
|
|
lines.push(buffer[end.line].slice(0, end.col));
|
|
return lines.join("\n");
|
|
}
|
|
|
|
function insertText(text) {
|
|
if (hasSelection(selection)) deleteSelection(buffer, cursor, selection);
|
|
const pasteLines = text.split("\n");
|
|
const line = buffer[cursor.line];
|
|
const before = line.slice(0, cursor.col);
|
|
const after = line.slice(cursor.col);
|
|
buffer[cursor.line] = before + pasteLines[0] + after;
|
|
for (let i = 1; i < pasteLines.length; i++)
|
|
buffer.splice(cursor.line + i, 0, pasteLines[i]);
|
|
cursor.line += pasteLines.length - 1;
|
|
cursor.col = pasteLines[pasteLines.length - 1].length +
|
|
(pasteLines.length === 1 ? before.length : 0);
|
|
clearSelection(selection);
|
|
}
|
|
|
|
function selectAll() {
|
|
selection.anchor = { line: 0, col: 0 };
|
|
selection.head = { line: buffer.length - 1, col: buffer[buffer.length - 1].length };
|
|
cursor.line = buffer.length - 1;
|
|
cursor.col = buffer[buffer.length - 1].length;
|
|
}
|
|
|
|
document.addEventListener("mousedown", startDrag);
|
|
document.addEventListener("mousemove", drag);
|
|
document.addEventListener("mouseup", endDrag);
|
|
document.addEventListener("dblclick", selectWord);
|
|
|
|
document.addEventListener("paste", (e) => {
|
|
e.preventDefault();
|
|
const text = e.clipboardData.getData("text");
|
|
if (!text) return;
|
|
insertText(text);
|
|
onChange();
|
|
});
|
|
|
|
document.addEventListener("keydown", (e) => {
|
|
const mod = e.ctrlKey || e.metaKey;
|
|
const extending = e.shiftKey;
|
|
|
|
if (mod) {
|
|
if (e.key === "c") {
|
|
e.preventDefault();
|
|
const text = getSelectedText();
|
|
if (text) navigator.clipboard.writeText(text);
|
|
return;
|
|
}
|
|
if (e.key === "x") {
|
|
e.preventDefault();
|
|
const text = getSelectedText();
|
|
if (text) navigator.clipboard.writeText(text);
|
|
deleteSelection(buffer, cursor, selection);
|
|
onChange();
|
|
return;
|
|
}
|
|
if (e.key === "v") {
|
|
return;
|
|
}
|
|
if (e.key === "a") {
|
|
e.preventDefault();
|
|
selectAll();
|
|
onChange();
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (e.key === "ArrowUp") {
|
|
e.preventDefault();
|
|
const newLine = Math.max(0, cursor.line - 1);
|
|
const newCol = Math.min(cursor.col, buffer[newLine].length);
|
|
moveCursor(newLine, newCol, extending);
|
|
onChange();
|
|
return;
|
|
}
|
|
if (e.key === "ArrowDown") {
|
|
e.preventDefault();
|
|
const newLine = Math.min(buffer.length - 1, cursor.line + 1);
|
|
const newCol = Math.min(cursor.col, buffer[newLine].length);
|
|
moveCursor(newLine, newCol, extending);
|
|
onChange();
|
|
return;
|
|
}
|
|
if (e.key === "ArrowLeft") {
|
|
e.preventDefault();
|
|
let newLine = cursor.line;
|
|
let newCol = cursor.col;
|
|
if (newCol > 0) newCol--;
|
|
else if (newLine > 0) { newLine--; newCol = buffer[newLine].length; }
|
|
moveCursor(newLine, newCol, extending);
|
|
onChange();
|
|
return;
|
|
}
|
|
if (e.key === "ArrowRight") {
|
|
e.preventDefault();
|
|
let newLine = cursor.line;
|
|
let newCol = cursor.col;
|
|
if (newCol < buffer[cursor.line].length) newCol++;
|
|
else if (newLine < buffer.length - 1) { newLine++; newCol = 0; }
|
|
moveCursor(newLine, newCol, extending);
|
|
onChange();
|
|
return;
|
|
}
|
|
if (e.key === "Backspace") {
|
|
e.preventDefault();
|
|
if (hasSelection(selection)) {
|
|
deleteSelection(buffer, cursor, selection);
|
|
} else if (cursor.col > 0) {
|
|
const line = buffer[cursor.line];
|
|
buffer[cursor.line] = line.slice(0, cursor.col - 1) + line.slice(cursor.col);
|
|
cursor.col--;
|
|
} else if (cursor.line > 0) {
|
|
cursor.col = buffer[cursor.line - 1].length;
|
|
buffer[cursor.line - 1] += buffer[cursor.line];
|
|
buffer.splice(cursor.line, 1);
|
|
cursor.line--;
|
|
}
|
|
clearSelection(selection);
|
|
onChange();
|
|
return;
|
|
}
|
|
if (e.key === "Enter") {
|
|
e.preventDefault();
|
|
if (hasSelection(selection)) deleteSelection(buffer, cursor, selection);
|
|
const line = buffer[cursor.line];
|
|
const rest = line.slice(cursor.col);
|
|
buffer[cursor.line] = line.slice(0, cursor.col);
|
|
buffer.splice(cursor.line + 1, 0, rest);
|
|
cursor.line++;
|
|
cursor.col = 0;
|
|
clearSelection(selection);
|
|
onChange();
|
|
return;
|
|
}
|
|
if (e.key.length === 1) {
|
|
e.preventDefault();
|
|
if (hasSelection(selection)) deleteSelection(buffer, cursor, selection);
|
|
const line = buffer[cursor.line];
|
|
buffer[cursor.line] = line.slice(0, cursor.col) + e.key + line.slice(cursor.col);
|
|
cursor.col++;
|
|
clearSelection(selection);
|
|
onChange();
|
|
}
|
|
});
|
|
}
|