Preparing for file reading/writing

This commit is contained in:
Timothy Warren 2023-11-13 15:33:56 -05:00
parent 4296930dae
commit 816295ff9c
15 changed files with 115 additions and 62 deletions

15
src/bun/file_io.ts Normal file
View 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;

View File

@ -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);

View File

@ -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
View 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;

View File

@ -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);

View File

@ -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();
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------

View File

@ -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;

View File

@ -1 +0,0 @@
export * from './editor.ts';

View File

@ -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';

View File

@ -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
View 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;

View File

@ -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;

View File

@ -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;

View File

@ -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);