This commit is contained in:
parent
21ff71cc94
commit
1951425508
@ -1,26 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* The main entrypoint when using Bun as the runtime
|
* The main entrypoint when using Bun as the runtime
|
||||||
*/
|
*/
|
||||||
|
import { CommonRuntime, IRuntime, RunTimeType } from '../common/runtime/mod.ts';
|
||||||
import { IRuntime, RunTimeType } from '../common/runtime.ts';
|
|
||||||
import { process } from '../common/runtime/node.ts';
|
|
||||||
import TerminalIO from '../common/runtime/terminal_io.ts';
|
|
||||||
import FileIO from '../common/runtime/file_io.ts';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Bun Runtime implementation
|
* The Bun Runtime implementation
|
||||||
*/
|
*/
|
||||||
const BunRuntime: IRuntime = {
|
const BunRuntime: IRuntime = {
|
||||||
|
...CommonRuntime,
|
||||||
name: RunTimeType.Bun,
|
name: RunTimeType.Bun,
|
||||||
file: FileIO,
|
|
||||||
term: TerminalIO,
|
|
||||||
onEvent: (eventName: string, handler) => process.on(eventName, handler),
|
|
||||||
onExit: (cb: () => void): void => {
|
|
||||||
process.on('beforeExit', cb);
|
|
||||||
process.on('exit', cb);
|
|
||||||
process.on('SIGINT', cb);
|
|
||||||
},
|
|
||||||
exit: (code?: number) => process.exit(code),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default BunRuntime;
|
export default BunRuntime;
|
||||||
|
@ -9,7 +9,7 @@ import Row from './row.ts';
|
|||||||
|
|
||||||
import * as Fn from './fns.ts';
|
import * as Fn from './fns.ts';
|
||||||
import { defaultTerminalSize, SCROLL_TAB_SIZE } from './config.ts';
|
import { defaultTerminalSize, SCROLL_TAB_SIZE } from './config.ts';
|
||||||
import { getTestRunner } from './runtime.ts';
|
import { getTestRunner } from './runtime/mod.ts';
|
||||||
import { SearchDirection } from './types.ts';
|
import { SearchDirection } from './types.ts';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -20,6 +20,8 @@ const {
|
|||||||
assertNotEquals,
|
assertNotEquals,
|
||||||
assertFalse,
|
assertFalse,
|
||||||
assertTrue,
|
assertTrue,
|
||||||
|
assertSome,
|
||||||
|
assertNone,
|
||||||
testSuite,
|
testSuite,
|
||||||
} = await getTestRunner();
|
} = await getTestRunner();
|
||||||
|
|
||||||
@ -433,10 +435,15 @@ const EditorTest = {
|
|||||||
|
|
||||||
const OptionTest = {
|
const OptionTest = {
|
||||||
'Option.from()': () => {
|
'Option.from()': () => {
|
||||||
assertTrue(Option.from(null).isNone());
|
assertNone(Option.from(null));
|
||||||
assertTrue(Option.from().isNone());
|
assertNone(Option.from());
|
||||||
assertEquivalent(Option.from(undefined), None);
|
assertEquivalent(Option.from(undefined), None);
|
||||||
|
|
||||||
|
assertSome(Option.from('foo'));
|
||||||
|
assertSome(Option.from(234));
|
||||||
|
assertSome(Option.from({}));
|
||||||
|
assertSome(Some([1, 2, 3]));
|
||||||
|
|
||||||
assertEquivalent(Option.from(Some('foo')), Some('foo'));
|
assertEquivalent(Option.from(Some('foo')), Some('foo'));
|
||||||
assertEquivalent(Some(Some('bar')), Some('bar'));
|
assertEquivalent(Some(Some('bar')), Some('bar'));
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { strlen, truncate } from './fns.ts';
|
import { strlen, truncate } from './fns.ts';
|
||||||
import { getRuntime } from './runtime.ts';
|
import { getRuntime } from './runtime/mod.ts';
|
||||||
|
|
||||||
class Buffer {
|
class Buffer {
|
||||||
#b = '';
|
#b = '';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Row from './row.ts';
|
import Row from './row.ts';
|
||||||
import { arrayInsert, maxAdd, minSub } from './fns.ts';
|
import { arrayInsert, maxAdd, minSub } from './fns.ts';
|
||||||
import Option, { None, Some } from './option.ts';
|
import Option, { None, Some } from './option.ts';
|
||||||
import { getRuntime, logDebug, logWarning } from './runtime.ts';
|
import { getRuntime, logDebug, logWarning } from './runtime/mod.ts';
|
||||||
import { Position, SearchDirection } from './types.ts';
|
import { Position, SearchDirection } from './types.ts';
|
||||||
|
|
||||||
export class Document {
|
export class Document {
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
truncate,
|
truncate,
|
||||||
} from './fns.ts';
|
} from './fns.ts';
|
||||||
import Option, { None, Some } from './option.ts';
|
import Option, { None, Some } from './option.ts';
|
||||||
import { getRuntime, logDebug, logWarning } from './runtime.ts';
|
import { getRuntime, logDebug, logWarning } from './runtime/mod.ts';
|
||||||
import { ITerminalSize, Position, SearchDirection } from './types.ts';
|
import { ITerminalSize, Position, SearchDirection } from './types.ts';
|
||||||
|
|
||||||
export default class Editor {
|
export default class Editor {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { process } from './runtime/node.ts';
|
|
||||||
import { readKey } from './fns.ts';
|
import { readKey } from './fns.ts';
|
||||||
import { getRuntime, logError, logWarning } from './runtime.ts';
|
import { getRuntime, logError, logWarning, process } from './runtime/mod.ts';
|
||||||
import Editor from './editor.ts';
|
import Editor from './editor.ts';
|
||||||
|
|
||||||
export async function main() {
|
export async function main() {
|
||||||
|
@ -1,204 +0,0 @@
|
|||||||
/**
|
|
||||||
* Functions/Methods that depend on the current runtime to function
|
|
||||||
*/
|
|
||||||
import { process } from './runtime/node.ts';
|
|
||||||
import Ansi from './ansi.ts';
|
|
||||||
import { IRuntime, ITerminalSize, ITestBase } from './types.ts';
|
|
||||||
import { noop } from './fns.ts';
|
|
||||||
import {
|
|
||||||
defaultTerminalSize,
|
|
||||||
SCROLL_LOG_FILE_PREFIX,
|
|
||||||
SCROLL_LOG_FILE_SUFFIX,
|
|
||||||
} from './config.ts';
|
|
||||||
|
|
||||||
export type { IFileIO, IRuntime, ITerminal } from './types.ts';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Which Typescript runtime is currently being used
|
|
||||||
*/
|
|
||||||
export enum RunTimeType {
|
|
||||||
Bun = 'bun',
|
|
||||||
Deno = 'deno',
|
|
||||||
Tsx = 'tsx',
|
|
||||||
Unknown = 'common',
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The label for type/severity of the log entry
|
|
||||||
*/
|
|
||||||
export enum LogLevel {
|
|
||||||
Debug = 'Debug',
|
|
||||||
Info = 'Info',
|
|
||||||
Notice = 'Notice',
|
|
||||||
Warning = 'Warning',
|
|
||||||
Error = 'Error',
|
|
||||||
}
|
|
||||||
|
|
||||||
let scrollRuntime: IRuntime | null = null;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Misc runtime functions
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the size of the terminal window via ANSI codes
|
|
||||||
* @see https://viewsourcecode.org/snaptoken/kilo/03.rawInputAndOutput.html#window-size-the-hard-way
|
|
||||||
*/
|
|
||||||
async function _getTerminalSizeFromAnsi(): Promise<ITerminalSize> {
|
|
||||||
const { term } = await getRuntime();
|
|
||||||
|
|
||||||
// Tell the cursor to move to Row 999 and Column 999
|
|
||||||
// Since this command specifically doesn't go off the screen
|
|
||||||
// When we ask where the cursor is, we should get the size of the screen
|
|
||||||
await term.writeStdout(
|
|
||||||
Ansi.moveCursorForward(999) + Ansi.moveCursorDown(999),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ask where the cursor is
|
|
||||||
await term.writeStdout(Ansi.GetCursorLocation);
|
|
||||||
|
|
||||||
// Get the first chunk from stdin
|
|
||||||
// The response is \x1b[(rows);(cols)R..
|
|
||||||
const chunk = await term.readStdinRaw();
|
|
||||||
if (chunk === null) {
|
|
||||||
return defaultTerminalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rawCode = (new TextDecoder()).decode(chunk);
|
|
||||||
const res = rawCode.trim().replace(/^.\[([0-9]+;[0-9]+)R$/, '$1');
|
|
||||||
const [srows, scols] = res.split(';');
|
|
||||||
const rows = parseInt(srows, 10) ?? 24;
|
|
||||||
const cols = parseInt(scols, 10) ?? 80;
|
|
||||||
|
|
||||||
// Clear the screen
|
|
||||||
await term.writeStdout(Ansi.ClearScreen + Ansi.ResetCursor);
|
|
||||||
|
|
||||||
return {
|
|
||||||
rows,
|
|
||||||
cols,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic logging -
|
|
||||||
*/
|
|
||||||
export function log(
|
|
||||||
s: unknown,
|
|
||||||
level: LogLevel = LogLevel.Notice,
|
|
||||||
data?: any,
|
|
||||||
): void {
|
|
||||||
getRuntime().then(({ file }) => {
|
|
||||||
const rawS = JSON.stringify(s, null, 2);
|
|
||||||
const rawData = JSON.stringify(data, null, 2);
|
|
||||||
const output = (typeof data !== 'undefined')
|
|
||||||
? `${rawS}\n${rawData}\n\n`
|
|
||||||
: `${rawS}\n`;
|
|
||||||
|
|
||||||
const outputFile =
|
|
||||||
`${SCROLL_LOG_FILE_PREFIX}-${level.toLowerCase()}${SCROLL_LOG_FILE_SUFFIX}`;
|
|
||||||
file.appendFile(outputFile, output).then(noop);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const logDebug = (s: unknown, data?: any) =>
|
|
||||||
log(s, LogLevel.Debug, data);
|
|
||||||
export const logInfo = (s: unknown, data?: any) => log(s, LogLevel.Info, data);
|
|
||||||
export const logNotice = (s: unknown, data?: any) =>
|
|
||||||
log(s, LogLevel.Notice, data);
|
|
||||||
export const logWarning = (s: unknown, data?: any) =>
|
|
||||||
log(s, LogLevel.Warning, data);
|
|
||||||
export const logError = (s: unknown, data?: any) =>
|
|
||||||
log(s, LogLevel.Warning, data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Kill program, displaying an error message
|
|
||||||
* @param s
|
|
||||||
*/
|
|
||||||
export function die(s: string | Error): void {
|
|
||||||
logError(s);
|
|
||||||
process.stdin.setRawMode(false);
|
|
||||||
console.error(s);
|
|
||||||
getRuntime().then((r) => r.exit());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine which Typescript runtime we are operating under
|
|
||||||
*/
|
|
||||||
export function runtimeType(): RunTimeType {
|
|
||||||
let runtime = RunTimeType.Tsx;
|
|
||||||
|
|
||||||
if ('Deno' in globalThis) {
|
|
||||||
runtime = RunTimeType.Deno;
|
|
||||||
}
|
|
||||||
if ('Bun' in globalThis) {
|
|
||||||
runtime = RunTimeType.Bun;
|
|
||||||
}
|
|
||||||
|
|
||||||
return runtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the adapter object for the current Runtime
|
|
||||||
*/
|
|
||||||
export async function getRuntime(): Promise<IRuntime> {
|
|
||||||
if (scrollRuntime === null) {
|
|
||||||
const runtime = runtimeType();
|
|
||||||
const path = `../${runtime}/mod.ts`;
|
|
||||||
|
|
||||||
const pkg = await import(path);
|
|
||||||
if ('default' in pkg) {
|
|
||||||
scrollRuntime = pkg.default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scrollRuntime !== null) {
|
|
||||||
return Promise.resolve(scrollRuntime);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject('Missing default import');
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve(scrollRuntime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the common test interface object
|
|
||||||
*/
|
|
||||||
export async function getTestRunner(): Promise<ITestBase> {
|
|
||||||
const runtime = runtimeType();
|
|
||||||
const path = `../${runtime}/test_base.ts`;
|
|
||||||
const pkg = await import(path);
|
|
||||||
if ('default' in pkg) {
|
|
||||||
return pkg.default;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pkg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import a runtime-specific module
|
|
||||||
*
|
|
||||||
* e.g. to load "src/bun/mod.ts", if the runtime is bun,
|
|
||||||
* you can use like so `await importForRuntime('index')`;
|
|
||||||
*
|
|
||||||
* @param path - the path within the runtime module
|
|
||||||
*/
|
|
||||||
export const importForRuntime = async (path: string) => {
|
|
||||||
const runtime = runtimeType();
|
|
||||||
const suffix = '.ts';
|
|
||||||
const base = `../${runtime}/`;
|
|
||||||
|
|
||||||
const pathParts = path
|
|
||||||
.split('/')
|
|
||||||
.filter((part) => part !== '' && part !== '.' && part !== suffix)
|
|
||||||
.map((part) => part.replace(suffix, ''));
|
|
||||||
|
|
||||||
const cleanedPath = pathParts.join('/');
|
|
||||||
const importPath = base + cleanedPath + suffix;
|
|
||||||
|
|
||||||
const pkg = await import(importPath);
|
|
||||||
if ('default' in pkg) {
|
|
||||||
return pkg.default;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pkg;
|
|
||||||
};
|
|
@ -1,9 +1,9 @@
|
|||||||
import { appendFile, readFile, writeFile } from 'node:fs/promises';
|
import { appendFile, readFile, writeFile } from 'node:fs/promises';
|
||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
import { IFileIO } from '../runtime.ts';
|
import { IFileIO } from './mod.ts';
|
||||||
|
|
||||||
const CommonFileIO: IFileIO = {
|
export const CommonFileIO: IFileIO = {
|
||||||
openFile: async function (path: string): Promise<string> {
|
openFile: async function (path: string): Promise<string> {
|
||||||
const filePath = resolve(path);
|
const filePath = resolve(path);
|
||||||
const contents = await readFile(filePath, { encoding: 'utf8' });
|
const contents = await readFile(filePath, { encoding: 'utf8' });
|
||||||
|
72
src/common/runtime/helpers.ts
Normal file
72
src/common/runtime/helpers.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* Functions/Methods that depend on the current runtime to function
|
||||||
|
*/
|
||||||
|
import { logError } from './log.ts';
|
||||||
|
import { process } from './node.ts';
|
||||||
|
import { RunTimeType } from './runtime.ts';
|
||||||
|
import { IRuntime, ITestBase } from '../types.ts';
|
||||||
|
|
||||||
|
let scrollRuntime: IRuntime | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kill program, displaying an error message
|
||||||
|
* @param s
|
||||||
|
*/
|
||||||
|
export function die(s: string | Error): void {
|
||||||
|
logError(s);
|
||||||
|
process.stdin.setRawMode(false);
|
||||||
|
console.error(s);
|
||||||
|
getRuntime().then((r) => r.exit());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine which Typescript runtime we are operating under
|
||||||
|
*/
|
||||||
|
export function runtimeType(): RunTimeType {
|
||||||
|
let runtime = RunTimeType.Tsx;
|
||||||
|
|
||||||
|
if ('Deno' in globalThis) {
|
||||||
|
runtime = RunTimeType.Deno;
|
||||||
|
} else if ('Bun' in globalThis) {
|
||||||
|
runtime = RunTimeType.Bun;
|
||||||
|
}
|
||||||
|
|
||||||
|
return runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the adapter object for the current Runtime
|
||||||
|
*/
|
||||||
|
export async function getRuntime(): Promise<IRuntime> {
|
||||||
|
if (scrollRuntime === null) {
|
||||||
|
const runtime = runtimeType();
|
||||||
|
const path = `../../${runtime}/mod.ts`;
|
||||||
|
|
||||||
|
const pkg = await import(path);
|
||||||
|
if ('default' in pkg) {
|
||||||
|
scrollRuntime = pkg.default;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollRuntime !== null) {
|
||||||
|
return Promise.resolve(scrollRuntime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject('Missing default import');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(scrollRuntime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the common test interface object
|
||||||
|
*/
|
||||||
|
export async function getTestRunner(): Promise<ITestBase> {
|
||||||
|
const runtime = runtimeType();
|
||||||
|
const path = `../../${runtime}/test_base.ts`;
|
||||||
|
const pkg = await import(path);
|
||||||
|
if ('default' in pkg) {
|
||||||
|
return pkg.default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkg;
|
||||||
|
}
|
45
src/common/runtime/log.ts
Normal file
45
src/common/runtime/log.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { noop } from '../fns.ts';
|
||||||
|
import { SCROLL_LOG_FILE_PREFIX, SCROLL_LOG_FILE_SUFFIX } from '../config.ts';
|
||||||
|
import { getRuntime } from './mod.ts';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The label for type/severity of the log entry
|
||||||
|
*/
|
||||||
|
export enum LogLevel {
|
||||||
|
Debug = 'Debug',
|
||||||
|
Info = 'Info',
|
||||||
|
Notice = 'Notice',
|
||||||
|
Warning = 'Warning',
|
||||||
|
Error = 'Error',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic logging -
|
||||||
|
*/
|
||||||
|
export function log(
|
||||||
|
s: unknown,
|
||||||
|
level: LogLevel = LogLevel.Notice,
|
||||||
|
data?: any,
|
||||||
|
): void {
|
||||||
|
getRuntime().then(({ file }) => {
|
||||||
|
const rawS = JSON.stringify(s, null, 2);
|
||||||
|
const rawData = JSON.stringify(data, null, 2);
|
||||||
|
const output = (typeof data !== 'undefined')
|
||||||
|
? `${rawS}\n${rawData}\n\n`
|
||||||
|
: `${rawS}\n`;
|
||||||
|
|
||||||
|
const outputFile =
|
||||||
|
`${SCROLL_LOG_FILE_PREFIX}-${level.toLowerCase()}${SCROLL_LOG_FILE_SUFFIX}`;
|
||||||
|
file.appendFile(outputFile, output).then(noop);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const logDebug = (s: unknown, data?: any) =>
|
||||||
|
log(s, LogLevel.Debug, data);
|
||||||
|
export const logInfo = (s: unknown, data?: any) => log(s, LogLevel.Info, data);
|
||||||
|
export const logNotice = (s: unknown, data?: any) =>
|
||||||
|
log(s, LogLevel.Notice, data);
|
||||||
|
export const logWarning = (s: unknown, data?: any) =>
|
||||||
|
log(s, LogLevel.Warning, data);
|
||||||
|
export const logError = (s: unknown, data?: any) =>
|
||||||
|
log(s, LogLevel.Warning, data);
|
7
src/common/runtime/mod.ts
Normal file
7
src/common/runtime/mod.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
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';
|
@ -1,3 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Re-export of node apis shared by runtimes
|
||||||
|
*/
|
||||||
|
import * as assert from 'node:assert';
|
||||||
import * as process from 'node:process';
|
import * as process from 'node:process';
|
||||||
|
|
||||||
export { process };
|
export { assert, process };
|
||||||
|
145
src/common/runtime/runtime.ts
Normal file
145
src/common/runtime/runtime.ts
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
import { process } from './node.ts';
|
||||||
|
import CommonFileIO from './file_io.ts';
|
||||||
|
import CommonTerminalIO from './terminal_io.ts';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Runtime adapter interfaces
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of terminal in rows and columns
|
||||||
|
*/
|
||||||
|
export interface ITerminalSize {
|
||||||
|
rows: number;
|
||||||
|
cols: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which Typescript runtime is currently being used
|
||||||
|
*/
|
||||||
|
export enum RunTimeType {
|
||||||
|
Bun = 'bun',
|
||||||
|
Deno = 'deno',
|
||||||
|
Tsx = 'tsx',
|
||||||
|
Unknown = 'common',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime-specific terminal functionality
|
||||||
|
*/
|
||||||
|
export interface ITerminal {
|
||||||
|
/**
|
||||||
|
* The arguments passed to the program on launch
|
||||||
|
*/
|
||||||
|
argv: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The generator function returning chunks of input from the stdin stream
|
||||||
|
*/
|
||||||
|
inputLoop(): AsyncGenerator<Uint8Array, null>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the terminal
|
||||||
|
*/
|
||||||
|
getTerminalSize(): Promise<ITerminalSize>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current chunk of input, if it exists
|
||||||
|
*/
|
||||||
|
readStdin(): Promise<string | null>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the raw chunk of input
|
||||||
|
*/
|
||||||
|
readStdinRaw(): Promise<Uint8Array | null>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pipe a string to stdout
|
||||||
|
*/
|
||||||
|
writeStdout(s: string): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime-specific file system io
|
||||||
|
*/
|
||||||
|
export interface IFileIO {
|
||||||
|
/**
|
||||||
|
* Open an entire file
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
openFile(path: string): Promise<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append to a file, or create it if it doesn't exist
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @param contents
|
||||||
|
*/
|
||||||
|
appendFile(path: string, contents: string): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save a string into a file
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @param contents
|
||||||
|
*/
|
||||||
|
saveFile(path: string, contents: string): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The common interface for runtime adapters
|
||||||
|
*/
|
||||||
|
export interface IRuntime {
|
||||||
|
/**
|
||||||
|
* The name of the runtime
|
||||||
|
*/
|
||||||
|
name: RunTimeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime-specific terminal functionality
|
||||||
|
*/
|
||||||
|
term: ITerminal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime-specific file system io
|
||||||
|
*/
|
||||||
|
file: IFileIO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up an event handler
|
||||||
|
*
|
||||||
|
* @param eventName - The event to listen for
|
||||||
|
* @param handler - The event handler
|
||||||
|
*/
|
||||||
|
onEvent: (
|
||||||
|
eventName: string,
|
||||||
|
handler: (e: Event | ErrorEvent) => void,
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a beforeExit/beforeUnload event handler for the runtime
|
||||||
|
* @param cb - The event handler
|
||||||
|
*/
|
||||||
|
onExit(cb: () => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop execution
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
*/
|
||||||
|
exit(code?: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CommonRuntime: IRuntime = {
|
||||||
|
name: RunTimeType.Unknown,
|
||||||
|
term: CommonTerminalIO,
|
||||||
|
file: CommonFileIO,
|
||||||
|
onEvent: (eventName: string, handler) => process.on(eventName, handler),
|
||||||
|
onExit: (cb: () => void): void => {
|
||||||
|
process.on('beforeExit', cb);
|
||||||
|
process.on('exit', cb);
|
||||||
|
process.on('SIGINT', cb);
|
||||||
|
},
|
||||||
|
exit: (code?: number) => process.exit(code),
|
||||||
|
};
|
@ -2,7 +2,7 @@ import { process } from './node.ts';
|
|||||||
import { readKey } from '../fns.ts';
|
import { readKey } from '../fns.ts';
|
||||||
import { ITerminal, ITerminalSize } from '../types.ts';
|
import { ITerminal, ITerminalSize } from '../types.ts';
|
||||||
|
|
||||||
const CommonTerminalIO: ITerminal = {
|
export const CommonTerminalIO: ITerminal = {
|
||||||
argv: (process.argv.length > 2) ? process.argv.slice(2) : [],
|
argv: (process.argv.length > 2) ? process.argv.slice(2) : [],
|
||||||
inputLoop: async function* (): AsyncGenerator<Uint8Array, null> {
|
inputLoop: async function* (): AsyncGenerator<Uint8Array, null> {
|
||||||
yield (await CommonTerminalIO.readStdinRaw()) ?? new Uint8Array(0);
|
yield (await CommonTerminalIO.readStdinRaw()) ?? new Uint8Array(0);
|
||||||
|
@ -20,7 +20,7 @@ export interface ITestBase {
|
|||||||
testSuite(testObj: any): void;
|
testSuite(testObj: any): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractTestBase implements Partial<ITestBase> {
|
export abstract class AbstractTestBase implements Partial<ITestBase> {
|
||||||
/**
|
/**
|
||||||
* The values (often objects) have all the same property values
|
* The values (often objects) have all the same property values
|
||||||
*/
|
*/
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
import { RunTimeType } from './runtime.ts';
|
|
||||||
|
|
||||||
export { Position } from './position.ts';
|
export { Position } from './position.ts';
|
||||||
export type { ITestBase } from './runtime/test_base.ts';
|
export type { ITestBase } from './runtime/test_base.ts';
|
||||||
|
export type {
|
||||||
/**
|
IFileIO,
|
||||||
* The size of terminal in rows and columns
|
IRuntime,
|
||||||
*/
|
ITerminal,
|
||||||
export interface ITerminalSize {
|
ITerminalSize,
|
||||||
rows: number;
|
RunTimeType,
|
||||||
cols: number;
|
} from './runtime/mod.ts';
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Which direction to search in the current document
|
* Which direction to search in the current document
|
||||||
@ -18,114 +15,3 @@ export enum SearchDirection {
|
|||||||
Forward = 1,
|
Forward = 1,
|
||||||
Backward = -1,
|
Backward = -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Runtime adapter interfaces
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime-specific terminal functionality
|
|
||||||
*/
|
|
||||||
export interface ITerminal {
|
|
||||||
/**
|
|
||||||
* The arguments passed to the program on launch
|
|
||||||
*/
|
|
||||||
argv: string[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The generator function returning chunks of input from the stdin stream
|
|
||||||
*/
|
|
||||||
inputLoop(): AsyncGenerator<Uint8Array, null>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the size of the terminal
|
|
||||||
*/
|
|
||||||
getTerminalSize(): Promise<ITerminalSize>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current chunk of input, if it exists
|
|
||||||
*/
|
|
||||||
readStdin(): Promise<string | null>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the raw chunk of input
|
|
||||||
*/
|
|
||||||
readStdinRaw(): Promise<Uint8Array | null>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pipe a string to stdout
|
|
||||||
*/
|
|
||||||
writeStdout(s: string): Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime-specific file system io
|
|
||||||
*/
|
|
||||||
export interface IFileIO {
|
|
||||||
/**
|
|
||||||
* Open an entire file
|
|
||||||
*
|
|
||||||
* @param path
|
|
||||||
*/
|
|
||||||
openFile(path: string): Promise<string>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append to a file, or create it if it doesn't exist
|
|
||||||
*
|
|
||||||
* @param path
|
|
||||||
* @param contents
|
|
||||||
*/
|
|
||||||
appendFile(path: string, contents: string): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save a string into a file
|
|
||||||
*
|
|
||||||
* @param path
|
|
||||||
* @param contents
|
|
||||||
*/
|
|
||||||
saveFile(path: string, contents: string): Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The common interface for runtime adapters
|
|
||||||
*/
|
|
||||||
export interface IRuntime {
|
|
||||||
/**
|
|
||||||
* The name of the runtime
|
|
||||||
*/
|
|
||||||
name: RunTimeType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime-specific terminal functionality
|
|
||||||
*/
|
|
||||||
term: ITerminal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime-specific file system io
|
|
||||||
*/
|
|
||||||
file: IFileIO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up an event handler
|
|
||||||
*
|
|
||||||
* @param eventName - The event to listen for
|
|
||||||
* @param handler - The event handler
|
|
||||||
*/
|
|
||||||
onEvent: (
|
|
||||||
eventName: string,
|
|
||||||
handler: (e: Event | ErrorEvent) => void,
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a beforeExit/beforeUnload event handler for the runtime
|
|
||||||
* @param cb - The event handler
|
|
||||||
*/
|
|
||||||
onExit(cb: () => void): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop execution
|
|
||||||
*
|
|
||||||
* @param code
|
|
||||||
*/
|
|
||||||
exit(code?: number): void;
|
|
||||||
}
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export * as stdAssert from 'https://deno.land/std@0.208.0/assert/mod.ts';
|
|
@ -1,4 +1,4 @@
|
|||||||
import { IFileIO } from '../common/runtime.ts';
|
import { IFileIO } from '../common/runtime/mod.ts';
|
||||||
|
|
||||||
const DenoFileIO: IFileIO = {
|
const DenoFileIO: IFileIO = {
|
||||||
openFile: async function (path: string): Promise<string> {
|
openFile: async function (path: string): Promise<string> {
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* The main entrypoint when using Deno as the runtime
|
* The main entrypoint when using Deno as the runtime
|
||||||
*/
|
*/
|
||||||
import { IRuntime, RunTimeType } from '../common/runtime.ts';
|
import { CommonRuntime, IRuntime, RunTimeType } from '../common/runtime/mod.ts';
|
||||||
import DenoTerminalIO from './terminal_io.ts';
|
import DenoTerminalIO from './terminal_io.ts';
|
||||||
import DenoFileIO from './file_io.ts';
|
import DenoFileIO from './file_io.ts';
|
||||||
|
|
||||||
import * as node_process from 'node:process';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Deno Runtime implementation
|
* The Deno Runtime implementation
|
||||||
*/
|
*/
|
||||||
const DenoRuntime: IRuntime = {
|
const DenoRuntime: IRuntime = {
|
||||||
|
...CommonRuntime,
|
||||||
name: RunTimeType.Deno,
|
name: RunTimeType.Deno,
|
||||||
file: DenoFileIO,
|
file: DenoFileIO,
|
||||||
term: DenoTerminalIO,
|
term: DenoTerminalIO,
|
||||||
@ -20,7 +19,6 @@ const DenoRuntime: IRuntime = {
|
|||||||
globalThis.addEventListener('onbeforeunload', cb);
|
globalThis.addEventListener('onbeforeunload', cb);
|
||||||
globalThis.onbeforeunload = cb;
|
globalThis.onbeforeunload = cb;
|
||||||
},
|
},
|
||||||
exit: (code?: number) => node_process.exit(code),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DenoRuntime;
|
export default DenoRuntime;
|
||||||
|
@ -1,25 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* The main entrypoint when using Tsx as the runtime
|
* The main entrypoint when using Tsx as the runtime
|
||||||
*/
|
*/
|
||||||
import { IRuntime, RunTimeType } from '../common/runtime.ts';
|
import { CommonRuntime, IRuntime, RunTimeType } from '../common/runtime/mod.ts';
|
||||||
import { process } from '../common/runtime/node.ts';
|
|
||||||
import TsxTerminalIO from '../common/runtime/terminal_io.ts';
|
|
||||||
import FileIO from '../common/runtime/file_io.ts';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Tsx Runtime implementation
|
* The Tsx Runtime implementation
|
||||||
*/
|
*/
|
||||||
const TsxRuntime: IRuntime = {
|
const TsxRuntime: IRuntime = {
|
||||||
|
...CommonRuntime,
|
||||||
name: RunTimeType.Tsx,
|
name: RunTimeType.Tsx,
|
||||||
file: FileIO,
|
|
||||||
term: TsxTerminalIO,
|
|
||||||
onEvent: (eventName: string, handler) => process.on(eventName, handler),
|
|
||||||
onExit: (cb: () => void): void => {
|
|
||||||
process.on('beforeExit', cb);
|
|
||||||
process.on('exit', cb);
|
|
||||||
process.on('SIGINT', cb);
|
|
||||||
},
|
|
||||||
exit: (code?: number) => process.exit(code),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TsxRuntime;
|
export default TsxRuntime;
|
||||||
|
Loading…
Reference in New Issue
Block a user