From e84dfa9ba9ddfc1461010b4fb85e1edeaaf8f83e Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Wed, 17 Jul 2024 10:32:00 -0400 Subject: [PATCH] Highlight keywords --- src/common/filetype/filetype.ts | 141 ++++++++++++++++++++++++++++++-- src/common/highlight.ts | 8 ++ src/common/row.ts | 78 ++++++++++++++++++ 3 files changed, 219 insertions(+), 8 deletions(-) diff --git a/src/common/filetype/filetype.ts b/src/common/filetype/filetype.ts index dd4c8de..ed75100 100644 --- a/src/common/filetype/filetype.ts +++ b/src/common/filetype/filetype.ts @@ -20,8 +20,12 @@ export interface HighlightingOptions { interface IFileType { readonly name: FileLang; readonly singleLineComment: Option; + readonly keywords1: string[]; + readonly keywords2: string[]; readonly hlOptions: HighlightingOptions; get flags(): HighlightingOptions; + get primaryKeywords(): string[]; + get secondaryKeywords(): string[]; } /** @@ -30,6 +34,8 @@ interface IFileType { export abstract class AbstractFileType implements IFileType { public readonly name: FileLang = FileLang.Plain; public readonly singleLineComment = None; + public readonly keywords1: string[] = []; + public readonly keywords2: string[] = []; public readonly hlOptions: HighlightingOptions = { numbers: false, strings: false, @@ -38,6 +44,14 @@ export abstract class AbstractFileType implements IFileType { get flags(): HighlightingOptions { return this.hlOptions; } + + get primaryKeywords(): string[] { + return this.keywords1; + } + + get secondaryKeywords(): string[] { + return this.keywords2; + } } // ---------------------------------------------------------------------------- @@ -48,20 +62,131 @@ const defaultHighlightOptions: HighlightingOptions = { strings: true, }; -class TypeScriptFile extends AbstractFileType { - public readonly name: FileLang = FileLang.TypeScript; +class JavaScriptFile extends AbstractFileType { + public readonly name: FileLang = FileLang.JavaScript; 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 = { ...defaultHighlightOptions, }; } -class JavaScriptFile extends AbstractFileType { - public readonly name: FileLang = FileLang.JavaScript; - public readonly singleLineComment = Some('//'); - public readonly hlOptions: HighlightingOptions = { - ...defaultHighlightOptions, - }; +class TypeScriptFile extends JavaScriptFile { + public readonly name: FileLang = FileLang.TypeScript; + 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', + // Typescript-specific + 'keyof', + 'interface', + 'enum', + 'public', + 'protected', + 'private', + 'string', + 'number', + 'boolean', + 'any', + 'unknown', + 'type', + ]; } class CSSFile extends AbstractFileType { diff --git a/src/common/highlight.ts b/src/common/highlight.ts index ce7221a..d1ef0ce 100644 --- a/src/common/highlight.ts +++ b/src/common/highlight.ts @@ -6,6 +6,8 @@ export enum HighlightType { Match, String, SingleLineComment, + Keyword1, + Keyword2, } export function highlightToColor(type: HighlightType): string { @@ -22,6 +24,12 @@ export function highlightToColor(type: HighlightType): string { case HighlightType.SingleLineComment: return Ansi.color256(45); + case HighlightType.Keyword1: + return Ansi.color256(226); + + case HighlightType.Keyword2: + return Ansi.color256(118); + default: return Ansi.ResetFormatting; } diff --git a/src/common/row.ts b/src/common/row.ts index 3dc4242..cfb2980 100644 --- a/src/common/row.ts +++ b/src/common/row.ts @@ -232,6 +232,8 @@ export class Row { const ch = this.rchars[i]; 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.highlightNumber(i, syntax, ch)); @@ -305,6 +307,82 @@ export class Row { return None; } + protected highlightStr( + i: number, + substring: string, + hl_type: HighlightType, + ): Option { + 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 { + 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 { + return this.highlightKeywords( + i, + syntax.primaryKeywords, + HighlightType.Keyword1, + ); + } + + protected highlightSecondaryKeywords( + i: number, + syntax: FileType, + ): Option { + return this.highlightKeywords( + i, + syntax.secondaryKeywords, + HighlightType.Keyword2, + ); + } + protected highlightString( i: number, syntax: FileType,