Refactor everything again
This commit is contained in:
parent
e9ce780c1d
commit
02be6a133c
1
justfile
1
justfile
@ -25,6 +25,7 @@ clean:
|
|||||||
rm -rf docs
|
rm -rf docs
|
||||||
rm -f scroll.log
|
rm -f scroll.log
|
||||||
rm -f scroll.err
|
rm -f scroll.err
|
||||||
|
rm -f tsconfig.tsbuildinfo
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
# Bun-specific commands
|
# Bun-specific commands
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { IFileIO } from '../common/runtime.ts';
|
import { IFileIO } from '../common/runtime.ts';
|
||||||
|
|
||||||
import { appendFileSync, readFileSync } from 'node:fs';
|
|
||||||
import { appendFile } from 'node:fs/promises';
|
import { appendFile } from 'node:fs/promises';
|
||||||
|
|
||||||
const BunFileIO: IFileIO = {
|
const BunFileIO: IFileIO = {
|
||||||
@ -8,15 +6,9 @@ const BunFileIO: IFileIO = {
|
|||||||
const file = await Bun.file(path);
|
const file = await Bun.file(path);
|
||||||
return await file.text();
|
return await file.text();
|
||||||
},
|
},
|
||||||
openFileSync: (path: string): string => {
|
|
||||||
return readFileSync(path).toString();
|
|
||||||
},
|
|
||||||
appendFile: async function (path: string, contents: string): Promise<void> {
|
appendFile: async function (path: string, contents: string): Promise<void> {
|
||||||
return await appendFile(path, contents);
|
return await appendFile(path, contents);
|
||||||
},
|
},
|
||||||
appendFileSync: function (path: string, contents: string) {
|
|
||||||
return appendFileSync(path, contents);
|
|
||||||
},
|
|
||||||
saveFile: async function (path: string, contents: string): Promise<void> {
|
saveFile: async function (path: string, contents: string): Promise<void> {
|
||||||
await Bun.write(path, contents);
|
await Bun.write(path, contents);
|
||||||
return;
|
return;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* The main entrypoint when using Bun as the runtime
|
* The main entrypoint when using Bun as the runtime
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IRuntime, RunTimeType } from '../common/mod.ts';
|
import { IRuntime, RunTimeType } from '../common/runtime.ts';
|
||||||
import BunTerminalIO from './terminal_io.ts';
|
import BunTerminalIO from './terminal_io.ts';
|
||||||
import BunFileIO from './file_io.ts';
|
import BunFileIO from './file_io.ts';
|
||||||
|
|
||||||
|
@ -2,12 +2,9 @@
|
|||||||
* Wrap the runtime-specific hook into stdin
|
* Wrap the runtime-specific hook into stdin
|
||||||
*/
|
*/
|
||||||
import Ansi from '../common/ansi.ts';
|
import Ansi from '../common/ansi.ts';
|
||||||
import {
|
import { defaultTerminalSize } from '../common/config.ts';
|
||||||
defaultTerminalSize,
|
import { readKey } from '../common/fns.ts';
|
||||||
ITerminal,
|
import { ITerminal, ITerminalSize } from '../common/types.ts';
|
||||||
ITerminalSize,
|
|
||||||
readKey,
|
|
||||||
} from '../common/mod.ts';
|
|
||||||
|
|
||||||
const BunTerminalIO: ITerminal = {
|
const BunTerminalIO: ITerminal = {
|
||||||
// Deno only returns arguments passed to the script, so
|
// Deno only returns arguments passed to the script, so
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Adapt the bun test interface to the shared testing interface
|
* Adapt the bun test interface to the shared testing interface
|
||||||
*/
|
*/
|
||||||
import { describe, expect, test } from 'bun:test';
|
import { describe, expect, test } from 'bun:test';
|
||||||
import { ITestBase } from '../common/mod.ts';
|
import { ITestBase } from '../common/types.ts';
|
||||||
|
|
||||||
export function testSuite(testObj: any) {
|
export function testSuite(testObj: any) {
|
||||||
Object.keys(testObj).forEach((group) => {
|
Object.keys(testObj).forEach((group) => {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Ansi, KeyCommand } from './ansi.ts';
|
|
||||||
import Buffer from './buffer.ts';
|
import Buffer from './buffer.ts';
|
||||||
import Document from './document.ts';
|
import Document from './document.ts';
|
||||||
import Editor from './editor.ts';
|
import Editor from './editor.ts';
|
||||||
import Row from './row.ts';
|
import Row from './row.ts';
|
||||||
import { getTestRunner, readKey } from './runtime.ts';
|
import { Ansi, KeyCommand } from './ansi.ts';
|
||||||
import { defaultTerminalSize } from './termios.ts';
|
import { defaultTerminalSize } from './config.ts';
|
||||||
|
import { getTestRunner } from './runtime.ts';
|
||||||
import { Position } from './types.ts';
|
import { Position } from './types.ts';
|
||||||
import * as Util from './utils.ts';
|
import * as Util from './fns.ts';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
assertEquals,
|
assertEquals,
|
||||||
@ -21,61 +21,29 @@ const {
|
|||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
const testKeyMap = (codes: string[], expected: string) => {
|
const testKeyMap = (codes: string[], expected: string) => {
|
||||||
codes.forEach((code) => {
|
codes.forEach((code) => {
|
||||||
assertEquals(readKey(encoder.encode(code)), expected);
|
assertEquals(Util.readKey(encoder.encode(code)), expected);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
testSuite({
|
testSuite({
|
||||||
'ANSI::ANSI utils': {
|
'ANSI utils': {
|
||||||
'Ansi.moveCursor': () => {
|
'moveCursor()': () => {
|
||||||
assertEquals(Ansi.moveCursor(1, 2), '\x1b[2;3H');
|
assertEquals(Ansi.moveCursor(1, 2), '\x1b[2;3H');
|
||||||
},
|
},
|
||||||
'Ansi.moveCursorForward': () => {
|
'moveCursorForward()': () => {
|
||||||
assertEquals(Ansi.moveCursorForward(2), '\x1b[2C');
|
assertEquals(Ansi.moveCursorForward(2), '\x1b[2C');
|
||||||
},
|
},
|
||||||
'Ansi.moveCursorDown': () => {
|
'moveCursorDown()': () => {
|
||||||
assertEquals(Ansi.moveCursorDown(7), '\x1b[7B');
|
assertEquals(Ansi.moveCursorDown(7), '\x1b[7B');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'ANSI::readKey()': {
|
|
||||||
'readKey passthrough': () => {
|
|
||||||
// Ignore unhandled escape sequences
|
|
||||||
assertEquals(readKey(encoder.encode('\x1b[]')), '\x1b[]');
|
|
||||||
|
|
||||||
// Pass explicitly mapped values right through
|
|
||||||
assertEquals(
|
|
||||||
readKey(encoder.encode(KeyCommand.ArrowUp)),
|
|
||||||
KeyCommand.ArrowUp,
|
|
||||||
);
|
|
||||||
assertEquals(readKey(encoder.encode(KeyCommand.Home)), KeyCommand.Home);
|
|
||||||
assertEquals(
|
|
||||||
readKey(encoder.encode(KeyCommand.Delete)),
|
|
||||||
KeyCommand.Delete,
|
|
||||||
);
|
|
||||||
|
|
||||||
// And pass through whatever else
|
|
||||||
assertEquals(readKey(encoder.encode('foobaz')), 'foobaz');
|
|
||||||
},
|
|
||||||
'readKey Esc': () =>
|
|
||||||
testKeyMap(['\x1b', Util.ctrlKey('l')], KeyCommand.Escape),
|
|
||||||
'readKey Backspace': () =>
|
|
||||||
testKeyMap(
|
|
||||||
[Util.ctrlKey('h'), '\x7f'],
|
|
||||||
KeyCommand.Backspace,
|
|
||||||
),
|
|
||||||
'readKey Home': () =>
|
|
||||||
testKeyMap(['\x1b[1~', '\x1b[7~', '\x1b[H', '\x1bOH'], KeyCommand.Home),
|
|
||||||
'readKey End': () =>
|
|
||||||
testKeyMap(['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'], KeyCommand.End),
|
|
||||||
'readKey Enter': () => testKeyMap(['\n', '\r', '\v'], KeyCommand.Enter),
|
|
||||||
},
|
|
||||||
Buffer: {
|
Buffer: {
|
||||||
'Buffer exists': () => {
|
'new Buffer': () => {
|
||||||
const b = new Buffer();
|
const b = new Buffer();
|
||||||
assertInstanceOf(b, Buffer);
|
assertInstanceOf(b, Buffer);
|
||||||
assertEquals(b.strlen(), 0);
|
assertEquals(b.strlen(), 0);
|
||||||
},
|
},
|
||||||
'Buffer.appendLine': () => {
|
'.appendLine': () => {
|
||||||
const b = new Buffer();
|
const b = new Buffer();
|
||||||
|
|
||||||
// Carriage return and line feed
|
// Carriage return and line feed
|
||||||
@ -88,7 +56,7 @@ testSuite({
|
|||||||
b.appendLine('foo');
|
b.appendLine('foo');
|
||||||
assertEquals(b.strlen(), 5);
|
assertEquals(b.strlen(), 5);
|
||||||
},
|
},
|
||||||
'Buffer.append': () => {
|
'.append': () => {
|
||||||
const b = new Buffer();
|
const b = new Buffer();
|
||||||
|
|
||||||
b.append('foobar');
|
b.append('foobar');
|
||||||
@ -98,7 +66,7 @@ testSuite({
|
|||||||
b.append('foobar', 3);
|
b.append('foobar', 3);
|
||||||
assertEquals(b.strlen(), 3);
|
assertEquals(b.strlen(), 3);
|
||||||
},
|
},
|
||||||
'Buffer.flush': async () => {
|
'.flush': async () => {
|
||||||
const b = new Buffer();
|
const b = new Buffer();
|
||||||
b.appendLine('foobarbaz' + Ansi.ClearLine);
|
b.appendLine('foobarbaz' + Ansi.ClearLine);
|
||||||
assertEquals(b.strlen(), 14);
|
assertEquals(b.strlen(), 14);
|
||||||
@ -109,20 +77,20 @@ testSuite({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Document: {
|
Document: {
|
||||||
'Document.empty': () => {
|
'.default': () => {
|
||||||
const doc = Document.default();
|
const doc = Document.default();
|
||||||
assertEquals(doc.numRows, 0);
|
assertEquals(doc.numRows, 0);
|
||||||
assertTrue(doc.isEmpty());
|
assertTrue(doc.isEmpty());
|
||||||
assertEquals(doc.row(0), null);
|
assertEquals(doc.row(0), null);
|
||||||
},
|
},
|
||||||
'Document.insertRow': () => {
|
'.insertRow': () => {
|
||||||
const doc = Document.default();
|
const doc = Document.default();
|
||||||
doc.insertRow(undefined, 'foobar');
|
doc.insertRow(undefined, 'foobar');
|
||||||
assertEquals(doc.numRows, 1);
|
assertEquals(doc.numRows, 1);
|
||||||
assertFalse(doc.isEmpty());
|
assertFalse(doc.isEmpty());
|
||||||
assertInstanceOf(doc.row(0), Row);
|
assertInstanceOf(doc.row(0), Row);
|
||||||
},
|
},
|
||||||
'Document.insert': () => {
|
'.insert': () => {
|
||||||
const doc = Document.default();
|
const doc = Document.default();
|
||||||
assertFalse(doc.dirty);
|
assertFalse(doc.dirty);
|
||||||
doc.insert(Position.at(0, 0), 'foobar');
|
doc.insert(Position.at(0, 0), 'foobar');
|
||||||
@ -145,7 +113,7 @@ testSuite({
|
|||||||
assertEquals(doc.numRows, 2);
|
assertEquals(doc.numRows, 2);
|
||||||
assertTrue(doc.dirty);
|
assertTrue(doc.dirty);
|
||||||
},
|
},
|
||||||
'Document.delete': () => {
|
'.delete': () => {
|
||||||
const doc = Document.default();
|
const doc = Document.default();
|
||||||
doc.insert(Position.default(), 'foobar');
|
doc.insert(Position.default(), 'foobar');
|
||||||
doc.delete(Position.at(3, 0));
|
doc.delete(Position.at(3, 0));
|
||||||
@ -159,23 +127,23 @@ testSuite({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Position: {
|
Position: {
|
||||||
'default': () => {
|
'.default': () => {
|
||||||
const p = Position.default();
|
const p = Position.default();
|
||||||
assertEquals(p.x, 0);
|
assertEquals(p.x, 0);
|
||||||
assertEquals(p.y, 0);
|
assertEquals(p.y, 0);
|
||||||
},
|
},
|
||||||
'at': () => {
|
'.at': () => {
|
||||||
const p = Position.at(5, 7);
|
const p = Position.at(5, 7);
|
||||||
assertEquals(p.x, 5);
|
assertEquals(p.x, 5);
|
||||||
assertEquals(p.y, 7);
|
assertEquals(p.y, 7);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Row: {
|
Row: {
|
||||||
'Row.default': () => {
|
'.default': () => {
|
||||||
const row = Row.default();
|
const row = Row.default();
|
||||||
assertEquals(row.toString(), '');
|
assertEquals(row.toString(), '');
|
||||||
},
|
},
|
||||||
'Row.from': () => {
|
'.from': () => {
|
||||||
// From string
|
// From string
|
||||||
const row = Row.from('xyz');
|
const row = Row.from('xyz');
|
||||||
assertEquals(row.toString(), 'xyz');
|
assertEquals(row.toString(), 'xyz');
|
||||||
@ -187,7 +155,7 @@ testSuite({
|
|||||||
assertEquals(Row.from(['😺', '😸', '😹']).toString(), '😺😸😹');
|
assertEquals(Row.from(['😺', '😸', '😹']).toString(), '😺😸😹');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Util misc fns': {
|
'fns': {
|
||||||
'arrayInsert() strings': () => {
|
'arrayInsert() strings': () => {
|
||||||
const a = ['😺', '😸', '😹'];
|
const a = ['😺', '😸', '😹'];
|
||||||
const b = Util.arrayInsert(a, 1, 'x');
|
const b = Util.arrayInsert(a, 1, 'x');
|
||||||
@ -224,8 +192,6 @@ testSuite({
|
|||||||
assertEquals(Util.maxAdd(99, 99, 75), 75);
|
assertEquals(Util.maxAdd(99, 99, 75), 75);
|
||||||
assertEquals(Util.maxAdd(25, 74, 101), 99);
|
assertEquals(Util.maxAdd(25, 74, 101), 99);
|
||||||
},
|
},
|
||||||
},
|
|
||||||
'Util string fns': {
|
|
||||||
'ord()': () => {
|
'ord()': () => {
|
||||||
// Invalid output
|
// Invalid output
|
||||||
assertEquals(Util.ord(''), 256);
|
assertEquals(Util.ord(''), 256);
|
||||||
@ -236,7 +202,7 @@ testSuite({
|
|||||||
'chars() properly splits strings into unicode characters': () => {
|
'chars() properly splits strings into unicode characters': () => {
|
||||||
assertEquals(Util.chars('😺😸😹'), ['😺', '😸', '😹']);
|
assertEquals(Util.chars('😺😸😹'), ['😺', '😸', '😹']);
|
||||||
},
|
},
|
||||||
'ctrl_key()': () => {
|
'ctrlKey()': () => {
|
||||||
const ctrl_a = Util.ctrlKey('a');
|
const ctrl_a = Util.ctrlKey('a');
|
||||||
assertTrue(Util.isControl(ctrl_a));
|
assertTrue(Util.isControl(ctrl_a));
|
||||||
assertEquals(ctrl_a, String.fromCodePoint(0x01));
|
assertEquals(ctrl_a, String.fromCodePoint(0x01));
|
||||||
@ -245,12 +211,12 @@ testSuite({
|
|||||||
assertFalse(Util.isControl(invalid));
|
assertFalse(Util.isControl(invalid));
|
||||||
assertEquals(invalid, '😺');
|
assertEquals(invalid, '😺');
|
||||||
},
|
},
|
||||||
'is_ascii()': () => {
|
'isAscii()': () => {
|
||||||
assertTrue(Util.isAscii('asjyverkjhsdf1928374'));
|
assertTrue(Util.isAscii('asjyverkjhsdf1928374'));
|
||||||
assertFalse(Util.isAscii('😺acalskjsdf'));
|
assertFalse(Util.isAscii('😺acalskjsdf'));
|
||||||
assertFalse(Util.isAscii('ab😺ac'));
|
assertFalse(Util.isAscii('ab😺ac'));
|
||||||
},
|
},
|
||||||
'is_control()': () => {
|
'isControl()': () => {
|
||||||
assertFalse(Util.isControl('abc'));
|
assertFalse(Util.isControl('abc'));
|
||||||
assertTrue(Util.isControl(String.fromCodePoint(0x01)));
|
assertTrue(Util.isControl(String.fromCodePoint(0x01)));
|
||||||
assertFalse(Util.isControl('😺'));
|
assertFalse(Util.isControl('😺'));
|
||||||
@ -277,4 +243,42 @@ testSuite({
|
|||||||
assertEquals(Util.truncate('👨👩👧👦', 5), '👨👩👧');
|
assertEquals(Util.truncate('👨👩👧👦', 5), '👨👩👧');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'readKey()': {
|
||||||
|
'empty input': () => {
|
||||||
|
assertEquals(Util.readKey(new Uint8Array(0)), '');
|
||||||
|
},
|
||||||
|
'passthrough': () => {
|
||||||
|
// Ignore unhandled escape sequences
|
||||||
|
assertEquals(Util.readKey(encoder.encode('\x1b[]')), '\x1b[]');
|
||||||
|
|
||||||
|
// Pass explicitly mapped values right through
|
||||||
|
assertEquals(
|
||||||
|
Util.readKey(encoder.encode(KeyCommand.ArrowUp)),
|
||||||
|
KeyCommand.ArrowUp,
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
Util.readKey(encoder.encode(KeyCommand.Home)),
|
||||||
|
KeyCommand.Home,
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
Util.readKey(encoder.encode(KeyCommand.Delete)),
|
||||||
|
KeyCommand.Delete,
|
||||||
|
);
|
||||||
|
|
||||||
|
// And pass through whatever else
|
||||||
|
assertEquals(Util.readKey(encoder.encode('foobaz')), 'foobaz');
|
||||||
|
},
|
||||||
|
|
||||||
|
'Esc': () => testKeyMap(['\x1b', Util.ctrlKey('l')], KeyCommand.Escape),
|
||||||
|
'Backspace': () =>
|
||||||
|
testKeyMap(
|
||||||
|
[Util.ctrlKey('h'), '\x7f'],
|
||||||
|
KeyCommand.Backspace,
|
||||||
|
),
|
||||||
|
'Home': () =>
|
||||||
|
testKeyMap(['\x1b[1~', '\x1b[7~', '\x1b[H', '\x1bOH'], KeyCommand.Home),
|
||||||
|
'End': () =>
|
||||||
|
testKeyMap(['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'], KeyCommand.End),
|
||||||
|
'Enter': () => testKeyMap(['\n', '\r', '\v'], KeyCommand.Enter),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { strlen, truncate } from './utils.ts';
|
import { strlen, truncate } from './fns.ts';
|
||||||
import { getRuntime } from './runtime.ts';
|
import { getRuntime } from './runtime.ts';
|
||||||
|
|
||||||
class Buffer {
|
class Buffer {
|
||||||
|
13
src/common/config.ts
Normal file
13
src/common/config.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { ITerminalSize } from './types.ts';
|
||||||
|
|
||||||
|
export const SCROLL_VERSION = '0.0.1';
|
||||||
|
export const SCROLL_QUIT_TIMES = 3;
|
||||||
|
export const SCROLL_TAB_SIZE = 4;
|
||||||
|
|
||||||
|
export const SCROLL_LOG_FILE = './scroll.log';
|
||||||
|
export const SCROLL_ERR_FILE = './scroll.err';
|
||||||
|
|
||||||
|
export const defaultTerminalSize: ITerminalSize = {
|
||||||
|
rows: 24,
|
||||||
|
cols: 80,
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
import Row from './row.ts';
|
import Row from './row.ts';
|
||||||
|
import { arrayInsert } from './fns.ts';
|
||||||
import { getRuntime } from './runtime.ts';
|
import { getRuntime } from './runtime.ts';
|
||||||
import { arrayInsert, Position } from './mod.ts';
|
import { Position } from './types.ts';
|
||||||
|
|
||||||
export class Document {
|
export class Document {
|
||||||
#rows: Row[];
|
#rows: Row[];
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
import Ansi, { KeyCommand } from './ansi.ts';
|
import Ansi, { KeyCommand } from './ansi.ts';
|
||||||
import Buffer from './buffer.ts';
|
import Buffer from './buffer.ts';
|
||||||
import Document from './document.ts';
|
import Document from './document.ts';
|
||||||
import {
|
|
||||||
getRuntime,
|
|
||||||
isControl,
|
|
||||||
ITerminalSize,
|
|
||||||
logToFile,
|
|
||||||
Position,
|
|
||||||
readKey,
|
|
||||||
SCROLL_QUIT_TIMES,
|
|
||||||
SCROLL_VERSION,
|
|
||||||
} from './mod.ts';
|
|
||||||
import Row from './row.ts';
|
import Row from './row.ts';
|
||||||
import { ctrlKey, maxAdd, posSub, truncate } from './utils.ts';
|
|
||||||
|
import { SCROLL_QUIT_TIMES, SCROLL_VERSION } from './config.ts';
|
||||||
|
import {
|
||||||
|
ctrlKey,
|
||||||
|
isControl,
|
||||||
|
maxAdd,
|
||||||
|
posSub,
|
||||||
|
readKey,
|
||||||
|
truncate,
|
||||||
|
} from './fns.ts';
|
||||||
|
import { getRuntime, logToFile } from './runtime.ts';
|
||||||
|
import { ITerminalSize, Position } from './types.ts';
|
||||||
|
|
||||||
class Editor {
|
class Editor {
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,66 @@
|
|||||||
|
import { KeyCommand } from './ansi.ts';
|
||||||
|
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Misc
|
// Misc
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An empty function
|
||||||
|
*/
|
||||||
|
export const noop = () => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert input from ANSI escape sequences into a form
|
||||||
|
* that can be more easily mapped to editor commands
|
||||||
|
*
|
||||||
|
* @param raw - the raw chunk of input
|
||||||
|
*/
|
||||||
|
export function readKey(raw: Uint8Array): string {
|
||||||
|
if (raw.length === 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const parsed = decoder.decode(raw);
|
||||||
|
|
||||||
|
// Return the input if it's unambiguous
|
||||||
|
if (parsed in KeyCommand) {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some keycodes have multiple potential inputs
|
||||||
|
switch (parsed) {
|
||||||
|
case '\x1b[1~':
|
||||||
|
case '\x1b[7~':
|
||||||
|
case '\x1bOH':
|
||||||
|
case '\x1b[H':
|
||||||
|
return KeyCommand.Home;
|
||||||
|
|
||||||
|
case '\x1b[4~':
|
||||||
|
case '\x1b[8~':
|
||||||
|
case '\x1bOF':
|
||||||
|
case '\x1b[F':
|
||||||
|
return KeyCommand.End;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
case '\v':
|
||||||
|
return KeyCommand.Enter;
|
||||||
|
|
||||||
|
case ctrlKey('l'):
|
||||||
|
return KeyCommand.Escape;
|
||||||
|
|
||||||
|
case ctrlKey('h'):
|
||||||
|
return KeyCommand.Backspace;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Array manipulation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a value into an array at the specified index
|
* Insert a value into an array at the specified index
|
||||||
* @param arr - the array
|
* @param arr - the array
|
||||||
@ -22,11 +81,6 @@ export function arrayInsert<T>(
|
|||||||
return [...arr.slice(0, at), ...insert, ...arr.slice(at)];
|
return [...arr.slice(0, at), ...insert, ...arr.slice(at)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An empty function
|
|
||||||
*/
|
|
||||||
export const noop = () => {};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Math
|
// Math
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
@ -1,10 +1,11 @@
|
|||||||
import { getRuntime, readKey } from './runtime.ts';
|
import { readKey } from './fns.ts';
|
||||||
|
import { getRuntime, logError } from './runtime.ts';
|
||||||
import { getTermios } from './termios.ts';
|
import { getTermios } from './termios.ts';
|
||||||
import Editor from './editor.ts';
|
import Editor from './editor.ts';
|
||||||
|
|
||||||
export async function main() {
|
export async function main() {
|
||||||
const rt = await getRuntime();
|
const rt = await getRuntime();
|
||||||
const { file, term } = rt;
|
const { term } = rt;
|
||||||
|
|
||||||
// Setup raw mode, and tear down on error or normal exit
|
// Setup raw mode, and tear down on error or normal exit
|
||||||
const t = await getTermios();
|
const t = await getTermios();
|
||||||
@ -17,7 +18,7 @@ export async function main() {
|
|||||||
// Setup error handler to log to file
|
// Setup error handler to log to file
|
||||||
rt.onEvent('error', (error) => {
|
rt.onEvent('error', (error) => {
|
||||||
t.disableRawMode();
|
t.disableRawMode();
|
||||||
file.appendFileSync('./scroll.err', JSON.stringify(error, null, 2));
|
logError(JSON.stringify(error, null, 2));
|
||||||
});
|
});
|
||||||
|
|
||||||
const terminalSize = await term.getTerminalSize();
|
const terminalSize = await term.getTerminalSize();
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
export * from './editor.ts';
|
|
||||||
export * from './runtime.ts';
|
|
||||||
export * from './termios.ts';
|
|
||||||
export * from './types.ts';
|
|
||||||
export * from './utils.ts';
|
|
||||||
|
|
||||||
export type * from './types.ts';
|
|
||||||
|
|
||||||
export const SCROLL_VERSION = '0.0.1';
|
|
||||||
export const SCROLL_QUIT_TIMES = 3;
|
|
||||||
export const SCROLL_TAB_SIZE = 4;
|
|
@ -1,5 +1,5 @@
|
|||||||
import { arrayInsert, chars, SCROLL_TAB_SIZE } from './mod.ts';
|
import { SCROLL_TAB_SIZE } from './config.ts';
|
||||||
import * as Util from './utils.ts';
|
import * as Util from './fns.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One row of text in the current document
|
* One row of text in the current document
|
||||||
@ -46,7 +46,7 @@ export class Row {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public append(s: string): void {
|
public append(s: string): void {
|
||||||
this.chars = this.chars.concat(chars(s));
|
this.chars = this.chars.concat(Util.chars(s));
|
||||||
this.updateRender();
|
this.updateRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ export class Row {
|
|||||||
if (at >= this.size) {
|
if (at >= this.size) {
|
||||||
this.chars = this.chars.concat(newSlice);
|
this.chars = this.chars.concat(newSlice);
|
||||||
} else {
|
} else {
|
||||||
this.chars = arrayInsert(this.chars, at + 1, newSlice);
|
this.chars = Util.arrayInsert(this.chars, at + 1, newSlice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ export class Row {
|
|||||||
' '.repeat(SCROLL_TAB_SIZE),
|
' '.repeat(SCROLL_TAB_SIZE),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.render = chars(newString);
|
this.render = Util.chars(newString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
import { IRuntime, ITestBase } from './types.ts';
|
||||||
import { getTermios } from './termios.ts';
|
import { getTermios } from './termios.ts';
|
||||||
import { ctrlKey, noop } from './utils.ts';
|
import { noop } from './fns.ts';
|
||||||
import { ITestBase } from './types.ts';
|
import { SCROLL_ERR_FILE, SCROLL_LOG_FILE } from './config.ts';
|
||||||
import { KeyCommand } from './ansi.ts';
|
|
||||||
import { IRuntime } from './runtime_types.ts';
|
export type { IFFI, IFileIO, IRuntime, ITerminal } from './types.ts';
|
||||||
export type * from './runtime_types.ts';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Which Typescript runtime is currently being used
|
* Which Typescript runtime is currently being used
|
||||||
@ -14,68 +14,33 @@ export enum RunTimeType {
|
|||||||
Unknown = 'common',
|
Unknown = 'common',
|
||||||
}
|
}
|
||||||
|
|
||||||
const decoder = new TextDecoder();
|
|
||||||
let scrollRuntime: IRuntime | null = null;
|
let scrollRuntime: IRuntime | null = null;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Misc runtime functions
|
// Misc runtime functions
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert input from ANSI escape sequences into a form
|
|
||||||
* that can be more easily mapped to editor commands
|
|
||||||
*
|
|
||||||
* @param raw - the raw chunk of input
|
|
||||||
*/
|
|
||||||
export function readKey(raw: Uint8Array): string {
|
|
||||||
if (raw.length === 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
const parsed = decoder.decode(raw);
|
|
||||||
|
|
||||||
// Return the input if it's unambiguous
|
|
||||||
if (parsed in KeyCommand) {
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some keycodes have multiple potential inputs
|
|
||||||
switch (parsed) {
|
|
||||||
case '\x1b[1~':
|
|
||||||
case '\x1b[7~':
|
|
||||||
case '\x1bOH':
|
|
||||||
case '\x1b[H':
|
|
||||||
return KeyCommand.Home;
|
|
||||||
|
|
||||||
case '\x1b[4~':
|
|
||||||
case '\x1b[8~':
|
|
||||||
case '\x1bOF':
|
|
||||||
case '\x1b[F':
|
|
||||||
return KeyCommand.End;
|
|
||||||
|
|
||||||
case '\n':
|
|
||||||
case '\v':
|
|
||||||
return KeyCommand.Enter;
|
|
||||||
|
|
||||||
case ctrlKey('l'):
|
|
||||||
return KeyCommand.Escape;
|
|
||||||
|
|
||||||
case ctrlKey('h'):
|
|
||||||
return KeyCommand.Backspace;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append information to the scroll.log logfile
|
* Append information to the scroll.log logfile
|
||||||
*/
|
*/
|
||||||
export function logToFile(s: unknown) {
|
export function logToFile(s: unknown): void {
|
||||||
importForRuntime('file_io').then((f) => {
|
getRuntime().then(({ file }) => {
|
||||||
const raw = typeof s === 'string' ? s : JSON.stringify(s, null, 2);
|
const raw = typeof s === 'string' ? s : JSON.stringify(s, null, 2);
|
||||||
const output = raw + '\n';
|
const output = raw + '\n';
|
||||||
|
|
||||||
f.appendFile('./scroll.log', output).then(noop);
|
file.appendFile(SCROLL_LOG_FILE, output).then(noop);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append information to the scroll.err logfile
|
||||||
|
*/
|
||||||
|
export function logError(s: unknown): void {
|
||||||
|
getRuntime().then(({ file }) => {
|
||||||
|
const raw = typeof s === 'string' ? s : JSON.stringify(s, null, 2);
|
||||||
|
const output = raw + '\n';
|
||||||
|
|
||||||
|
file.appendFile(SCROLL_ERR_FILE, output).then(noop);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,11 +49,11 @@ export function logToFile(s: unknown) {
|
|||||||
* @param s
|
* @param s
|
||||||
*/
|
*/
|
||||||
export function die(s: string | Error): void {
|
export function die(s: string | Error): void {
|
||||||
|
logError(s);
|
||||||
getTermios().then((t) => {
|
getTermios().then((t) => {
|
||||||
t.disableRawMode();
|
t.disableRawMode();
|
||||||
t.cleanup();
|
t.cleanup();
|
||||||
console.error(s);
|
console.error(s);
|
||||||
|
|
||||||
getRuntime().then((r) => r.exit());
|
getRuntime().then((r) => r.exit());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
import { RunTimeType } from './runtime.ts';
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Runtime adapter interfaces
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The size of terminal in rows and columns
|
|
||||||
*/
|
|
||||||
export interface ITerminalSize {
|
|
||||||
rows: number;
|
|
||||||
cols: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The native functions for getting/setting terminal settings
|
|
||||||
*/
|
|
||||||
export interface IFFI {
|
|
||||||
/**
|
|
||||||
* Get the existing termios settings (for canonical mode)
|
|
||||||
*/
|
|
||||||
tcgetattr(fd: number, termiosPtr: unknown): number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the termios settings
|
|
||||||
*/
|
|
||||||
tcsetattr(fd: number, act: number, termiosPtr: unknown): number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the termios pointer with raw mode settings
|
|
||||||
*/
|
|
||||||
cfmakeraw(termiosPtr: unknown): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a TypedArray to an opaque pointer for ffi calls
|
|
||||||
*/
|
|
||||||
// deno-lint-ignore no-explicit-any
|
|
||||||
getPointer(ta: any): unknown;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the FFI handle
|
|
||||||
*/
|
|
||||||
close(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The common interface for runtime adapters
|
|
||||||
*/
|
|
||||||
export interface IRuntime {
|
|
||||||
/**
|
|
||||||
* The name of the runtime
|
|
||||||
*/
|
|
||||||
name: RunTimeType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime-specific terminal functionality
|
|
||||||
*/
|
|
||||||
term: {
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
file: {
|
|
||||||
openFile(path: string): Promise<string>;
|
|
||||||
openFileSync(path: string): string;
|
|
||||||
appendFile(path: string, contents: string): Promise<void>;
|
|
||||||
appendFileSync(path: string, contents: string): void;
|
|
||||||
saveFile(path: string, contents: string): Promise<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime-specific terminal functionality
|
|
||||||
*/
|
|
||||||
export type ITerminal = IRuntime['term'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime-specific file handling
|
|
||||||
*/
|
|
||||||
export type IFileIO = IRuntime['file'];
|
|
@ -1,15 +1,10 @@
|
|||||||
import { die, IFFI, importForRuntime, ITerminalSize } from './mod.ts';
|
import { die, IFFI, importForRuntime } from './runtime.ts';
|
||||||
|
|
||||||
export const STDIN_FILENO = 0;
|
export const STDIN_FILENO = 0;
|
||||||
export const TCSANOW = 0;
|
export const TCSANOW = 0;
|
||||||
|
|
||||||
export const TERMIOS_SIZE = 60;
|
export const TERMIOS_SIZE = 60;
|
||||||
|
|
||||||
export const defaultTerminalSize: ITerminalSize = {
|
|
||||||
rows: 24,
|
|
||||||
cols: 80,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation to toggle raw mode
|
* Implementation to toggle raw mode
|
||||||
*/
|
*/
|
||||||
|
@ -1,3 +1,136 @@
|
|||||||
|
import { RunTimeType } from './runtime.ts';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Runtime adapter interfaces
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of terminal in rows and columns
|
||||||
|
*/
|
||||||
|
export interface ITerminalSize {
|
||||||
|
rows: number;
|
||||||
|
cols: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The native functions for getting/setting terminal settings
|
||||||
|
*/
|
||||||
|
export interface IFFI {
|
||||||
|
/**
|
||||||
|
* Get the existing termios settings (for canonical mode)
|
||||||
|
*/
|
||||||
|
tcgetattr(fd: number, termiosPtr: unknown): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the termios settings
|
||||||
|
*/
|
||||||
|
tcsetattr(fd: number, act: number, termiosPtr: unknown): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the termios pointer with raw mode settings
|
||||||
|
*/
|
||||||
|
cfmakeraw(termiosPtr: unknown): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a TypedArray to an opaque pointer for ffi calls
|
||||||
|
*/
|
||||||
|
// deno-lint-ignore no-explicit-any
|
||||||
|
getPointer(ta: any): unknown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the FFI handle
|
||||||
|
*/
|
||||||
|
close(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The common interface for runtime adapters
|
||||||
|
*/
|
||||||
|
export interface IRuntime {
|
||||||
|
/**
|
||||||
|
* The name of the runtime
|
||||||
|
*/
|
||||||
|
name: RunTimeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime-specific terminal functionality
|
||||||
|
*/
|
||||||
|
term: {
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
file: {
|
||||||
|
openFile(path: string): Promise<string>;
|
||||||
|
appendFile(path: string, contents: string): Promise<void>;
|
||||||
|
saveFile(path: string, contents: string): Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime-specific terminal functionality
|
||||||
|
*/
|
||||||
|
export type ITerminal = IRuntime['term'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime-specific file handling
|
||||||
|
*/
|
||||||
|
export type IFileIO = IRuntime['file'];
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// General types
|
// General types
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -6,11 +6,6 @@ const DenoFileIO: IFileIO = {
|
|||||||
const data = await Deno.readFile(path);
|
const data = await Deno.readFile(path);
|
||||||
return decoder.decode(data);
|
return decoder.decode(data);
|
||||||
},
|
},
|
||||||
openFileSync: function (path: string): string {
|
|
||||||
const decoder = new TextDecoder('utf-8');
|
|
||||||
const data = Deno.readFileSync(path);
|
|
||||||
return decoder.decode(data);
|
|
||||||
},
|
|
||||||
appendFile: async function (path: string, contents: string): Promise<void> {
|
appendFile: async function (path: string, contents: string): Promise<void> {
|
||||||
const file = await Deno.open(path, {
|
const file = await Deno.open(path, {
|
||||||
write: true,
|
write: true,
|
||||||
@ -23,10 +18,6 @@ const DenoFileIO: IFileIO = {
|
|||||||
await writer.write(encoder.encode(contents));
|
await writer.write(encoder.encode(contents));
|
||||||
file.close();
|
file.close();
|
||||||
},
|
},
|
||||||
appendFileSync: function (path: string, contents: string) {
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
Deno.writeFileSync(path, encoder.encode(contents));
|
|
||||||
},
|
|
||||||
saveFile: async function (path: string, contents: string): Promise<void> {
|
saveFile: async function (path: string, contents: string): Promise<void> {
|
||||||
return await Deno.writeTextFile(path, contents);
|
return await Deno.writeTextFile(path, contents);
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* The main entrypoint when using Deno as the runtime
|
* The main entrypoint when using Deno as the runtime
|
||||||
*/
|
*/
|
||||||
import { IRuntime, RunTimeType } from '../common/mod.ts';
|
import { IRuntime, RunTimeType } from '../common/runtime.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';
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { ITerminal, ITerminalSize, readKey } from '../common/runtime.ts';
|
import { readKey } from '../common/fns.ts';
|
||||||
|
import { ITerminal, ITerminalSize } from '../common/types.ts';
|
||||||
|
|
||||||
const DenoTerminalIO: ITerminal = {
|
const DenoTerminalIO: ITerminal = {
|
||||||
argv: Deno.args,
|
argv: Deno.args,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ITestBase } from '../common/mod.ts';
|
import { ITestBase } from '../common/types.ts';
|
||||||
import { stdAssert } from './deps.ts';
|
import { stdAssert } from './deps.ts';
|
||||||
const {
|
const {
|
||||||
assertEquals,
|
assertEquals,
|
||||||
|
Loading…
Reference in New Issue
Block a user