Add horizontal scrolling

This commit is contained in:
Timothy Warren 2023-11-20 14:21:42 -05:00
parent 9b95850e86
commit 28ec91798a
3 changed files with 83 additions and 23 deletions

View File

@ -8,6 +8,10 @@ export class Row {
this.chars = chars(s); this.chars = chars(s);
} }
public get size(): number {
return this.chars.length;
}
public toString(): string { public toString(): string {
return this.chars.join(''); return this.chars.join('');
} }
@ -48,11 +52,7 @@ export class Document {
} }
public row(i: number): Row | null { public row(i: number): Row | null {
if (this.#rows[i] !== undefined) { return this.#rows[i] ?? null;
return this.#rows[i];
}
return null;
} }
public appendRow(s: string): void { public appendRow(s: string): void {

View File

@ -1,8 +1,8 @@
import Ansi, { KeyCommand } from './ansi.ts'; import Ansi, { KeyCommand } from './ansi.ts';
import Buffer from './buffer.ts'; import Buffer from './buffer.ts';
import Document from './document.ts'; import Document, { Row } from './document.ts';
import { IPoint, ITerminalSize, logToFile, VERSION } from './mod.ts'; import { IPoint, ITerminalSize, logToFile, VERSION } from './mod.ts';
import { ctrlKey } from './utils.ts'; import { ctrlKey, posSub } from './utils.ts';
export class Editor { export class Editor {
/** /**
@ -29,6 +29,11 @@ export class Editor {
* @private * @private
*/ */
#document: Document; #document: Document;
private get currentRow(): Row | null {
return this.#document.row(this.#cursor.y);
}
constructor(terminalSize: ITerminalSize) { constructor(terminalSize: ITerminalSize) {
this.#buffer = new Buffer(); this.#buffer = new Buffer();
this.#screen = terminalSize; this.#screen = terminalSize;
@ -102,11 +107,24 @@ export class Editor {
case KeyCommand.ArrowLeft: case KeyCommand.ArrowLeft:
if (this.#cursor.x > 0) { if (this.#cursor.x > 0) {
this.#cursor.x--; this.#cursor.x--;
} else if (this.#cursor.y > 0) {
this.#cursor.y--;
this.#cursor.x = (this.currentRow !== null)
? this.currentRow.size - 1
: 0;
} }
break; break;
case KeyCommand.ArrowRight: case KeyCommand.ArrowRight:
if (this.#cursor.x < this.#screen.cols) { if (
this.currentRow !== null && this.#cursor.x < this.currentRow.size - 1
) {
this.#cursor.x++; this.#cursor.x++;
} else if (
this.currentRow !== null &&
this.#cursor.x === this.currentRow.size - 1
) {
this.#cursor.y++;
this.#cursor.x = 0;
} }
break; break;
case KeyCommand.ArrowUp: case KeyCommand.ArrowUp:
@ -115,11 +133,16 @@ export class Editor {
} }
break; break;
case KeyCommand.ArrowDown: case KeyCommand.ArrowDown:
if (this.#cursor.y < this.#screen.rows) { if (this.#cursor.y < this.#document.numRows) {
this.#cursor.y++; this.#cursor.y++;
} }
break; break;
} }
const rowLen = this.currentRow?.size ?? 0;
if (this.#cursor.x > rowLen) {
this.#cursor.x = rowLen;
}
} }
private scroll(): void { private scroll(): void {
@ -129,6 +152,12 @@ export class Editor {
if (this.#cursor.y >= this.#offset.y + this.#screen.rows) { if (this.#cursor.y >= this.#offset.y + this.#screen.rows) {
this.#offset.y = this.#cursor.y - this.#screen.rows + 1; this.#offset.y = this.#cursor.y - this.#screen.rows + 1;
} }
if (this.#cursor.x < this.#offset.x) {
this.#offset.x = this.#cursor.x;
}
if (this.#cursor.x >= this.#offset.x + this.#screen.cols) {
this.#offset.x = this.#cursor.x - this.#screen.cols + 1;
}
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -144,7 +173,10 @@ export class Editor {
this.#buffer.append(Ansi.ResetCursor); this.#buffer.append(Ansi.ResetCursor);
this.drawRows(); this.drawRows();
this.#buffer.append( this.#buffer.append(
Ansi.moveCursor(this.#cursor.y, this.#cursor.x), Ansi.moveCursor(
this.#cursor.y - this.#offset.y,
this.#cursor.x - this.#offset.x,
),
); );
this.#buffer.append(Ansi.ShowCursor); this.#buffer.append(Ansi.ShowCursor);
@ -160,11 +192,16 @@ export class Editor {
private drawRows(): void { private drawRows(): void {
for (let y = 0; y < this.#screen.rows; y++) { for (let y = 0; y < this.#screen.rows; y++) {
let filerow = y + this.#offset.y; const filerow = y + this.#offset.y;
if (filerow >= this.#document.numRows) { if (filerow >= this.#document.numRows) {
this.drawPlaceholderRow(y); this.drawPlaceholderRow(filerow);
} else { } else {
this.drawFileRow(y); this.drawFileRow(filerow);
}
this.#buffer.append(Ansi.ClearLine);
if (y < this.#screen.rows - 1) {
this.#buffer.appendLine();
} }
} }
} }
@ -176,13 +213,12 @@ export class Editor {
return this.drawPlaceholderRow(y); return this.drawPlaceholderRow(y);
} }
let len = row.chars.length ?? 0; const len = Math.min(
if (len > this.#screen.cols) { posSub(row.chars.length, this.#offset.x),
len = this.#screen.cols; this.#screen.cols,
} );
this.#buffer.append(row.toString(), len); this.#buffer.append(row.toString(), len);
this.#buffer.appendLine(Ansi.ClearLine);
} }
private drawPlaceholderRow(y: number): void { private drawPlaceholderRow(y: number): void {
@ -203,10 +239,5 @@ export class Editor {
} else { } else {
this.#buffer.append('~'); this.#buffer.append('~');
} }
this.#buffer.append(Ansi.ClearLine);
if (y < this.#screen.rows - 1) {
this.#buffer.appendLine();
}
} }
} }

View File

@ -4,6 +4,35 @@
export const noop = () => {}; export const noop = () => {};
/**
* Subtract two numbers, returning a zero if the result is negative
* @param l
* @param s
*/
export function posSub(l: number, s: number): number {
return minSub(l, s, 0);
}
/**
* Subtract two numbers, returning at least the minimum specified
* @param l
* @param s
* @param min
*/
export function minSub(l: number, s: number, min: number): number {
return Math.max(l - s, min);
}
/**
* Add two numbers, up to a max value
* @param n1
* @param n2
* @param max
*/
export function maxAdd(n1: number, n2: number, max: number): number {
return Math.min(n1 + n2, max);
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Strings // Strings
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------