feat: working-ish shell and terminal

This commit is contained in:
2026-03-26 13:57:58 +01:00
parent 1d54c8b650
commit ed15d94255
4 changed files with 79 additions and 17 deletions

View File

@@ -6,6 +6,9 @@ import type { EventBroadcaster } from '../utils/EventBroadcaster'
import { Shell } from './Shell' import { Shell } from './Shell'
export class Wush extends Shell { export class Wush extends Shell {
private buffer: string[] = []
private bufferPos: number = 0
constructor(broadcaster: EventBroadcaster, terminal: Terminal) { constructor(broadcaster: EventBroadcaster, terminal: Terminal) {
super(broadcaster, terminal) super(broadcaster, terminal)
} }
@@ -21,20 +24,63 @@ export class Wush extends Shell {
this.terminal.Write('hi -> ') this.terminal.Write('hi -> ')
} }
PushToBuffer(text: string) {
text.split('').forEach(char => {
this.buffer.splice(this.bufferPos, 0, char)
this.bufferPos++
})
console.log(this.buffer)
}
RemoveLastCharsFromBuffer(amount: number) {
this.buffer.splice(this.buffer.length - amount, amount)
this.bufferPos -= amount
console.log(this.buffer)
}
MoveBufferPos(index: number, absolute: boolean = false) {
this.bufferPos = Math.max(absolute ? index : this.bufferPos + index, 0)
}
FlushBuffer() {
this.buffer = []
this.bufferPos = 0
}
ExecuteBuffer() {
const args = this.buffer.join('').split(' ')
this.FlushBuffer()
console.log(`Executing ${args[0]} with args '${args}'`)
}
HandleKeyInput(key: string, isCharacter: boolean) { HandleKeyInput(key: string, isCharacter: boolean) {
if (!isCharacter) if (!isCharacter) {
switch (key) { switch (key) {
case 'ArrowLeft':
this.terminal.MoveCursor(-1, 0)
this.MoveBufferPos(-1)
break
case 'ArrowRight':
this.terminal.MoveCursor(1, 0)
this.MoveBufferPos(1)
break
case 'Backspace': case 'Backspace':
this.terminal.RemoveCell() this.terminal.RemoveCell()
this.RemoveLastCharsFromBuffer(1)
this.terminal.MoveCursor(-1, 0) this.terminal.MoveCursor(-1, 0)
break break
case 'Enter': case 'Enter':
this.terminal.MoveCursor(0, 4, { x: true, y: false }) this.terminal.MoveCursor(0, 1, { x: true, y: false })
this.ExecuteBuffer()
this.Prompt() this.Prompt()
break break
} }
else { } else {
this.terminal.Write(key) this.terminal.InsertCell(key)
this.PushToBuffer(key)
this.terminal.MoveCursor(1, 0) this.terminal.MoveCursor(1, 0)
} }
} }

View File

@@ -7,4 +7,6 @@
height: 20px; height: 20px;
position: absolute; position: absolute;
background: colors.$terminal-white; background: colors.$terminal-white;
transition: .2s cubic-bezier(0, 1, 0.3, 1);
} }

View File

@@ -24,7 +24,6 @@
} }
.line { .line {
background: red;
width: fit-content width: fit-content
} }
} }

View File

@@ -19,9 +19,9 @@ export class Terminal {
this.terminal = sqs('#terminal') this.terminal = sqs('#terminal')
this.cursor = sqs('#cursor') this.cursor = sqs('#cursor')
this.SetCursorStyle('bar')
this.ResetCellSize() this.ResetCellSize()
this.SetCursorStyle('bar')
this.NewPage() this.NewPage()
} }
@@ -43,6 +43,12 @@ export class Terminal {
paragraph.className = 'line' paragraph.className = 'line'
this.terminal.appendChild(paragraph) this.terminal.appendChild(paragraph)
paragraph.scrollIntoView({behavior: 'smooth'})
}
UpdateLines() {
const lines = new Array(...this.terminal.children)
lines.forEach((line, i) => line.id = `line-${i}`)
} }
/** /**
@@ -53,13 +59,10 @@ export class Terminal {
} }
Write(text: string) { Write(text: string) {
let adjustment = 0
text.split('').forEach((char) => { text.split('').forEach((char) => {
this.MoveCursor(adjustment, 0)
adjustment = 1
this.SetCell(char) this.SetCell(char)
this.MoveCursor(1, 0)
}) })
} }
@@ -92,13 +95,23 @@ export class Terminal {
sqs(selector).innerText = char[0] sqs(selector).innerText = char[0]
} }
AppendCells(content: string) { UpdateCells() {
const paragraph = sqs(`#line-${this.cursorPosition.row}`) const cells = new Array(...sqs(`#line-${this.cursorPosition.row}`).children)
cells.forEach((cell, i) => cell.className = `cell-${i}`)
}
content.split('').forEach((char) => { InsertCell(char: string) {
paragraph.textContent += char.replace(' ', '\u00A0') const cell = document.createElement('span')
this.MoveCursor(1, 0) cell.className = `cell-${this.cursorPosition.col}`
}) cell.style.width = `${this.cellWidth}px`
cell.style.height = `${this.cellHeight}px`
cell.style.lineHeight = `${this.cellHeight}px`
cell.innerText = char[0]
sqs(`#line-${this.cursorPosition.row} .cell-${this.cursorPosition.col}`).insertAdjacentElement('beforebegin', cell)
this.UpdateCells()
} }
RemoveCell() { RemoveCell() {
@@ -106,6 +119,8 @@ export class Terminal {
sqs(`#line-${this.cursorPosition.row} .cell-${this.cursorPosition.col - 1}`).remove() sqs(`#line-${this.cursorPosition.row} .cell-${this.cursorPosition.col - 1}`).remove()
} catch (_) { } catch (_) {
} finally {
this.UpdateCells()
} }
} }