Preparing for file reading/writing
This commit is contained in:
parent
4296930dae
commit
816295ff9c
15
src/bun/file_io.ts
Normal file
15
src/bun/file_io.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { IFIO } from '../common/types.ts';
|
||||||
|
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
|
||||||
|
const BunFileIO: IFIO = {
|
||||||
|
openFile: async (path: string): Promise<string> => {
|
||||||
|
const file = await Bun.file(path);
|
||||||
|
return await file.text();
|
||||||
|
},
|
||||||
|
openFileSync: (path: string): string => {
|
||||||
|
return readFileSync(path);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BunFileIO;
|
@ -5,6 +5,7 @@
|
|||||||
import { getTermios, IRuntime, RunTimeType } from '../common/mod.ts';
|
import { getTermios, IRuntime, RunTimeType } from '../common/mod.ts';
|
||||||
import BunFFI from './ffi.ts';
|
import BunFFI from './ffi.ts';
|
||||||
import BunTerminalIO from './terminal_io.ts';
|
import BunTerminalIO from './terminal_io.ts';
|
||||||
|
import BunFileIO from './file_io.ts';
|
||||||
|
|
||||||
process.on('error', async (e) => {
|
process.on('error', async (e) => {
|
||||||
(await getTermios()).disableRawMode();
|
(await getTermios()).disableRawMode();
|
||||||
@ -14,8 +15,9 @@ process.on('error', async (e) => {
|
|||||||
|
|
||||||
const BunRuntime: IRuntime = {
|
const BunRuntime: IRuntime = {
|
||||||
name: RunTimeType.Bun,
|
name: RunTimeType.Bun,
|
||||||
|
file: BunFileIO,
|
||||||
ffi: BunFFI,
|
ffi: BunFFI,
|
||||||
io: BunTerminalIO,
|
term: BunTerminalIO,
|
||||||
onExit: (cb: () => void): void => {
|
onExit: (cb: () => void): void => {
|
||||||
process.on('beforeExit', cb);
|
process.on('beforeExit', cb);
|
||||||
process.on('exit', cb);
|
process.on('exit', cb);
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* Wrap the runtime-specific hook into stdin
|
* Wrap the runtime-specific hook into stdin
|
||||||
*/
|
*/
|
||||||
import { ITerminalIO, ITerminalSize } from '../common/mod.ts';
|
import { ITerminal, ITerminalSize } from '../common/mod.ts';
|
||||||
import Ansi from '../common/editor/ansi.ts';
|
import Ansi from '../common/ansi.ts';
|
||||||
|
|
||||||
const BunTerminalIO: ITerminalIO = {
|
const BunTerminalIO: ITerminal = {
|
||||||
|
argv: Bun.argv,
|
||||||
inputLoop: async function* inputLoop() {
|
inputLoop: async function* inputLoop() {
|
||||||
for await (const chunk of Bun.stdin.stream()) {
|
for await (const chunk of Bun.stdin.stream()) {
|
||||||
yield chunk;
|
yield chunk;
|
||||||
@ -45,7 +46,7 @@ const BunTerminalIO: ITerminalIO = {
|
|||||||
cols: 80,
|
cols: 80,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
write: async function write(s: string): Promise<void> {
|
writeStdout: async function write(s: string): Promise<void> {
|
||||||
const buffer = new TextEncoder().encode(s);
|
const buffer = new TextEncoder().encode(s);
|
||||||
|
|
||||||
await Bun.write(Bun.stdout, buffer);
|
await Bun.write(Bun.stdout, buffer);
|
||||||
|
36
src/common/buffer.ts
Normal file
36
src/common/buffer.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { strlen } from './utils.ts';
|
||||||
|
import { getRuntime } from './runtime.ts';
|
||||||
|
|
||||||
|
class Buffer {
|
||||||
|
#b = '';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public append(s: string): void {
|
||||||
|
this.#b += s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public appendLine(s: string): void {
|
||||||
|
this.#b += s + '\r\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.#b = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output the contents of the buffer into stdout
|
||||||
|
*/
|
||||||
|
public async flush() {
|
||||||
|
const { term } = await getRuntime();
|
||||||
|
await term.writeStdout(this.#b);
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public strlen(): number {
|
||||||
|
return strlen(this.#b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Buffer;
|
@ -1,4 +1,4 @@
|
|||||||
import { chars } from '../utils.ts';
|
import { chars } from './utils.ts';
|
||||||
|
|
||||||
export class Row {
|
export class Row {
|
||||||
chars: string[] = [];
|
chars: string[] = [];
|
||||||
@ -27,7 +27,7 @@ export class Document {
|
|||||||
return new Document();
|
return new Document();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static open(): Document {
|
public static open(_filename: string): Document {
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
const line = 'Hello, World!';
|
const line = 'Hello, World!';
|
||||||
const row = new Row(line);
|
const row = new Row(line);
|
@ -1,21 +1,23 @@
|
|||||||
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 { ctrl_key, IPoint, ITerminalSize, truncate, VERSION } from '../mod.ts';
|
import { ctrl_key, IPoint, ITerminalSize, truncate, VERSION } from './mod.ts';
|
||||||
|
|
||||||
export class Editor {
|
export class Editor {
|
||||||
#buffer: Buffer;
|
#buffer: Buffer;
|
||||||
#screen: ITerminalSize;
|
#screen: ITerminalSize;
|
||||||
#cursor: IPoint;
|
#cursor: IPoint;
|
||||||
#document: Document;
|
#document: Document;
|
||||||
constructor(terminalSize: ITerminalSize) {
|
constructor(terminalSize: ITerminalSize, args: string[]) {
|
||||||
this.#buffer = new Buffer();
|
this.#buffer = new Buffer();
|
||||||
this.#screen = terminalSize;
|
this.#screen = terminalSize;
|
||||||
this.#cursor = {
|
this.#cursor = {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
};
|
};
|
||||||
this.#document = Document.open();
|
this.#document = (args.length >= 2)
|
||||||
|
? Document.open(args[1])
|
||||||
|
: Document.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
@ -1,37 +0,0 @@
|
|||||||
import { strlen } from '../utils.ts';
|
|
||||||
import { getRuntime } from '../runtime.ts';
|
|
||||||
|
|
||||||
class Buffer {
|
|
||||||
#b = '';
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
}
|
|
||||||
|
|
||||||
append(s: string): void {
|
|
||||||
this.#b += s;
|
|
||||||
}
|
|
||||||
|
|
||||||
appendLine(s: string): void {
|
|
||||||
this.#b += s + '\r\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
clear(): void {
|
|
||||||
this.#b = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
getBuffer(): string {
|
|
||||||
return this.#b;
|
|
||||||
}
|
|
||||||
|
|
||||||
async flush() {
|
|
||||||
const { io } = await getRuntime();
|
|
||||||
await io.write(this.#b);
|
|
||||||
this.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
strlen(): number {
|
|
||||||
return strlen(this.#b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Buffer;
|
|
@ -1 +0,0 @@
|
|||||||
export * from './editor.ts';
|
|
@ -1,4 +1,4 @@
|
|||||||
export * from './editor/mod.ts';
|
export * from './editor.ts';
|
||||||
export * from './runtime.ts';
|
export * from './runtime.ts';
|
||||||
export * from './termios.ts';
|
export * from './termios.ts';
|
||||||
export * from './utils.ts';
|
export * from './utils.ts';
|
||||||
|
@ -47,9 +47,13 @@ export interface ITerminalSize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runtime-specific IO streams
|
* Runtime-specific terminal functionality
|
||||||
*/
|
*/
|
||||||
export interface ITerminalIO {
|
export interface ITerminal {
|
||||||
|
/**
|
||||||
|
* The arguments passed to the program on launch
|
||||||
|
*/
|
||||||
|
argv: string[];
|
||||||
/**
|
/**
|
||||||
* The generator function returning chunks of input from the stdin stream
|
* The generator function returning chunks of input from the stdin stream
|
||||||
*/
|
*/
|
||||||
@ -63,7 +67,15 @@ export interface ITerminalIO {
|
|||||||
/**
|
/**
|
||||||
* Pipe a string to stdout
|
* Pipe a string to stdout
|
||||||
*/
|
*/
|
||||||
write(s: string): Promise<void>;
|
writeStdout(s: string): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime-specific file handling
|
||||||
|
*/
|
||||||
|
export interface IFIO {
|
||||||
|
openFile(path: string): Promise<string>;
|
||||||
|
openFileSync(path: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRuntime {
|
export interface IRuntime {
|
||||||
@ -78,7 +90,11 @@ export interface IRuntime {
|
|||||||
/**
|
/**
|
||||||
* Runtime-specific terminal functionality
|
* Runtime-specific terminal functionality
|
||||||
*/
|
*/
|
||||||
io: ITerminalIO;
|
term: ITerminal;
|
||||||
|
/**
|
||||||
|
* Runtime-specific file system io
|
||||||
|
*/
|
||||||
|
file: IFIO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a beforeExit/beforeUnload event handler for the runtime
|
* Set a beforeExit/beforeUnload event handler for the runtime
|
||||||
|
16
src/deno/file_io.ts
Normal file
16
src/deno/file_io.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { IFIO } from '../common/types.ts';
|
||||||
|
|
||||||
|
const DenoFileIO: IFIO = {
|
||||||
|
openFile: async function (path: string): Promise<string> {
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
const data = await Deno.readFile(path);
|
||||||
|
return decoder.decode(data);
|
||||||
|
},
|
||||||
|
openFileSync: function (path: string): string {
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
const data = Deno.readFileSync(path);
|
||||||
|
return decoder.decode(data);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DenoFileIO;
|
@ -4,11 +4,13 @@
|
|||||||
import { IRuntime, RunTimeType } from '../common/mod.ts';
|
import { IRuntime, RunTimeType } from '../common/mod.ts';
|
||||||
import DenoFFI from './ffi.ts';
|
import DenoFFI from './ffi.ts';
|
||||||
import DenoTerminalIO from './terminal_io.ts';
|
import DenoTerminalIO from './terminal_io.ts';
|
||||||
|
import DenoFileIO from './file_io.ts';
|
||||||
|
|
||||||
const DenoRuntime: IRuntime = {
|
const DenoRuntime: IRuntime = {
|
||||||
name: RunTimeType.Deno,
|
name: RunTimeType.Deno,
|
||||||
|
file: DenoFileIO,
|
||||||
ffi: DenoFFI,
|
ffi: DenoFFI,
|
||||||
io: DenoTerminalIO,
|
term: DenoTerminalIO,
|
||||||
onExit: (cb: () => void): void => {
|
onExit: (cb: () => void): void => {
|
||||||
globalThis.addEventListener('onbeforeunload', cb);
|
globalThis.addEventListener('onbeforeunload', cb);
|
||||||
globalThis.onbeforeunload = cb;
|
globalThis.onbeforeunload = cb;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { ITerminalIO, ITerminalSize } from '../common/types.ts';
|
import { ITerminal, ITerminalSize } from '../common/types.ts';
|
||||||
|
|
||||||
const DenoTerminalIO: ITerminalIO = {
|
const DenoTerminalIO: ITerminal = {
|
||||||
|
argv: Deno.args,
|
||||||
/**
|
/**
|
||||||
* Wrap the runtime-specific hook into stdin
|
* Wrap the runtime-specific hook into stdin
|
||||||
*/
|
*/
|
||||||
@ -17,7 +18,7 @@ const DenoTerminalIO: ITerminalIO = {
|
|||||||
cols: size.columns,
|
cols: size.columns,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
write: async function write(s: string): Promise<void> {
|
writeStdout: async function write(s: string): Promise<void> {
|
||||||
const buffer: Uint8Array = new TextEncoder().encode(s);
|
const buffer: Uint8Array = new TextEncoder().encode(s);
|
||||||
const stdout: WritableStream<Uint8Array> = Deno.stdout.writable;
|
const stdout: WritableStream<Uint8Array> = Deno.stdout.writable;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* The starting point for running scroll
|
* The starting point for running scroll
|
||||||
*/
|
*/
|
||||||
import { Editor, getRuntime, getTermios } from './common/mod.ts';
|
import { Editor, getRuntime, getTermios } from './common/mod.ts';
|
||||||
import { KeyCommand } from './common/editor/ansi.ts';
|
import { KeyCommand } from './common/ansi.ts';
|
||||||
|
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ function readKey(raw: Uint8Array): string {
|
|||||||
|
|
||||||
export async function main() {
|
export async function main() {
|
||||||
const runTime = await getRuntime();
|
const runTime = await getRuntime();
|
||||||
const { io, onExit } = runTime;
|
const { term, onExit } = runTime;
|
||||||
|
|
||||||
// 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();
|
||||||
@ -44,14 +44,14 @@ export async function main() {
|
|||||||
t.disableRawMode();
|
t.disableRawMode();
|
||||||
});
|
});
|
||||||
|
|
||||||
const terminalSize = await io.getTerminalSize();
|
const terminalSize = await term.getTerminalSize();
|
||||||
|
|
||||||
// Create the editor itself
|
// Create the editor itself
|
||||||
const editor = new Editor(terminalSize);
|
const editor = new Editor(terminalSize, term.argv);
|
||||||
await editor.refreshScreen();
|
await editor.refreshScreen();
|
||||||
|
|
||||||
// The main event loop
|
// The main event loop
|
||||||
for await (const chunk of io.inputLoop()) {
|
for await (const chunk of term.inputLoop()) {
|
||||||
// Process input
|
// Process input
|
||||||
const char = readKey(chunk);
|
const char = readKey(chunk);
|
||||||
const shouldLoop = editor.processKeyPress(char);
|
const shouldLoop = editor.processKeyPress(char);
|
||||||
|
Loading…
Reference in New Issue
Block a user