Add horizontal scrolling
This commit is contained in:
parent
9b95850e86
commit
28ec91798a
@ -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 {
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user