Add incremental (character by character) search functionality
All checks were successful
timw4mail/scroll/pipeline/head This commit looks good

This commit is contained in:
Timothy Warren 2024-02-22 14:57:12 -05:00
parent b3177cbd48
commit e21944b4a4
4 changed files with 91 additions and 31 deletions

View File

@ -50,11 +50,11 @@ bun-run file="":
# Lint code and check types # Lint code and check types
deno-check: deno-check:
deno lint deno lint
deno check --unstable --all -c deno.jsonc ./src/deno/*.ts ./src/common/*.ts deno check --unstable-ffi --all -c deno.jsonc ./src/deno/*.ts ./src/common/*.ts
# Test with deno # Test with deno
deno-test: deno-test:
deno test --allow-all --unstable deno test --allow-all --unstable-ffi
# Create test coverage report with deno # Create test coverage report with deno
deno-coverage: deno-coverage:
@ -62,4 +62,4 @@ deno-coverage:
# Run with deno # Run with deno
deno-run file="": deno-run file="":
deno run --allow-all --allow-ffi --deny-hrtime --unstable ./src/scroll.ts {{file}} deno run --allow-all --allow-ffi --deny-hrtime --unstable-ffi ./src/scroll.ts {{file}}

View File

@ -138,6 +138,19 @@ testSuite({
assertEquals(p.x, 5); assertEquals(p.x, 5);
assertEquals(p.y, 7); assertEquals(p.y, 7);
}, },
'.from': () => {
const p1 = Position.at(1, 2);
const p2 = Position.from(p1);
p1.x = 2;
p1.y = 4;
assertEquals(p1.x, 2);
assertEquals(p1.y, 4);
assertEquals(p2.x, 1);
assertEquals(p2.y, 2);
},
}, },
Row: { Row: {
'.default': () => { '.default': () => {

View File

@ -231,10 +231,18 @@ class Editor {
return true; return true;
} }
public async prompt(p: string): Promise<string | null> { public async prompt(
p: string,
callback?: (query: string, char: string) => void,
): Promise<string | null> {
const { term } = await getRuntime(); const { term } = await getRuntime();
let res = ''; let res = '';
const maybeCallback = (query: string, char: string) => {
if (callback !== undefined) {
callback(query, char);
}
};
outer: while (true) { outer: while (true) {
if (p.includes('%s')) { if (p.includes('%s')) {
@ -250,26 +258,38 @@ class Editor {
continue; continue;
} }
// End the prompt switch (char) {
if (char === KeyCommand.Enter) { // Remove the last character from the prompt input
this.setStatusMessage(''); case KeyCommand.Backspace:
if (res.length === 0) { case KeyCommand.Delete:
res = truncate(res, res.length - 1);
maybeCallback(res, char);
continue outer;
// End the prompt
case KeyCommand.Escape:
this.setStatusMessage('');
maybeCallback(res, char);
return null; return null;
}
return res; // Return the input and end the prompt
case KeyCommand.Enter:
if (res.length > 0) {
this.setStatusMessage('');
maybeCallback(res, char);
return res;
}
break;
// Add to the prompt result
default:
if (!isControl(char)) {
res += char;
}
} }
// Allow backspacing maybeCallback(res, char);
if (char === KeyCommand.Backspace || char === KeyCommand.Delete) {
res = truncate(res, res.length - 1);
continue outer;
}
// Add to the prompt result
if (!isControl(char!)) {
res += char;
}
} }
} }
} }
@ -278,14 +298,32 @@ class Editor {
* Find text within the document * Find text within the document
*/ */
public async find(): Promise<void> { public async find(): Promise<void> {
const res = await this.prompt('Search: %s (ESC to cancel)'); const savedCursor = Position.from(this.#cursor);
if (res !== null && res.length > 0) { const savedOffset = Position.from(this.#offset);
const pos = this.#document.find(res);
if (pos !== null) { const query = await this.prompt(
this.#cursor = pos; 'Search: %s (ESC to cancel)',
} else { (query: string, key: string) => {
this.setStatusMessage('Not found'); if (key === KeyCommand.Enter || key === KeyCommand.Escape) {
} return;
}
if (query !== null && query.length > 0) {
const pos = this.#document.find(query);
if (pos !== null) {
this.#cursor = pos;
} else {
this.setStatusMessage('Not found');
}
}
},
);
// Return to document position before search
// when you cancel the search (press the escape key)
if (query !== null) {
this.#cursor = Position.from(savedCursor);
this.#offset = Position.from(savedOffset);
} }
} }

View File

@ -139,7 +139,7 @@ export class Position {
public x: number; public x: number;
public y: number; public y: number;
private constructor(x: number, y: number) { private constructor(x: number = 0, y: number = 0) {
this.x = x; this.x = x;
this.y = y; this.y = y;
} }
@ -148,9 +148,18 @@ export class Position {
return new Position(x, y); return new Position(x, y);
} }
public static default(): Position { public static from(p: Position): Position {
return new Position(0, 0); return new Position(p.x, p.y);
} }
public static default(): Position {
return new Position();
}
}
export enum SearchDirection {
Forward = 1,
Backward = -1,
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------