Add render optimizations from hecto, fix rendering of multiline comments
All checks were successful
timw4mail/scroll/pipeline/head This commit looks good
All checks were successful
timw4mail/scroll/pipeline/head This commit looks good
This commit is contained in:
parent
2b3be61933
commit
ea00f76a62
@ -361,6 +361,10 @@ const DocumentTest = {
|
|||||||
doc.insert(Position.at(9, 0), 'buzz');
|
doc.insert(Position.at(9, 0), 'buzz');
|
||||||
assertEquals(doc.numRows, 1);
|
assertEquals(doc.numRows, 1);
|
||||||
assertTrue(doc.dirty);
|
assertTrue(doc.dirty);
|
||||||
|
|
||||||
|
// Update row
|
||||||
|
doc.highlight(None, None);
|
||||||
|
|
||||||
const row0 = doc.row(0).unwrap();
|
const row0 = doc.row(0).unwrap();
|
||||||
assertEquals(row0.toString(), 'foobazbarbuzz');
|
assertEquals(row0.toString(), 'foobazbarbuzz');
|
||||||
assertEquals(row0.rstring(), 'foobazbarbuzz');
|
assertEquals(row0.rstring(), 'foobazbarbuzz');
|
||||||
|
@ -58,9 +58,9 @@ export class Document {
|
|||||||
|
|
||||||
const rawFile = await file.openFile(filename);
|
const rawFile = await file.openFile(filename);
|
||||||
rawFile.split(/\r?\n/)
|
rawFile.split(/\r?\n/)
|
||||||
.forEach((row) => this.insertRow(this.numRows, row));
|
.forEach((row) => {
|
||||||
|
this.#rows.push(Row.from(row));
|
||||||
this.highlight(None);
|
});
|
||||||
|
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
|
|
||||||
@ -76,16 +76,20 @@ export class Document {
|
|||||||
await file.saveFile(filename, this.rowsToString());
|
await file.saveFile(filename, this.rowsToString());
|
||||||
this.type = FileType.from(filename);
|
this.type = FileType.from(filename);
|
||||||
|
|
||||||
// Re-highlight the file
|
|
||||||
this.highlight(None);
|
|
||||||
|
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the cursor position of the query, if it exists
|
||||||
|
*
|
||||||
|
* @param q - the search query
|
||||||
|
* @param at - the point from which to start the search
|
||||||
|
* @param direction - which direction to search, backward or forward
|
||||||
|
*/
|
||||||
public find(
|
public find(
|
||||||
q: string,
|
q: string,
|
||||||
at: Position,
|
at: Position,
|
||||||
direction: SearchDirection = SearchDirection.Forward,
|
direction: SearchDirection,
|
||||||
): Option<Position> {
|
): Option<Position> {
|
||||||
if (at.y >= this.numRows) {
|
if (at.y >= this.numRows) {
|
||||||
logWarning('Trying to search beyond the end of the current file', {
|
logWarning('Trying to search beyond the end of the current file', {
|
||||||
@ -127,23 +131,6 @@ export class Document {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
public insert(at: Position, c: string): void {
|
|
||||||
if (at.y > this.numRows) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dirty = true;
|
|
||||||
|
|
||||||
if (at.y === this.numRows) {
|
|
||||||
this.insertRow(this.numRows, c);
|
|
||||||
} else {
|
|
||||||
this.#rows[at.y].insertChar(at.x, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-highlight the file
|
|
||||||
this.highlight(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a new line, splitting and/or creating a new row as needed
|
* Insert a new line, splitting and/or creating a new row as needed
|
||||||
*/
|
*/
|
||||||
@ -166,9 +153,30 @@ export class Document {
|
|||||||
const currentRow = this.#rows[at.y];
|
const currentRow = this.#rows[at.y];
|
||||||
const newRow = currentRow.split(at.x, this.type);
|
const newRow = currentRow.split(at.x, this.type);
|
||||||
this.#rows = arrayInsert(this.#rows, at.y + 1, newRow);
|
this.#rows = arrayInsert(this.#rows, at.y + 1, newRow);
|
||||||
|
}
|
||||||
|
|
||||||
// Re-highlight the file
|
public insert(at: Position, c: string): void {
|
||||||
this.highlight(None);
|
if (at.y > this.numRows) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dirty = true;
|
||||||
|
|
||||||
|
if (at.y === this.numRows) {
|
||||||
|
this.#rows.push(Row.from(c));
|
||||||
|
} else {
|
||||||
|
this.#rows[at.y].insertChar(at.x, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unHighlightRows(at.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected unHighlightRows(start: number): void {
|
||||||
|
if (this.numRows < start && start >= 1) {
|
||||||
|
for (let i = start - 1; i < this.numRows; i++) {
|
||||||
|
this.#rows[i].isHighlighted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,8 +215,7 @@ export class Document {
|
|||||||
row.delete(at.x);
|
row.delete(at.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-highlight the file
|
this.unHighlightRows(at.y);
|
||||||
this.highlight(None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public row(i: number): Option<Row> {
|
public row(i: number): Option<Row> {
|
||||||
@ -219,19 +226,20 @@ export class Document {
|
|||||||
return Option.from(this.#rows.at(i));
|
return Option.from(this.#rows.at(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
public highlight(searchMatch: Option<string>): void {
|
public highlight(searchMatch: Option<string>, limit: Option<number>): void {
|
||||||
let startWithComment = false;
|
let startWithComment = false;
|
||||||
this.#rows.forEach((row) => {
|
let until = this.numRows;
|
||||||
startWithComment = row.update(searchMatch, this.type, startWithComment);
|
if (limit.isSome() && (limit.unwrap() + 1 < this.numRows)) {
|
||||||
});
|
until = limit.unwrap() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected insertRow(
|
for (let i = 0; i < until; i++) {
|
||||||
at: number = this.numRows,
|
startWithComment = this.#rows[i].update(
|
||||||
s: string = '',
|
searchMatch,
|
||||||
): void {
|
this.type,
|
||||||
this.#rows = arrayInsert(this.#rows, at, Row.from(s));
|
startWithComment,
|
||||||
this.dirty = true;
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,6 +58,8 @@ export default class Editor {
|
|||||||
*/
|
*/
|
||||||
protected quitTimes: number = SCROLL_QUIT_TIMES;
|
protected quitTimes: number = SCROLL_QUIT_TIMES;
|
||||||
|
|
||||||
|
protected highlightedWord: Option<string> = None;
|
||||||
|
|
||||||
constructor(terminalSize: ITerminalSize) {
|
constructor(terminalSize: ITerminalSize) {
|
||||||
this.buffer = new Buffer();
|
this.buffer = new Buffer();
|
||||||
|
|
||||||
@ -300,7 +302,7 @@ export default class Editor {
|
|||||||
this.moveCursor(KeyCommand.ArrowLeft);
|
this.moveCursor(KeyCommand.ArrowLeft);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.document.highlight(Some(query));
|
this.highlightedWord = Some(query);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -313,7 +315,7 @@ export default class Editor {
|
|||||||
this.scroll();
|
this.scroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.document.highlight(None);
|
this.highlightedWord = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -438,6 +440,10 @@ export default class Editor {
|
|||||||
this.scroll();
|
this.scroll();
|
||||||
this.buffer.append(Ansi.HideCursor);
|
this.buffer.append(Ansi.HideCursor);
|
||||||
this.buffer.append(Ansi.ResetCursor);
|
this.buffer.append(Ansi.ResetCursor);
|
||||||
|
this.document.highlight(
|
||||||
|
this.highlightedWord,
|
||||||
|
Some(this.offset.y + this.screen.rows),
|
||||||
|
);
|
||||||
this.drawRows();
|
this.drawRows();
|
||||||
this.drawStatusBar();
|
this.drawStatusBar();
|
||||||
this.drawMessageBar();
|
this.drawMessageBar();
|
||||||
|
@ -152,6 +152,17 @@ export function strlen(s: string): number {
|
|||||||
return strChars(s).length;
|
return strChars(s).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a slice of a string
|
||||||
|
*
|
||||||
|
* @param s - the string
|
||||||
|
* @param from - the 'character' index of the start of the slice
|
||||||
|
* @param to - the 'character' index of the last character you want
|
||||||
|
*/
|
||||||
|
export function substr(s: string, from: number, to?: number): string {
|
||||||
|
return strChars(s).slice(from, to).join('');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are all the characters in the string in ASCII range?
|
* Are all the characters in the string in ASCII range?
|
||||||
*
|
*
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
isSeparator,
|
isSeparator,
|
||||||
strChars,
|
strChars,
|
||||||
strlen,
|
strlen,
|
||||||
|
substr,
|
||||||
} from './fns.ts';
|
} from './fns.ts';
|
||||||
import { FileType } from './filetype/mod.ts';
|
import { FileType } from './filetype/mod.ts';
|
||||||
import { highlightToColor, HighlightType } from './highlight.ts';
|
import { highlightToColor, HighlightType } from './highlight.ts';
|
||||||
@ -35,6 +36,11 @@ export class Row {
|
|||||||
*/
|
*/
|
||||||
public hl: HighlightType[] = [];
|
public hl: HighlightType[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the current row been highlighted?
|
||||||
|
*/
|
||||||
|
public isHighlighted: boolean = false;
|
||||||
|
|
||||||
private constructor(s: string | string[] = '') {
|
private constructor(s: string | string[] = '') {
|
||||||
this.chars = Array.isArray(s) ? s : strChars(s);
|
this.chars = Array.isArray(s) ? s : strChars(s);
|
||||||
this.rchars = [];
|
this.rchars = [];
|
||||||
@ -102,7 +108,7 @@ export class Row {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Search the current row for the specified string, and return
|
* Search the current row for the specified string, and return
|
||||||
* the 'character' index of the start of that match
|
* the render 'character' index of the start of that match
|
||||||
*/
|
*/
|
||||||
public find(
|
public find(
|
||||||
s: string,
|
s: string,
|
||||||
@ -142,13 +148,6 @@ export class Row {
|
|||||||
return (byteIndex >= 0) ? Some(this.byteIndexToCharIndex(byteIndex)) : None;
|
return (byteIndex >= 0) ? Some(this.byteIndexToCharIndex(byteIndex)) : None;
|
||||||
}
|
}
|
||||||
|
|
||||||
public rLastIndexOf(s: string, offset: number = 0): Option<number> {
|
|
||||||
const rstring = this.rchars.join('');
|
|
||||||
const byteIndex = rstring.lastIndexOf(s, this.charIndexToByteIndex(offset));
|
|
||||||
|
|
||||||
return (byteIndex >= 0) ? Some(this.byteIndexToCharIndex(byteIndex)) : None;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the raw row offset to the equivalent offset for screen rendering
|
* Convert the raw row offset to the equivalent offset for screen rendering
|
||||||
*/
|
*/
|
||||||
@ -247,19 +246,30 @@ export class Row {
|
|||||||
syntax: FileType,
|
syntax: FileType,
|
||||||
startWithComment: boolean,
|
startWithComment: boolean,
|
||||||
): boolean {
|
): boolean {
|
||||||
this.hl = [];
|
// Check for the end of a multiline comment
|
||||||
|
// if we are currently in one
|
||||||
|
if (this.isHighlighted && word.isNone()) {
|
||||||
|
const lastHl = this.hl[this.hl.length - 1];
|
||||||
|
return lastHl === HighlightType.MultiLineComment &&
|
||||||
|
syntax.hasMultilineComments() &&
|
||||||
|
this.size > 1 &&
|
||||||
|
substr(this.toString(), this.size - 2) ===
|
||||||
|
syntax.multiLineCommentEnd.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hl = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let inMlComment = startWithComment;
|
let inMlComment = startWithComment;
|
||||||
if (inMlComment && syntax.hasMultilineComments()) {
|
if (inMlComment && syntax.hasMultilineComments()) {
|
||||||
const maybEnd = this.rIndexOf(syntax.multiLineCommentEnd.unwrap(), i);
|
const maybeEnd = this.rIndexOf(syntax.multiLineCommentEnd.unwrap(), i);
|
||||||
const closingIndex = (maybEnd.isSome())
|
const closingIndex = (maybeEnd.isSome())
|
||||||
? maybEnd.unwrap() + 1
|
? maybeEnd.unwrap() + 2
|
||||||
: this.rsize;
|
: this.rsize;
|
||||||
|
|
||||||
for (; i < closingIndex; i++) {
|
for (; i < closingIndex; i++) {
|
||||||
this.hl.push(HighlightType.MultiLineComment);
|
this.hl.push(HighlightType.MultiLineComment);
|
||||||
}
|
}
|
||||||
|
i = closingIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; i < this.rsize;) {
|
for (; i < this.rsize;) {
|
||||||
@ -282,12 +292,12 @@ export class Row {
|
|||||||
|
|
||||||
if (maybeNext.isSome()) {
|
if (maybeNext.isSome()) {
|
||||||
const next = maybeNext.unwrap();
|
const next = maybeNext.unwrap();
|
||||||
if (next < this.rsize) {
|
if (next >= this.rsize) {
|
||||||
i = maybeNext.unwrap();
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
i = next;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
this.hl.push(HighlightType.None);
|
this.hl.push(HighlightType.None);
|
||||||
i += 1;
|
i += 1;
|
||||||
@ -295,17 +305,14 @@ export class Row {
|
|||||||
|
|
||||||
this.highlightMatch(word);
|
this.highlightMatch(word);
|
||||||
if (inMlComment && syntax.hasMultilineComments()) {
|
if (inMlComment && syntax.hasMultilineComments()) {
|
||||||
const commentEnd = syntax.multiLineCommentEnd.unwrap();
|
if (
|
||||||
const maybeIndex = this.rLastIndexOf(commentEnd);
|
substr(this.toString(), this.size - 2) !==
|
||||||
|
syntax.multiLineCommentEnd.unwrap()
|
||||||
if (maybeIndex.isNone()) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lastIndex = maybeIndex.unwrap();
|
|
||||||
return lastIndex !== this.rsize - 2;
|
|
||||||
}
|
}
|
||||||
|
this.isHighlighted = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user