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 BunFFI from './ffi.ts';
import BunTerminalIO from './terminal_io.ts';
import BunFileIO from './file_io.ts';
process.on('error', async (e) => {
(await getTermios()).disableRawMode();
@ -14,8 +15,9 @@ process.on('error', async (e) => {
const BunRuntime: IRuntime = {
name: RunTimeType.Bun,
file: BunFileIO,
ffi: BunFFI,
io: BunTerminalIO,
term: BunTerminalIO,
onExit: (cb: () => void): void => {
process.on('beforeExit', cb);
process.on('exit', cb);

View File

@ -1,10 +1,11 @@
/**
* Wrap the runtime-specific hook into stdin
*/
import { ITerminalIO, ITerminalSize } from '../common/mod.ts';
import Ansi from '../common/editor/ansi.ts';
import { ITerminal, ITerminalSize } from '../common/mod.ts';
import Ansi from '../common/ansi.ts';
const BunTerminalIO: ITerminalIO = {
const BunTerminalIO: ITerminal = {
argv: Bun.argv,
inputLoop: async function* inputLoop() {
for await (const chunk of Bun.stdin.stream()) {
yield chunk;
@ -45,7 +46,7 @@ const BunTerminalIO: ITerminalIO = {
cols: 80,
};
},
write: async function write(s: string): Promise<void> {
writeStdout: async function write(s: string): Promise<void> {
const buffer = new TextEncoder().encode(s);
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 {
chars: string[] = [];
@ -27,7 +27,7 @@ export class Document {
return new Document();
}
public static open(): Document {
public static open(_filename: string): Document {
const doc = new Document();
const line = 'Hello, World!';
const row = new Row(line);

View File

@ -1,21 +1,23 @@
import Ansi, { KeyCommand } from './ansi.ts';
import Buffer from './buffer.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 {
#buffer: Buffer;
#screen: ITerminalSize;
#cursor: IPoint;
#document: Document;
constructor(terminalSize: ITerminalSize) {
constructor(terminalSize: ITerminalSize, args: string[]) {
this.#buffer = new Buffer();
this.#screen = terminalSize;
this.#cursor = {
x: 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 './termios.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
*/
@ -63,7 +67,15 @@ export interface ITerminalIO {
/**
* 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 {
@ -78,7 +90,11 @@ export interface IRuntime {
/**
* Runtime-specific terminal functionality
*/
io: ITerminalIO;
term: ITerminal;
/**
* Runtime-specific file system io
*/
file: IFIO;
/**
* 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 DenoFFI from './ffi.ts';
import DenoTerminalIO from './terminal_io.ts';
import DenoFileIO from './file_io.ts';
const DenoRuntime: IRuntime = {
name: RunTimeType.Deno,
file: DenoFileIO,
ffi: DenoFFI,
io: DenoTerminalIO,
term: DenoTerminalIO,
onExit: (cb: () => void): void => {
globalThis.addEventListener('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
*/
@ -17,7 +18,7 @@ const DenoTerminalIO: ITerminalIO = {
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 stdout: WritableStream<Uint8Array> = Deno.stdout.writable;

View File

@ -2,7 +2,7 @@
* The starting point for running scroll
*/
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();
@ -35,7 +35,7 @@ function readKey(raw: Uint8Array): string {
export async function main() {
const runTime = await getRuntime();
const { io, onExit } = runTime;
const { term, onExit } = runTime;
// Setup raw mode, and tear down on error or normal exit
const t = await getTermios();
@ -44,14 +44,14 @@ export async function main() {
t.disableRawMode();
});
const terminalSize = await io.getTerminalSize();
const terminalSize = await term.getTerminalSize();
// Create the editor itself
const editor = new Editor(terminalSize);
const editor = new Editor(terminalSize, term.argv);
await editor.refreshScreen();
// The main event loop
for await (const chunk of io.inputLoop()) {
for await (const chunk of term.inputLoop()) {
// Process input
const char = readKey(chunk);
const shouldLoop = editor.processKeyPress(char);