diff --git a/deno.jsonc b/deno.jsonc index 825aab0..a146961 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -13,5 +13,6 @@ "semiColons": true, "singleQuote": true }, - "nodeModulesDir": true + "nodeModulesDir": true, + "exclude": ["src/bun/"] } diff --git a/justfile b/justfile index 89848e1..e8f9712 100644 --- a/justfile +++ b/justfile @@ -14,7 +14,7 @@ check: deno-check bun-check # Generate source docs docs: - deno doc --html --name="Scroll" ./src/scroll.ts ./src/common/*.ts ./src/deno/mod.ts ./src/bun/mod.ts ./src/tsx/mod.ts + deno doc --html --name="Scroll" ./src/common/*.ts ./src/common/**/*.ts # Generate source docs and open in default browser open-docs: docs diff --git a/src/bun/mod.ts b/src/bun/mod.ts index e83c484..02b236e 100644 --- a/src/bun/mod.ts +++ b/src/bun/mod.ts @@ -1,7 +1,7 @@ /** * The main entrypoint when using Bun as the runtime */ -import { CommonRuntime, IRuntime, RunTimeType } from '../common/runtime/mod.ts'; +import { CommonRuntime, IRuntime, RunTimeType } from '../common/runtime.ts'; /** * The Bun Runtime implementation diff --git a/src/common/all_test.ts b/src/common/all_test.ts index eba7de3..2663e3e 100644 --- a/src/common/all_test.ts +++ b/src/common/all_test.ts @@ -2,17 +2,16 @@ import Ansi, * as _Ansi from './ansi.ts'; import Buffer from './buffer.ts'; import Document from './document.ts'; import Editor from './editor.ts'; -import { FileLang } from './filetype/mod.ts'; -import { highlightToColor, HighlightType } from './highlight.ts'; +import { FileLang } from './filetype.ts'; import Option, { None, Some } from './option.ts'; import Position from './position.ts'; import Row from './row.ts'; -import FileType, * as FT from './filetype/mod.ts'; +import FileType, * as FT from './filetype.ts'; import * as Fn from './fns.ts'; import { defaultTerminalSize, SCROLL_TAB_SIZE } from './config.ts'; -import { getTestRunner } from './runtime/mod.ts'; -import { SearchDirection } from './types.ts'; +import { getTestRunner } from './runtime.ts'; +import { HighlightType, SearchDirection } from './types.ts'; import fs from 'node:fs'; @@ -51,6 +50,7 @@ const fnTest = () => { isAsciiDigit, strlen, truncate, + highlightToColor, } = Fn; return { @@ -78,6 +78,21 @@ const fnTest = () => { assertExists(noop); assertEquals(noop(), undefined); }, + 'highlightToColor()': () => { + [ + HighlightType.Number, + HighlightType.Match, + HighlightType.String, + HighlightType.SingleLineComment, + HighlightType.MultiLineComment, + HighlightType.Keyword1, + HighlightType.Keyword2, + HighlightType.Operator, + HighlightType.None, + ].forEach((type) => { + assertTrue(highlightToColor(type).length > 0); + }); + }, 'posSub()': () => { assertEquals(posSub(14, 15), 0); assertEquals(posSub(15, 1), 14); @@ -201,24 +216,6 @@ const readKeyTest = () => { }; }; -const highlightToColorTest = { - 'highlightToColor()': () => { - [ - HighlightType.Number, - HighlightType.Match, - HighlightType.String, - HighlightType.SingleLineComment, - HighlightType.MultiLineComment, - HighlightType.Keyword1, - HighlightType.Keyword2, - HighlightType.Operator, - HighlightType.None, - ].forEach((type) => { - assertTrue(highlightToColor(type).length > 0); - }); - }, -}; - // ---------------------------------------------------------------------------- // Tests by module // ---------------------------------------------------------------------------- @@ -708,7 +705,6 @@ const RowTest = { testSuite({ fns: fnTest(), - highlightToColorTest, 'readKey()': readKeyTest(), 'ANSI utils': ANSITest(), Buffer: BufferTest, diff --git a/src/common/ansi.ts b/src/common/ansi.ts index 43815dd..d07d72c 100644 --- a/src/common/ansi.ts +++ b/src/common/ansi.ts @@ -117,6 +117,9 @@ const rgb = ( ground: Ground = Ground.Fore, ): string => textFormat([ground, AnsiColor.TypeRGB, r, g, b]); +/** + * Ansi terminal codes and helper functions + */ export const Ansi = { ClearLine: code('K'), ClearScreen: code('2J'), diff --git a/src/common/buffer.ts b/src/common/buffer.ts index 3201df0..94dc878 100644 --- a/src/common/buffer.ts +++ b/src/common/buffer.ts @@ -1,6 +1,9 @@ import { strlen, truncate } from './fns.ts'; -import { getRuntime } from './runtime/mod.ts'; +import { getRuntime } from './runtime.ts'; +/** + * A simple string buffer + */ class Buffer { #b = ''; diff --git a/src/common/config.ts b/src/common/config.ts index b036e3f..d6325a0 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -1,7 +1,7 @@ import Ansi from './ansi.ts'; import { HighlightType, ITerminalSize } from './types.ts'; -export const SCROLL_VERSION = '0.0.1'; +export const SCROLL_VERSION = '0.1.0'; export const SCROLL_QUIT_TIMES = 3; export const SCROLL_TAB_SIZE = 4; diff --git a/src/common/document.ts b/src/common/document.ts index 3d945b2..2073d25 100644 --- a/src/common/document.ts +++ b/src/common/document.ts @@ -1,8 +1,8 @@ import Row from './row.ts'; -import { FileType } from './filetype/mod.ts'; +import { FileType } from './filetype.ts'; import { arrayInsert } from './fns.ts'; import Option, { None, Some } from './option.ts'; -import { getRuntime, logWarning } from './runtime/mod.ts'; +import { getRuntime, logWarning } from './runtime.ts'; import { Position, SearchDirection } from './types.ts'; export class Document { @@ -52,7 +52,7 @@ export class Document { const rawFile = await file.openFile(filename); rawFile.split(/\r?\n/) - .forEach((row) => { + .forEach((row: string) => { this.#rows.push(Row.from(row)); }); diff --git a/src/common/editor.ts b/src/common/editor.ts index fc5ce29..dd25e09 100644 --- a/src/common/editor.ts +++ b/src/common/editor.ts @@ -13,7 +13,7 @@ import { truncate, } from './fns.ts'; import Option, { None, Some } from './option.ts'; -import { getRuntime, logDebug, logWarning } from './runtime/mod.ts'; +import { getRuntime, logDebug, logWarning } from './runtime.ts'; import { ITerminalSize, Position, SearchDirection } from './types.ts'; /** diff --git a/src/common/filetype.ts b/src/common/filetype.ts new file mode 100644 index 0000000..914f507 --- /dev/null +++ b/src/common/filetype.ts @@ -0,0 +1,5 @@ +export * from './filetype/base.ts'; +export * from './filetype/filetype.ts'; + +import FileType from './filetype/filetype.ts'; +export default FileType; diff --git a/src/common/filetype/filetype.ts b/src/common/filetype/filetype.ts index 47cc290..0610877 100644 --- a/src/common/filetype/filetype.ts +++ b/src/common/filetype/filetype.ts @@ -1,4 +1,4 @@ -import { node_path as path } from '../runtime/mod.ts'; +import { node_path as path } from '../runtime.ts'; import { AbstractFileType } from './base.ts'; import { CFile } from './c.ts'; import { CSSFile } from './css.ts'; diff --git a/src/common/filetype/mod.ts b/src/common/filetype/mod.ts deleted file mode 100644 index a2bf1a0..0000000 --- a/src/common/filetype/mod.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './base.ts'; -export * from './filetype.ts'; - -import FileType from './filetype.ts'; -export default FileType; diff --git a/src/common/fns.ts b/src/common/fns.ts index dcc6f1a..aefde84 100644 --- a/src/common/fns.ts +++ b/src/common/fns.ts @@ -1,4 +1,6 @@ -import { KeyCommand } from './ansi.ts'; +import Ansi, { KeyCommand } from './ansi.ts'; +import { SCROLL_COLOR_SCHEME } from './config.ts'; +import { HighlightType } from './types.ts'; const decoder = new TextDecoder(); @@ -57,6 +59,16 @@ export function readKey(raw: Uint8Array): string { } } +/** + * Return the configured ANSI formatting escape codes for the + * type of syntax specified + * + * @param type The type of syntax to highlight + */ +export function highlightToColor(type: HighlightType): string { + return SCROLL_COLOR_SCHEME.get(type) ?? Ansi.ResetFormatting; +} + // ---------------------------------------------------------------------------- // Array manipulation // ---------------------------------------------------------------------------- diff --git a/src/common/highlight.ts b/src/common/highlight.ts deleted file mode 100644 index 7919562..0000000 --- a/src/common/highlight.ts +++ /dev/null @@ -1,38 +0,0 @@ -import Ansi from './ansi.ts'; -import { SCROLL_COLOR_SCHEME } from './config.ts'; - -/** - * The type of Syntax being highlighted - */ -export enum HighlightType { - /** No highlighting */ - None, - /** Number literals */ - Number, - /** Search results */ - Match, - /** Character literals */ - Character, - /** String literals */ - String, - /** Single line comments */ - SingleLineComment, - /** Multi-line comments */ - MultiLineComment, - /** Primary keywords */ - Keyword1, - /** Secondary keywords */ - Keyword2, - /** Math/logic operators */ - Operator, -} - -/** - * Return the configured ANSI formatting escape codes for the - * type of syntax specified - * - * @param type The type of syntax to highlight - */ -export function highlightToColor(type: HighlightType): string { - return SCROLL_COLOR_SCHEME.get(type) ?? Ansi.ResetFormatting; -} diff --git a/src/common/main.ts b/src/common/main.ts index a3f3acd..9328a3d 100644 --- a/src/common/main.ts +++ b/src/common/main.ts @@ -4,10 +4,15 @@ import { logError, logWarning, node_process as process, -} from './runtime/mod.ts'; +} from './runtime.ts'; import Editor from './editor.ts'; -export async function main() { +/** + * The main runtime loop + * + * Only returns on error or quit + */ +export async function main(): Promise { const rt = await getRuntime(); const { term } = rt; @@ -18,7 +23,7 @@ export async function main() { }); // Setup error handler to log to file - rt.onEvent('error', (error) => { + rt.onEvent('error', (error: any) => { process.stdin.setRawMode(false); logError(JSON.stringify(error, null, 2)); }); diff --git a/src/common/position.ts b/src/common/position.ts index 06010c5..cc50cd8 100644 --- a/src/common/position.ts +++ b/src/common/position.ts @@ -4,14 +4,23 @@ export class Position { private constructor(public x: number = 0, public y: number = 0) {} + /** + * Create a new `Position` at the specified location + */ public static at(x: number, y: number): Position { return new Position(x, y); } + /** + * Create a new `Position` from an existing one + */ public static from(p: Position): Position { return new Position(p.x, p.y); } + /** + * Create a new `Position` at the origin (0, 0) + */ public static default(): Position { return new Position(); } diff --git a/src/common/row.ts b/src/common/row.ts index 4e10d47..2a22829 100644 --- a/src/common/row.ts +++ b/src/common/row.ts @@ -3,16 +3,16 @@ import Ansi from './ansi.ts'; import { SCROLL_TAB_SIZE } from './config.ts'; import { arrayInsert, + highlightToColor, isAsciiDigit, isSeparator, strChars, strlen, substr, } from './fns.ts'; -import { FileType } from './filetype/mod.ts'; -import { highlightToColor, HighlightType } from './highlight.ts'; +import { FileType } from './filetype.ts'; import Option, { None, Some } from './option.ts'; -import { SearchDirection } from './types.ts'; +import { HighlightType, SearchDirection } from './types.ts'; const SINGLE_QUOTE = "'"; const DOUBLE_QUOTE = '"'; diff --git a/src/common/runtime.ts b/src/common/runtime.ts new file mode 100644 index 0000000..9db1a16 --- /dev/null +++ b/src/common/runtime.ts @@ -0,0 +1,11 @@ +export * from './runtime/file_io.ts'; +export * from './runtime/helpers.ts'; +export * from './runtime/log.ts'; +export * from './runtime/node.ts'; +export * from './runtime/runtime.ts'; +export * from './runtime/terminal_io.ts'; +export * from './runtime/test_base.ts'; +export { RunTimeType } from './types.ts'; + +import { CommonRuntime } from './runtime/runtime.ts'; +export default CommonRuntime; diff --git a/src/common/runtime/file_io.ts b/src/common/runtime/file_io.ts index 9f13d08..a91464a 100644 --- a/src/common/runtime/file_io.ts +++ b/src/common/runtime/file_io.ts @@ -1,8 +1,11 @@ import { appendFile, readFile, writeFile } from 'node:fs/promises'; import { resolve } from 'node:path'; -import { IFileIO } from './mod.ts'; +import { IFileIO } from './runtime.ts'; +/** + * File IO implementation using shared node APIs + */ export const CommonFileIO: IFileIO = { openFile: async function (path: string): Promise { const filePath = resolve(path); diff --git a/src/common/runtime/helpers.ts b/src/common/runtime/helpers.ts index 8e559ff..98fb88e 100644 --- a/src/common/runtime/helpers.ts +++ b/src/common/runtime/helpers.ts @@ -3,8 +3,9 @@ */ import { logError, logWarning } from './log.ts'; import { node_path as path, node_process as process } from './node.ts'; -import { RunTimeType } from './runtime.ts'; -import { IRuntime, ITestBase } from '../types.ts'; +import { IRuntime } from './runtime.ts'; +import { ITestBase } from './test_base.ts'; +import { RunTimeType } from '../types.ts'; let scrollRuntime: IRuntime | null = null; diff --git a/src/common/runtime/log.ts b/src/common/runtime/log.ts index 308949e..e1e5823 100644 --- a/src/common/runtime/log.ts +++ b/src/common/runtime/log.ts @@ -1,6 +1,6 @@ import { noop } from '../fns.ts'; import { SCROLL_LOG_FILE_PREFIX, SCROLL_LOG_FILE_SUFFIX } from '../config.ts'; -import { getRuntime } from './mod.ts'; +import { getRuntime } from './helpers.ts'; /** * The label for type/severity of the log entry @@ -14,7 +14,11 @@ export enum LogLevel { } /** - * Basic logging - + * Basic logging + * + * @param s The string or data to display first + * @param level The log severity + * @param data Any additional data to display with the log entry */ export function log( s: unknown, @@ -34,12 +38,31 @@ export function log( }); } +/** + * Make a log entry of `LogLevel.Debug` severity + */ export const logDebug = (s: unknown, data?: any) => log(s, LogLevel.Debug, data); + +/** + * Make a log entry of `LogLevel.Info` severity + */ export const logInfo = (s: unknown, data?: any) => log(s, LogLevel.Info, data); + +/** + * Make a log entry of `LogLevel.Notice` severity + */ export const logNotice = (s: unknown, data?: any) => log(s, LogLevel.Notice, data); + +/** + * Make a log entry of `LogLevel.Warning` severity + */ export const logWarning = (s: unknown, data?: any) => log(s, LogLevel.Warning, data); + +/** + * Make a log entry of `LogLevel.Error` severity + */ export const logError = (s: unknown, data?: any) => log(s, LogLevel.Warning, data); diff --git a/src/common/runtime/mod.ts b/src/common/runtime/mod.ts deleted file mode 100644 index 7a80efe..0000000 --- a/src/common/runtime/mod.ts +++ /dev/null @@ -1,10 +0,0 @@ -export * from './file_io.ts'; -export * from './helpers.ts'; -export * from './log.ts'; -export * from './node.ts'; -export * from './runtime.ts'; -export * from './terminal_io.ts'; -export * from './test_base.ts'; - -import { CommonRuntime } from './runtime.ts'; -export default CommonRuntime; diff --git a/src/common/runtime/runtime.ts b/src/common/runtime/runtime.ts index 5adc69d..e17bc1e 100644 --- a/src/common/runtime/runtime.ts +++ b/src/common/runtime/runtime.ts @@ -1,6 +1,7 @@ import { node_process as process } from './node.ts'; import CommonFileIO from './file_io.ts'; import CommonTerminalIO from './terminal_io.ts'; +import { RunTimeType } from '../types.ts'; // ---------------------------------------------------------------------------- // Runtime adapter interfaces @@ -14,16 +15,6 @@ export interface ITerminalSize { cols: number; } -/** - * Which Typescript runtime is currently being used - */ -export enum RunTimeType { - Bun = 'bun', - Deno = 'deno', - Tsx = 'tsx', - Unknown = 'common', -} - /** * Runtime-specific terminal functionality */ @@ -131,6 +122,9 @@ export interface IRuntime { exit(code?: number): void; } +/** + * Base runtime using shared Node APIs + */ export const CommonRuntime: IRuntime = { name: RunTimeType.Unknown, term: CommonTerminalIO, diff --git a/src/common/runtime/terminal_io.ts b/src/common/runtime/terminal_io.ts index 9804e61..cc137ff 100644 --- a/src/common/runtime/terminal_io.ts +++ b/src/common/runtime/terminal_io.ts @@ -2,6 +2,9 @@ import { node_process as process } from './node.ts'; import { readKey } from '../fns.ts'; import { ITerminal, ITerminalSize } from '../types.ts'; +/** + * Terminal IO using shared Node APIs + */ export const CommonTerminalIO: ITerminal = { argv: (process.argv.length > 2) ? process.argv.slice(2) : [], inputLoop: async function* (): AsyncGenerator { diff --git a/src/common/runtime/test_base.ts b/src/common/runtime/test_base.ts index c143d31..c4133cc 100644 --- a/src/common/runtime/test_base.ts +++ b/src/common/runtime/test_base.ts @@ -4,6 +4,10 @@ import { deepStrictEqual, notStrictEqual, strictEqual } from 'node:assert'; import Option from '../option.ts'; +/** + * The shared interface for tests, running on a different test + * runner for each runtime + */ export interface ITestBase { assertEquivalent(actual: unknown, expected: unknown): void; assertExists(actual: unknown): void; @@ -20,6 +24,9 @@ export interface ITestBase { testSuite(testObj: any): void; } +/** + * The base testing implementation using Node assert API + */ export abstract class AbstractTestBase implements Partial { /** * The values (often objects) have all the same property values diff --git a/src/common/types.ts b/src/common/types.ts index bd6cd2f..d85e9f8 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -1,13 +1,42 @@ -export { HighlightType } from './highlight.ts'; export { Position } from './position.ts'; export type { ITestBase } from './runtime/test_base.ts'; -export type { - IFileIO, - IRuntime, - ITerminal, - ITerminalSize, - RunTimeType, -} from './runtime/mod.ts'; +export type { IFileIO, IRuntime, ITerminal, ITerminalSize } from './runtime.ts'; + +/** + * Which Typescript runtime is currently being used + */ +export enum RunTimeType { + Bun = 'bun', + Deno = 'deno', + Tsx = 'tsx', + Unknown = 'unknown', +} + +/** + * The type of Syntax being highlighted + */ +export enum HighlightType { + /** No highlighting */ + None, + /** Number literals */ + Number, + /** Search results */ + Match, + /** Character literals */ + Character, + /** String literals */ + String, + /** Single line comments */ + SingleLineComment, + /** Multi-line comments */ + MultiLineComment, + /** Primary keywords */ + Keyword1, + /** Secondary keywords */ + Keyword2, + /** Math/logic operators */ + Operator, +} /** * Which direction to search in the current document diff --git a/src/deno/file_io.ts b/src/deno/file_io.ts index 83f6bf7..c81194d 100644 --- a/src/deno/file_io.ts +++ b/src/deno/file_io.ts @@ -1,4 +1,4 @@ -import { IFileIO } from '../common/runtime/mod.ts'; +import { IFileIO } from '../common/runtime.ts'; const DenoFileIO: IFileIO = { openFile: async function (path: string): Promise { diff --git a/src/deno/mod.ts b/src/deno/mod.ts index 6d528e9..22dfef9 100644 --- a/src/deno/mod.ts +++ b/src/deno/mod.ts @@ -1,7 +1,7 @@ /** * The main entrypoint when using Deno as the runtime */ -import { CommonRuntime, IRuntime, RunTimeType } from '../common/runtime/mod.ts'; +import { CommonRuntime, IRuntime, RunTimeType } from '../common/runtime.ts'; import DenoTerminalIO from './terminal_io.ts'; import DenoFileIO from './file_io.ts'; diff --git a/src/tsx/mod.ts b/src/tsx/mod.ts index bd203c7..2ade92b 100644 --- a/src/tsx/mod.ts +++ b/src/tsx/mod.ts @@ -1,7 +1,7 @@ /** * The main entrypoint when using Tsx as the runtime */ -import { CommonRuntime, IRuntime, RunTimeType } from '../common/runtime/mod.ts'; +import { CommonRuntime, IRuntime, RunTimeType } from '../common/runtime.ts'; /** * The Tsx Runtime implementation