Highlight keywords
All checks were successful
timw4mail/scroll/pipeline/head This commit looks good

This commit is contained in:
Timothy Warren 2024-07-17 10:32:00 -04:00
parent 359e739fe8
commit e84dfa9ba9
3 changed files with 219 additions and 8 deletions

View File

@ -20,8 +20,12 @@ export interface HighlightingOptions {
interface IFileType { interface IFileType {
readonly name: FileLang; readonly name: FileLang;
readonly singleLineComment: Option<string>; readonly singleLineComment: Option<string>;
readonly keywords1: string[];
readonly keywords2: string[];
readonly hlOptions: HighlightingOptions; readonly hlOptions: HighlightingOptions;
get flags(): HighlightingOptions; get flags(): HighlightingOptions;
get primaryKeywords(): string[];
get secondaryKeywords(): string[];
} }
/** /**
@ -30,6 +34,8 @@ interface IFileType {
export abstract class AbstractFileType implements IFileType { export abstract class AbstractFileType implements IFileType {
public readonly name: FileLang = FileLang.Plain; public readonly name: FileLang = FileLang.Plain;
public readonly singleLineComment = None; public readonly singleLineComment = None;
public readonly keywords1: string[] = [];
public readonly keywords2: string[] = [];
public readonly hlOptions: HighlightingOptions = { public readonly hlOptions: HighlightingOptions = {
numbers: false, numbers: false,
strings: false, strings: false,
@ -38,6 +44,14 @@ export abstract class AbstractFileType implements IFileType {
get flags(): HighlightingOptions { get flags(): HighlightingOptions {
return this.hlOptions; return this.hlOptions;
} }
get primaryKeywords(): string[] {
return this.keywords1;
}
get secondaryKeywords(): string[] {
return this.keywords2;
}
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -48,20 +62,131 @@ const defaultHighlightOptions: HighlightingOptions = {
strings: true, strings: true,
}; };
class TypeScriptFile extends AbstractFileType { class JavaScriptFile extends AbstractFileType {
public readonly name: FileLang = FileLang.TypeScript; public readonly name: FileLang = FileLang.JavaScript;
public readonly singleLineComment = Some('//'); public readonly singleLineComment = Some('//');
public readonly keywords1 = [
'break',
'case',
'catch',
'class',
'const',
'continue',
'debugger',
'default',
'delete',
'do',
'else',
'export',
'extends',
'false',
'finally',
'for',
'function',
'if',
'import',
'in',
'instanceof',
'new',
'null',
'return',
'super',
'switch',
'this',
'throw',
'true',
'try',
'typeof',
'var',
'void',
'while',
'with',
'let',
'static',
'yield',
'await',
];
public readonly keywords2 = [
'arguments',
'as',
'async',
'eval',
'from',
'get',
'of',
'set',
];
public readonly hlOptions: HighlightingOptions = { public readonly hlOptions: HighlightingOptions = {
...defaultHighlightOptions, ...defaultHighlightOptions,
}; };
} }
class JavaScriptFile extends AbstractFileType { class TypeScriptFile extends JavaScriptFile {
public readonly name: FileLang = FileLang.JavaScript; public readonly name: FileLang = FileLang.TypeScript;
public readonly singleLineComment = Some('//'); public readonly keywords1 = [
public readonly hlOptions: HighlightingOptions = { 'break',
...defaultHighlightOptions, 'case',
}; 'catch',
'class',
'const',
'continue',
'debugger',
'default',
'delete',
'do',
'else',
'export',
'extends',
'false',
'finally',
'for',
'function',
'if',
'import',
'in',
'instanceof',
'new',
'null',
'return',
'super',
'switch',
'this',
'throw',
'true',
'try',
'typeof',
'var',
'void',
'while',
'with',
'let',
'static',
'yield',
'await',
];
public readonly keywords2 = [
'arguments',
'as',
'async',
'eval',
'from',
'get',
'of',
'set',
// Typescript-specific
'keyof',
'interface',
'enum',
'public',
'protected',
'private',
'string',
'number',
'boolean',
'any',
'unknown',
'type',
];
} }
class CSSFile extends AbstractFileType { class CSSFile extends AbstractFileType {

View File

@ -6,6 +6,8 @@ export enum HighlightType {
Match, Match,
String, String,
SingleLineComment, SingleLineComment,
Keyword1,
Keyword2,
} }
export function highlightToColor(type: HighlightType): string { export function highlightToColor(type: HighlightType): string {
@ -22,6 +24,12 @@ export function highlightToColor(type: HighlightType): string {
case HighlightType.SingleLineComment: case HighlightType.SingleLineComment:
return Ansi.color256(45); return Ansi.color256(45);
case HighlightType.Keyword1:
return Ansi.color256(226);
case HighlightType.Keyword2:
return Ansi.color256(118);
default: default:
return Ansi.ResetFormatting; return Ansi.ResetFormatting;
} }

View File

@ -232,6 +232,8 @@ export class Row {
const ch = this.rchars[i]; const ch = this.rchars[i];
const maybeNext = this.highlightComment(i, syntax, ch) const maybeNext = this.highlightComment(i, syntax, ch)
.orElse(() => this.highlightPrimaryKeywords(i, syntax))
.orElse(() => this.highlightSecondaryKeywords(i, syntax))
.orElse(() => this.highlightString(i, syntax, ch)) .orElse(() => this.highlightString(i, syntax, ch))
.orElse(() => this.highlightNumber(i, syntax, ch)); .orElse(() => this.highlightNumber(i, syntax, ch));
@ -305,6 +307,82 @@ export class Row {
return None; return None;
} }
protected highlightStr(
i: number,
substring: string,
hl_type: HighlightType,
): Option<number> {
if (strlen(substring) === 0) {
return None;
}
const substringChars = strChars(substring);
for (const [j, ch] of substringChars.entries()) {
const nextChar = this.rchars[i + j];
if (nextChar !== ch) {
return None;
}
}
for (const _ of substringChars) {
this.hl.push(hl_type);
i += 1;
}
return Some(i);
}
protected highlightKeywords(
i: number,
keywords: string[],
hl_type: HighlightType,
): Option<number> {
if (i > 0) {
const prevChar = this.rchars[i - 1];
if (!isSeparator(prevChar)) {
return None;
}
}
for (const keyword of keywords) {
if (i + strlen(keyword) < this.rsize) {
const nextChar = this.rchars[i + strlen(keyword)];
if (!isSeparator(nextChar)) {
continue;
}
}
const maybeHighlight = this.highlightStr(i, keyword, hl_type);
if (maybeHighlight.isSome()) {
return maybeHighlight;
}
}
return None;
}
protected highlightPrimaryKeywords(
i: number,
syntax: FileType,
): Option<number> {
return this.highlightKeywords(
i,
syntax.primaryKeywords,
HighlightType.Keyword1,
);
}
protected highlightSecondaryKeywords(
i: number,
syntax: FileType,
): Option<number> {
return this.highlightKeywords(
i,
syntax.secondaryKeywords,
HighlightType.Keyword2,
);
}
protected highlightString( protected highlightString(
i: number, i: number,
syntax: FileType, syntax: FileType,