Basic deletion functionality
This commit is contained in:
parent
a7f5fed9a3
commit
b665ce8ce7
@ -18,6 +18,12 @@ const {
|
|||||||
testSuite,
|
testSuite,
|
||||||
} = await getTestRunner();
|
} = await getTestRunner();
|
||||||
|
|
||||||
|
const testKeyMap = (codes: string[], expected: string) => {
|
||||||
|
codes.forEach((code) => {
|
||||||
|
assertEquals(readKey(code), expected);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
testSuite({
|
testSuite({
|
||||||
'ANSI::ANSI utils': {
|
'ANSI::ANSI utils': {
|
||||||
'Ansi.moveCursor': () => {
|
'Ansi.moveCursor': () => {
|
||||||
@ -39,27 +45,21 @@ testSuite({
|
|||||||
assertEquals(readKey(KeyCommand.ArrowUp), KeyCommand.ArrowUp);
|
assertEquals(readKey(KeyCommand.ArrowUp), KeyCommand.ArrowUp);
|
||||||
assertEquals(readKey(KeyCommand.Home), KeyCommand.Home);
|
assertEquals(readKey(KeyCommand.Home), KeyCommand.Home);
|
||||||
assertEquals(readKey(KeyCommand.Delete), KeyCommand.Delete);
|
assertEquals(readKey(KeyCommand.Delete), KeyCommand.Delete);
|
||||||
|
|
||||||
|
// And pass through whatever else
|
||||||
|
assertEquals(readKey('foobaz'), 'foobaz');
|
||||||
},
|
},
|
||||||
'readKey Esc': () => {
|
'readKey Esc': () =>
|
||||||
['\x1b', Util.ctrlKey('l')].forEach((code) => {
|
testKeyMap(['\x1b', Util.ctrlKey('l')], KeyCommand.Escape),
|
||||||
assertEquals(readKey(code), KeyCommand.Escape);
|
'readKey Backspace': () =>
|
||||||
});
|
testKeyMap(
|
||||||
},
|
[Util.ctrlKey('h'), '\x7f'],
|
||||||
'readKey Backspace': () => {
|
KeyCommand.Backspace,
|
||||||
[Util.ctrlKey('h'), String.fromCodePoint(127)].forEach((code) => {
|
),
|
||||||
assertEquals(readKey(code), KeyCommand.Backspace);
|
'readKey Home': () =>
|
||||||
});
|
testKeyMap(['\x1b[1~', '\x1b[7~', '\x1b[H', '\x1bOH'], KeyCommand.Home),
|
||||||
},
|
'readKey End': () =>
|
||||||
'readKey Home': () => {
|
testKeyMap(['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'], KeyCommand.End),
|
||||||
['\x1b[1~', '\x1b[7~', '\x1b[H', '\x1bOH'].forEach((code) => {
|
|
||||||
assertEquals(readKey(code), KeyCommand.Home);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'readKey End': () => {
|
|
||||||
['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'].forEach((code) => {
|
|
||||||
assertEquals(readKey(code), KeyCommand.End);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Buffer: {
|
Buffer: {
|
||||||
'Buffer exists': () => {
|
'Buffer exists': () => {
|
||||||
@ -137,6 +137,12 @@ testSuite({
|
|||||||
assertEquals(doc.numRows, 2);
|
assertEquals(doc.numRows, 2);
|
||||||
assertTrue(doc.dirty);
|
assertTrue(doc.dirty);
|
||||||
},
|
},
|
||||||
|
'Document.delete': () => {
|
||||||
|
const doc = Document.empty();
|
||||||
|
doc.insert(Position.default(), 'foobar');
|
||||||
|
doc.delete(Position.at(3, 0));
|
||||||
|
assertEquals(doc.row(0)?.toString(), 'fooar');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Editor: {
|
Editor: {
|
||||||
'new Editor': () => {
|
'new Editor': () => {
|
||||||
|
@ -76,7 +76,7 @@ export function readKey(parsed: string): string {
|
|||||||
return KeyCommand.Escape;
|
return KeyCommand.Escape;
|
||||||
|
|
||||||
case ctrlKey('h'):
|
case ctrlKey('h'):
|
||||||
case String.fromCodePoint(127):
|
case '\x7f':
|
||||||
return KeyCommand.Backspace;
|
return KeyCommand.Backspace;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { chars } from './utils.ts';
|
|
||||||
import Row from './row.ts';
|
import Row from './row.ts';
|
||||||
import { getRuntime } from './runtime.ts';
|
import { getRuntime } from './runtime.ts';
|
||||||
import { Position, SCROLL_TAB_SIZE } from './mod.ts';
|
import { Position } from './mod.ts';
|
||||||
|
|
||||||
export class Document {
|
export class Document {
|
||||||
#filename: string | null;
|
#filename: string | null;
|
||||||
@ -61,12 +60,22 @@ export class Document {
|
|||||||
this.appendRow(c);
|
this.appendRow(c);
|
||||||
} else {
|
} else {
|
||||||
this.#rows[at.y].insertChar(at.x, c);
|
this.#rows[at.y].insertChar(at.x, c);
|
||||||
this.updateRow(this.#rows[at.y]);
|
this.#rows[at.y].updateRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public delete(at: Position): void {
|
||||||
|
const row = this.row(at.y);
|
||||||
|
if (row === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
row.delete(at.x);
|
||||||
|
row.updateRender();
|
||||||
|
}
|
||||||
|
|
||||||
public row(i: number): Row | null {
|
public row(i: number): Row | null {
|
||||||
return this.#rows[i] ?? null;
|
return this.#rows[i] ?? null;
|
||||||
}
|
}
|
||||||
@ -74,15 +83,11 @@ export class Document {
|
|||||||
public appendRow(s: string): void {
|
public appendRow(s: string): void {
|
||||||
const at = this.numRows;
|
const at = this.numRows;
|
||||||
this.#rows[at] = new Row(s);
|
this.#rows[at] = new Row(s);
|
||||||
this.updateRow(this.#rows[at]);
|
this.#rows[at].updateRender();
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateRow(r: Row): void {
|
|
||||||
r.render = chars(r.toString().replace('\t', ' '.repeat(SCROLL_TAB_SIZE)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private rowsToString(): string {
|
private rowsToString(): string {
|
||||||
return this.#rows.map((r) => r.toString()).join('\n');
|
return this.#rows.map((r) => r.toString()).join('\n');
|
||||||
}
|
}
|
||||||
|
@ -113,9 +113,17 @@ class Editor {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCommand.Backspace:
|
|
||||||
case KeyCommand.Delete:
|
case KeyCommand.Delete:
|
||||||
// TODO
|
this.#document.delete(this.#cursor);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyCommand.Backspace:
|
||||||
|
{
|
||||||
|
if (this.#cursor.x > 0 || this.#cursor.y > 0) {
|
||||||
|
this.moveCursor(KeyCommand.ArrowLeft);
|
||||||
|
this.#document.delete(this.#cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCommand.PageUp:
|
case KeyCommand.PageUp:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { SCROLL_TAB_SIZE } from './mod.ts';
|
import { chars, SCROLL_TAB_SIZE } from './mod.ts';
|
||||||
import * as Util from './utils.ts';
|
import * as Util from './utils.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,6 +44,14 @@ export class Row {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public delete(at: number): void {
|
||||||
|
if (at >= this.size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chars.splice(at, 1);
|
||||||
|
}
|
||||||
|
|
||||||
public cxToRx(cx: number): number {
|
public cxToRx(cx: number): number {
|
||||||
let rx = 0;
|
let rx = 0;
|
||||||
let j = 0;
|
let j = 0;
|
||||||
@ -60,6 +68,15 @@ export class Row {
|
|||||||
public toString(): string {
|
public toString(): string {
|
||||||
return this.chars.join('');
|
return this.chars.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateRender(): void {
|
||||||
|
const newString = this.chars.join('').replace(
|
||||||
|
'\t',
|
||||||
|
' '.repeat(SCROLL_TAB_SIZE),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.render = chars(newString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Row;
|
export default Row;
|
||||||
|
Loading…
Reference in New Issue
Block a user