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 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);
|
||||
|
@ -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
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 {
|
||||
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);
|
@ -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();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
@ -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 './termios.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
|
||||
*/
|
||||
@ -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
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 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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user