Add various things to the demo

box-drawing
cpsdqs 7 years ago
parent 276d3af7da
commit d2dc99b6ff
Signed by untrusted user: cpsdqs
GPG Key ID: 3F59586BB7448DD1
  1. 172
      js/term/demo.js

@ -143,7 +143,7 @@ class ScrollingTerminal {
this.cursor = { x: 0, y: 0, style: 1, visible: true } this.cursor = { x: 0, y: 0, style: 1, visible: true }
this.trackMouse = false this.trackMouse = false
this.theme = 0 this.theme = 0
this.rainbow = false this.rainbow = this.superRainbow = false
this.parser.reset() this.parser.reset()
this.clear() this.clear()
} }
@ -291,6 +291,9 @@ class ScrollingTerminal {
data += this.buttonLabels.map(x => x + '\x01').join('') data += this.buttonLabels.map(x => x + '\x01').join('')
return data return data
} }
getTitle () {
return 'TESPTerm Web UI Demo\x01'
}
getCursor () { getCursor () {
let data = 'C' let data = 'C'
data += encodeAsCodePoint(this.cursor.y) data += encodeAsCodePoint(this.cursor.y)
@ -319,10 +322,15 @@ class ScrollingTerminal {
let x = index % this.width let x = index % this.width
let y = Math.floor(index / this.width) let y = Math.floor(index / this.width)
// C instead of F in mask and 1 << 8 in attrs to change attr bits 1 and 2 // C instead of F in mask and 1 << 8 in attrs to change attr bits 1 and 2
style[0] = getRainbowColor((x + y) / 10 + Date.now() / 1000) let t = (x + y) / 10 + Date.now() / 1000
if (this.superRainbow) {
t = (x * y + Date.now()) / 100 + Date.now() / 1000
}
style[0] = getRainbowColor(t)
style[1] = 0 style[1] = 0
if (this.superRainbow) style[1] = getRainbowColor(t / 10)
style[2] = style[2] | 1 style[2] = style[2] | 1
if (style[2] & (1 << 1)) style[2] ^= (1 << 1) if (!this.superRainbow && style[2] & (1 << 1)) style[2] ^= (1 << 1)
index++ index++
} }
@ -353,6 +361,7 @@ class ScrollingTerminal {
let topics = 0 let topics = 0
let topicData = [] let topicData = []
let screenOpts = this.getScreenOpts() let screenOpts = this.getScreenOpts()
let title = this.getTitle()
let buttons = this.getButtons() let buttons = this.getButtons()
let cursor = this.getCursor() let cursor = this.getCursor()
let screen = this.serializeScreen() let screen = this.serializeScreen()
@ -360,6 +369,10 @@ class ScrollingTerminal {
this._screenOpts = screenOpts this._screenOpts = screenOpts
topicData.push(screenOpts) topicData.push(screenOpts)
} }
if (this._title !== title) {
this._title = title
topicData.push(title)
}
if (this._buttons !== buttons) { if (this._buttons !== buttons) {
this._buttons = buttons this._buttons = buttons
topicData.push(buttons) topicData.push(buttons)
@ -528,7 +541,7 @@ let demoshIndex = {
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const self = this const self = this
let x = 14 let x = 13
let cycles = 0 let cycles = 0
let loop = function () { let loop = function () {
for (let y = 0; y < splash.length; y++) { for (let y = 0; y < splash.length; y++) {
@ -536,7 +549,7 @@ let demoshIndex = {
if (dx > 0) drawCell(dx, y) if (dx > 0) drawCell(dx, y)
} }
if (++x < 69) { if (++x < 70) {
if (++cycles >= 3) { if (++cycles >= 3) {
setTimeout(loop, 50) setTimeout(loop, 50)
cycles = 0 cycles = 0
@ -690,15 +703,40 @@ let demoshIndex = {
} }
}, },
rainbow: class ToggleRainbow extends Process { rainbow: class ToggleRainbow extends Process {
constructor (shell) { constructor (shell, options = {}) {
super() super()
this.shell = shell this.shell = shell
this.su = options.su
this.abort = false
}
write (data, newLine = true) {
if (data === 'y') {
this.shell.terminal.rainbow = !this.shell.terminal.rainbow
this.shell.terminal.superRainbow = true
demoData._didWarnRainbow = true
} else {
this.emit('write', data)
}
if (newLine) this.emit('write', '\x1b[0;32m\x1b[G\x1b[79PRainbow!\n')
this.destroy()
} }
run () { run () {
if (this.su && !this.shell.terminal.rainbow) {
if (!demoData._didWarnRainbow) {
this.emit('write', '\x1b[31;1mWarning: flashy colors. Continue? [y/N] ')
} else {
this.write('y', false)
}
} else {
this.shell.terminal.rainbow = !this.shell.terminal.rainbow this.shell.terminal.rainbow = !this.shell.terminal.rainbow
this.emit('write', '') this.shell.terminal.superRainbow = false
this.destroy() this.destroy()
} }
}
destroy () {
this.abort = true
super.destroy()
}
}, },
mouse: class ShowMouse extends Process { mouse: class ShowMouse extends Process {
constructor (shell) { constructor (shell) {
@ -767,43 +805,19 @@ let demoshIndex = {
constructor (shell) { constructor (shell) {
super() super()
this.shell = shell this.shell = shell
this.didDestroy = false
} }
run (...args) { run (...args) {
if (args.length === 0) { if (args.length === 0) {
this.emit('write', '\x1b[31mUsage: sudo <command>\x1b[m\r\n') this.emit('write', '\x1b[31mUsage: sudo [command]\x1b[m\r\n')
this.destroy()
} else if (args.length === 4 && args.join(' ').toLowerCase() === 'make me a sandwich') {
const b = '\x1b[33m'
const r = '\x1b[0m'
const l = '\x1b[32m'
const c = '\x1b[38;5;229m'
const h = '\x1b[38;5;225m'
this.emit('write',
` ${b}_.---._\r\n` +
` _.-~ ~-._\r\n` +
` _.-~ ~-._\r\n` +
` _.-~ ~---._\r\n` +
` _.-~ ~\\\r\n` +
` .-~ _.;\r\n` +
` :-._ _.-~ ./\r\n` +
` \`-._~-._ _..__.-~ _.-~\r\n` +
` ${c}/ ${b}~-._~-._ / .__..--${c}~-${l}---._\r\n` +
`${c} \\_____(_${b};-._\\. _.-~_/${c} ~)${l}.. . \\\r\n` +
`${l} /(_____ ${b}\\\`--...--~_.-~${c}______..-+${l}_______)\r\n` +
`${l} .(_________/${b}\`--...--~/${l} _/ ${h} ${b}/\\\r\n` +
`${b} /-._${h} \\_ ${l}(___./_..-~${h}__.....${b}__..-~./\r\n` +
`${b} \`-._~-._${h} ~\\--------~ .-~${b}_..__.-~ _.-~\r\n` +
`${b} ~-._~-._ ${h}~---------\` ${b}/ .__..--~\r\n` +
`${b} ~-._\\. _.-~_/\r\n` +
`${b} \\\`--...--~_.-~\r\n` +
`${b} \`--...--~${r}\r\n`)
this.destroy() this.destroy()
} else { } else {
let name = args.shift() let name = args.shift()
if (this.shell.index[name]) { if (this.shell.index[name]) {
let Process = this.shell.index[name] let Process = this.shell.index[name]
if (Process instanceof Function) { if (Process instanceof Function) {
let child = new Process(this) let child = this.child = new Process(this.shell, { su: true })
this.on('in', data => child.write(data))
let write = data => this.emit('write', data) let write = data => this.emit('write', data)
child.on('write', write) child.on('write', write)
child.on('exit', code => { child.on('exit', code => {
@ -821,12 +835,50 @@ let demoshIndex = {
} }
} }
} }
destroy () {
if (this.didDestroy) return
this.didDestroy = true
this.child.destroy()
super.destroy()
}
}, },
make: class Make extends Process { make: class Make extends Process {
constructor (shell, options = {}) {
super()
this.su = options.su
}
run (...args) { run (...args) {
if (args.length === 0) this.emit('write', '\x1b[31mmake: *** No targets specified. Stop.\x1b[0m\r\n') if (args.length === 0) this.emit('write', '\x1b[31mmake: *** No targets specified. Stop.\x1b[0m\r\n')
else if (args.length === 3 && args.join(' ').toLowerCase() === 'me a sandwich') { else if (args.length === 3 && args.join(' ').toLowerCase() === 'me a sandwich') {
console.log(this)
if (this.su) {
const b = '\x1b[33m'
const r = '\x1b[0m'
const l = '\x1b[32m'
const c = '\x1b[38;5;229m'
const h = '\x1b[38;5;225m'
this.emit('write',
` ${b}_.---._\r\n` +
` _.-~ ~-._\r\n` +
` _.-~ ~-._\r\n` +
` _.-~ ~---._\r\n` +
` _.-~ ~\\\r\n` +
` .-~ _.;\r\n` +
` :-._ _.-~ ./\r\n` +
` \`-._~-._ _..__.-~ _.-~\r\n` +
` ${c}/ ${b}~-._~-._ / .__..--${c}~-${l}---._\r\n` +
`${c} \\_____(_${b};-._\\. _.-~_/${c} ~)${l}.. . \\\r\n` +
`${l} /(_____ ${b}\\\`--...--~_.-~${c}______..-+${l}_______)\r\n` +
`${l} .(_________/${b}\`--...--~/${l} _/ ${h} ${b}/\\\r\n` +
`${b} /-._${h} \\_ ${l}(___./_..-~${h}__.....${b}__..-~./\r\n` +
`${b} \`-._~-._${h} ~\\--------~ .-~${b}_..__.-~ _.-~\r\n` +
`${b} ~-._~-._ ${h}~---------\` ${b}/ .__..--~\r\n` +
`${b} ~-._\\. _.-~_/\r\n` +
`${b} \\\`--...--~_.-~\r\n` +
`${b} \`--...--~${r}\r\n`)
} else {
this.emit('write', '\x1b[31mmake: me a sandwich : Permission denied\x1b[0m\r\n') this.emit('write', '\x1b[31mmake: me a sandwich : Permission denied\x1b[0m\r\n')
}
} else { } else {
this.emit('write', `\x1b[31mmake: *** No rule to make target '${args.join(' ').toLowerCase()}'. Stop.\x1b[0m\r\n`) this.emit('write', `\x1b[31mmake: *** No rule to make target '${args.join(' ').toLowerCase()}'. Stop.\x1b[0m\r\n`)
} }
@ -852,6 +904,12 @@ let demoshIndex = {
} }
} }
} }
let autocompleteIndex = {
'local-echo': 'local-echo [--suppress-note]',
theme: 'theme [n]',
cursor: 'cursor [block|line|bar] [--steady]',
sudo: 'sudo [command]'
}
class DemoShell { class DemoShell {
constructor (terminal, printInfo) { constructor (terminal, printInfo) {
@ -861,6 +919,7 @@ class DemoShell {
this.history = [] this.history = []
this.historyIndex = 0 this.historyIndex = 0
this.cursorPos = 0 this.cursorPos = 0
this.lastInputLength = 0
this.child = null this.child = null
this.index = demoshIndex this.index = demoshIndex
@ -887,8 +946,29 @@ class DemoShell {
this.history[0] = current this.history[0] = current
this.historyIndex = 0 this.historyIndex = 0
} }
getCompleted (visual = false) {
if (this.history[0]) {
let input = this.history[0]
let prefix = ''
if (input.startsWith('sudo ')) {
let newInput = input.replace(/^(sudo\s+)+/, '')
prefix = input.substr(0, input.length - newInput.length)
input = newInput
}
for (let name in this.index) {
if (name.startsWith(input) && name !== input) {
if (visual && name in autocompleteIndex) return prefix + autocompleteIndex[name]
return prefix + name
}
}
return null
}
return null
}
handleParsed (action, ...args) { handleParsed (action, ...args) {
this.terminal.write(`\x1b[${this.lastInputLength - this.cursorPos}P`)
this.terminal.write('\b\x1b[P'.repeat(this.cursorPos)) this.terminal.write('\b\x1b[P'.repeat(this.cursorPos))
if (action === 'write') { if (action === 'write') {
this.copyFromHistoryIndex() this.copyFromHistoryIndex()
this.history[0] = this.history[0].substr(0, this.cursorPos) + args[0] + this.history[0].substr(this.cursorPos) this.history[0] = this.history[0].substr(0, this.cursorPos) + args[0] + this.history[0].substr(this.cursorPos)
@ -899,7 +979,11 @@ class DemoShell {
this.cursorPos-- this.cursorPos--
if (this.cursorPos < 0) this.cursorPos = 0 if (this.cursorPos < 0) this.cursorPos = 0
} else if (action === 'tab') { } else if (action === 'tab') {
console.warn('TAB not implemented') // TODO completion let completed = this.getCompleted()
if (completed) {
this.history[0] = completed
this.cursorPos = this.history[0].length
}
} else if (action === 'move-cursor-x') { } else if (action === 'move-cursor-x') {
this.cursorPos = Math.max(0, Math.min(this.history[this.historyIndex].length, this.cursorPos + args[0])) this.cursorPos = Math.max(0, Math.min(this.history[this.historyIndex].length, this.cursorPos + args[0]))
} else if (action === 'delete-line') { } else if (action === 'delete-line') {
@ -922,17 +1006,27 @@ class DemoShell {
this.terminal.write(this.history[this.historyIndex]) this.terminal.write(this.history[this.historyIndex])
this.terminal.write('\b'.repeat(this.history[this.historyIndex].length)) this.terminal.write('\b'.repeat(this.history[this.historyIndex].length))
this.terminal.moveForward(this.cursorPos) this.terminal.moveForward(this.cursorPos)
this.terminal.write('') // dummy. Apply the moveFoward
this.lastInputLength = this.cursorPos
let completed = this.getCompleted(true)
if (this.historyIndex === 0 && completed) {
// show closest match faintly
let rest = completed.substr(this.history[0].length)
this.terminal.write(`\x1b[2m${rest}\x1b[m${'\b'.repeat(rest.length)}`)
this.lastInputLength += rest.length
}
if (action === 'return') { if (action === 'return') {
this.terminal.write('\r\n') this.terminal.write('\n')
this.parse(this.history[this.historyIndex]) this.parse(this.history[this.historyIndex])
} }
} }
parse (input) { parse (input) {
if (input === 'help') input = 'info' if (input === 'help') input = 'info'
// TODO: basic chaining (i.e. semicolon) // TODO: basic chaining (i.e. semicolon)
this.run(input) if (input) this.run(input)
else this.prompt()
} }
run (command) { run (command) {
let parts = [''] let parts = ['']

Loading…
Cancel
Save