Add incremental (character by character) search functionality
timw4mail/scroll/pipeline/head This commit looks good Details

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
deno-check:
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
deno-test:
deno test --allow-all --unstable
deno test --allow-all --unstable-ffi
# Create test coverage report with deno
deno-coverage:
@ -62,4 +62,4 @@ deno-coverage:
# Run with deno
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.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: {
'.default': () => {

View File

@ -231,10 +231,18 @@ class Editor {
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();
let res = '';
const maybeCallback = (query: string, char: string) => {
if (callback !== undefined) {
callback(query, char);
}
};
outer: while (true) {
if (p.includes('%s')) {
@ -250,26 +258,38 @@ class Editor {
continue;
}
// End the prompt
if (char === KeyCommand.Enter) {
this.setStatusMessage('');
if (res.length === 0) {
switch (char) {
// Remove the last character from the prompt input
case KeyCommand.Backspace:
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 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
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;
}
maybeCallback(res, char);
}
}
}
@ -278,14 +298,32 @@ class Editor {
* Find text within the document
*/
public async find(): Promise<void> {
const res = await this.prompt('Search: %s (ESC to cancel)');
if (res !== null && res.length > 0) {
const pos = this.#document.find(res);
if (pos !== null) {
this.#cursor = pos;
} else {
this.setStatusMessage('Not found');
}
const savedCursor = Position.from(this.#cursor);
const savedOffset = Position.from(this.#offset);
const query = await this.prompt(
'Search: %s (ESC to cancel)',
(query: string, key: string) => {
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 y: number;
private constructor(x: number, y: number) {
private constructor(x: number = 0, y: number = 0) {
this.x = x;
this.y = y;
}
@ -148,9 +148,18 @@ export class Position {
return new Position(x, y);
}
public static default(): Position {
return new Position(0, 0);
public static from(p: Position): Position {
return new Position(p.x, p.y);
}
public static default(): Position {
return new Position();
}
}
export enum SearchDirection {
Forward = 1,
Backward = -1,
}
// ----------------------------------------------------------------------------