mirror of
https://codeberg.org/TicklishHoneyBee/CLIte.git
synced 2026-03-11 09:04:37 +00:00
shell tabfill and history back in place, ability to set tty into raw mode added
This commit is contained in:
parent
015af5b3ba
commit
b6d539ec7f
6 changed files with 249 additions and 200 deletions
|
|
@ -385,6 +385,8 @@ bios.input.keyboard = {
|
|||
}
|
||||
if (k.code == 0)
|
||||
return false;
|
||||
e.preventDefault();
|
||||
bios.input.keyboard.internal.resetFocus();
|
||||
bios.input.keybuffer.input(k);
|
||||
return false;
|
||||
},
|
||||
|
|
@ -407,6 +409,7 @@ bios.input.keyboard = {
|
|||
if (k.code == 0)
|
||||
return false;
|
||||
e.target.value = '';
|
||||
bios.input.keyboard.internal.resetFocus();
|
||||
bios.input.keybuffer.input(k);
|
||||
return false;
|
||||
},
|
||||
|
|
@ -424,27 +427,27 @@ bios.input.keyboard = {
|
|||
switch (key) {
|
||||
case "Down":
|
||||
case "ArrowDown":
|
||||
k.char = String.fromCharCode(17);
|
||||
k.char = -3;
|
||||
k.lchr = k.char;
|
||||
k.code = 17;
|
||||
k.code = -3;
|
||||
break;
|
||||
case "Up":
|
||||
case "ArrowUp":
|
||||
k.char = String.fromCharCode(18);
|
||||
k.char = -4;
|
||||
k.lchr = k.char;
|
||||
k.code = 18;
|
||||
k.code = -4;
|
||||
break;
|
||||
case "Left":
|
||||
case "ArrowLeft":
|
||||
k.char = String.fromCharCode(19);
|
||||
k.char = -5;
|
||||
k.lchr = k.char;
|
||||
k.code = 19;
|
||||
k.code = -5;
|
||||
break;
|
||||
case "Right":
|
||||
case "ArrowRight":
|
||||
k.char = String.fromCharCode(20);
|
||||
k.char = -6;
|
||||
k.lchr = k.char;
|
||||
k.code = 20;
|
||||
k.code = -6;
|
||||
break;
|
||||
case "Enter":
|
||||
k.char = String.fromCharCode(10);
|
||||
|
|
@ -458,9 +461,9 @@ bios.input.keyboard = {
|
|||
k.code = 27;
|
||||
break;
|
||||
case "Shift":
|
||||
k.char = String.fromCharCode(15);
|
||||
k.char = -2;
|
||||
k.lchr = k.char;
|
||||
k.code = 15;
|
||||
k.code = -2;
|
||||
break;
|
||||
case "Tab":
|
||||
k.char = String.fromCharCode(9);
|
||||
|
|
@ -476,6 +479,11 @@ bios.input.keyboard = {
|
|||
k.lchr = k.char;
|
||||
k.code = 8;
|
||||
break;
|
||||
case 'Control':
|
||||
k.char = -1;
|
||||
k.lchar = k.char;
|
||||
k.code = -1;
|
||||
break;
|
||||
default:
|
||||
k.code = key;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -320,24 +320,24 @@ Options:
|
|||
return 0;
|
||||
break;
|
||||
default:
|
||||
stdio.write(io.stderr,'unknown argument: -'+args[i][j]);
|
||||
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
|
||||
}
|
||||
}
|
||||
}else if (file == null) {
|
||||
file = clite.resolvePath(args[i],false);
|
||||
}else{
|
||||
stdio.write(io.stderr,'unknown argument: '+args[i]);
|
||||
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (file == null) {
|
||||
stdio.write(io.stderr,'no file specified');
|
||||
stdio.write(io.stderr,'no file specified\n');
|
||||
return 1;
|
||||
}
|
||||
|
||||
function loadRemote(fd) {
|
||||
if (!fd) {
|
||||
stdio.write(io.stderr,'unable to create file: '+file);
|
||||
stdio.fprintf(io.stderr,'unable to create file: %s\n',file);
|
||||
io.exit(1);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
196
clite/core.js
196
clite/core.js
|
|
@ -2145,7 +2145,8 @@ clite.tty = {
|
|||
data:{
|
||||
active:null,
|
||||
activeID:-1,
|
||||
ttys:[]
|
||||
ttys:[],
|
||||
control:false
|
||||
},
|
||||
internal:{
|
||||
genTTY:function() {return null;},
|
||||
|
|
@ -2220,8 +2221,8 @@ clite.tty = {
|
|||
}
|
||||
// special case, returns any non-character key found
|
||||
if (t.buff[i].code <32 || t.buff[i].code > 126) {
|
||||
k = t.buff.splice(i,1);
|
||||
return t.code;
|
||||
var k = t.buff.splice(i,1);
|
||||
return k.code;
|
||||
}
|
||||
l += t.buff[i].char;
|
||||
}
|
||||
|
|
@ -2230,6 +2231,23 @@ clite.tty = {
|
|||
|
||||
t.buff = t.buff.slice(off);
|
||||
return l;
|
||||
},
|
||||
getControl:function(ch) {
|
||||
var key = {
|
||||
down:false,
|
||||
char:0,
|
||||
lchar:0,
|
||||
code:0
|
||||
};
|
||||
var ind = '-abcdefghijklmnopqrstuvwxyz[\\]^_?';
|
||||
var i = ind.indexOf(ch);
|
||||
if (i>0) {
|
||||
key.char = String.fromCharCode(i);
|
||||
key.lchar = key.char;
|
||||
key.code = i;
|
||||
return key;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
init:function(vfsapi) {
|
||||
|
|
@ -2283,21 +2301,44 @@ clite.tty = {
|
|||
return true;
|
||||
},
|
||||
input:function(key) {
|
||||
// TODO: check for control for special conversions
|
||||
if (key.down)
|
||||
if (key.down) {
|
||||
if (key.code == -1)
|
||||
clite.tty.data.control = true;
|
||||
return;
|
||||
}
|
||||
if (key.code < 0) {
|
||||
if (key.code == -1) {
|
||||
clite.tty.data.control = false;
|
||||
return;
|
||||
}else{
|
||||
if (clite.tty.data.active && typeof clite.tty.data.active.rcb === 'function') {
|
||||
var f = clite.tty.data.active.rcb;
|
||||
clite.tty.data.active.rcb = null;
|
||||
|
||||
f(key.code);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clite.tty.data.control) {
|
||||
var k = clite.tty.internal.getControl(key.char);
|
||||
if (k)
|
||||
key = k;
|
||||
}
|
||||
if (!clite.tty.data.active)
|
||||
return;
|
||||
var t = clite.tty.data.active;
|
||||
// TODO: this hides control characters from echoing... do we want that?
|
||||
if (t.echo && ((key.code > 31 && key.code < 127) || key.code == 10))
|
||||
if (t.echo && ((key.code > 31 && key.code < 127) || key.code == 10 || key.code == 9))
|
||||
clite.tty.write(t.id,key.char);
|
||||
if (t.raw) {
|
||||
if (typeof t.rcb === 'function') {
|
||||
if ((key.code > 31 && key.code < 127) || key.code == 10) {
|
||||
t.rcb(key.char);
|
||||
var f = t.rcb;
|
||||
t.rcb = null;
|
||||
if ((key.code > 31 && key.code < 127) || key.code == 10 || key.code == 9) {
|
||||
f(key.char);
|
||||
}else{
|
||||
t.rcb(key.code);
|
||||
f(key.code);
|
||||
}
|
||||
}else{
|
||||
t.buff.push(key);
|
||||
|
|
@ -2406,6 +2447,29 @@ clite.tty = {
|
|||
|
||||
clite.console.drawBuff(t.data);
|
||||
clite.console.setCursor(0,0);
|
||||
},
|
||||
ttyctrl:function(id,fn,v) {
|
||||
if (id<0 || id>=clite.tty.data.ttys.length)
|
||||
return;
|
||||
var t = clite.tty.data.ttys[id];
|
||||
switch (fn) {
|
||||
case 'raw':
|
||||
if (typeof v === 'boolean')
|
||||
t.raw = v;
|
||||
return t.raw;
|
||||
break;
|
||||
case 'atton':
|
||||
break;
|
||||
case 'attoff':
|
||||
break;
|
||||
case 'echo':
|
||||
if (typeof v === 'boolean')
|
||||
t.echo = v;
|
||||
return t.echo;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -2516,120 +2580,6 @@ clite.console = {
|
|||
}
|
||||
}
|
||||
|
||||
clite.term = {
|
||||
//events:{
|
||||
//keyup:function(e) {
|
||||
//if (clite.term.data.isalt && clite.term.data.alt.israwIn) {
|
||||
//if (clite.term.data.handler != null) {
|
||||
//if (e.key == 'Tab') {
|
||||
//clite.term.data.handler('\t');
|
||||
//}else{
|
||||
//clite.term.data.handler(e.key);
|
||||
//}
|
||||
//}
|
||||
//if (!clite.term.data.alt.echo) {
|
||||
//e.target.value = '';
|
||||
//clite.term.data.buff = '';
|
||||
//return false;
|
||||
//}
|
||||
//}else if (e.key.length > 1 && e.key != 'Spacebar' && clite.term.data.handler != null) {
|
||||
//if (e.key == 'Enter') {
|
||||
//clite.term.data.buff = '';
|
||||
//clite.term.data.handler(e.target.value);
|
||||
//return false;
|
||||
//}else{
|
||||
//clite.term.data.handler('\1'+e.key);
|
||||
//}
|
||||
//}
|
||||
//clite.term.data.buff = e.target.value;
|
||||
//return false;
|
||||
//},
|
||||
//},
|
||||
ttyctrl:function(fn,v) {
|
||||
switch (fn) {
|
||||
//case 'iget': // returns the current input string - bypassing tty read
|
||||
//try{
|
||||
//return clite.term.data.buff;
|
||||
//} catch(err) {
|
||||
//return '';
|
||||
//}
|
||||
//break;
|
||||
//case 'iset': // sets the current input string
|
||||
//try{
|
||||
//if (typeof v !== 'string')
|
||||
//v = '';
|
||||
//clite.term.data.field.value = v;
|
||||
//clite.term.data.buff = v;
|
||||
//return true;
|
||||
//} catch(err) {
|
||||
//return false;
|
||||
//}
|
||||
//break;
|
||||
//case 'prompt': // sets the prompt for input
|
||||
//if (typeof v !== 'string')
|
||||
//v = '';
|
||||
//clite.term.data.prompt = v;
|
||||
//return true;
|
||||
//break;
|
||||
//case 'hide': // turns off input
|
||||
//clite.term.data.show = false;
|
||||
//var f = document.getElementById('form');
|
||||
//if (!f)
|
||||
//return;
|
||||
//f.parentNode.removeChild(f);
|
||||
//break;
|
||||
//case 'show': // turns on input
|
||||
//clite.term.data.show = true;
|
||||
////clite.term.genForm();
|
||||
//break;
|
||||
//case 'alt': // switch to the alternate frame buffer
|
||||
//if (typeof v === 'boolean') {
|
||||
//clite.term.data.isalt = v;
|
||||
//}
|
||||
//if (!clite.term.data.isalt) {
|
||||
//var t = document.getElementById('termalt');
|
||||
//if (t)
|
||||
//t.parentNode.removeChild(t);
|
||||
//}else{
|
||||
////clite.term.genAlt();
|
||||
//}
|
||||
////clite.term.genForm();
|
||||
//return clite.term.data.isalt;
|
||||
//break;
|
||||
//case 'rawout':
|
||||
//if (!clite.term.data.isalt)
|
||||
//return false;
|
||||
//if (typeof v === 'boolean') {
|
||||
//clite.term.data.alt.israwOut = v;
|
||||
//}
|
||||
//return clite.term.data.alt.israwOut;
|
||||
//break;
|
||||
//case 'rawin':
|
||||
//if (!clite.term.data.isalt)
|
||||
//return false;
|
||||
//if (typeof v === 'boolean') {
|
||||
//clite.term.data.alt.israwIn = v;
|
||||
//}
|
||||
//return clite.term.data.alt.israwIn;
|
||||
//break;
|
||||
//case 'atton':
|
||||
//break;
|
||||
//case 'attoff':
|
||||
//break;
|
||||
//case 'echo':
|
||||
//if (!clite.term.data.isalt)
|
||||
//return false;
|
||||
//if (typeof v === 'boolean') {
|
||||
//clite.term.data.alt.echo = v;
|
||||
//}
|
||||
//return clite.term.data.alt.echo;
|
||||
//break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
clite.lib = {
|
||||
// makes text html safe
|
||||
htmlEncode:function(txt) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ clite.libs.data = function() {
|
|||
|
||||
clite.libs.load('libterm','term',function(io,env) {
|
||||
|
||||
// TODO: get the controlling tty id
|
||||
|
||||
return Object.create({
|
||||
|
||||
// clears the terminal
|
||||
|
|
@ -11,8 +13,8 @@ return Object.create({
|
|||
},
|
||||
|
||||
ttyctrl:function(fn,v) {
|
||||
return false;
|
||||
//return clite.term.ttyctrl(fn,v);
|
||||
var ctty = 0;
|
||||
return clite.tty.ttyctrl(ctty,fn,v);
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ clite.libs.load('libtime','time',function(io,env) {
|
|||
t = t.toString();
|
||||
}
|
||||
clite.io.close(io.pid,fd);
|
||||
console.log(t);
|
||||
return parseInt(t,10);
|
||||
}
|
||||
function genTime(time,tz) {
|
||||
|
|
|
|||
210
clite/shell.js
210
clite/shell.js
|
|
@ -6,7 +6,6 @@ clite.commands.load('sh',function(args,env,io) {
|
|||
var stdlib = io.include('stdlib');
|
||||
var term = io.include('term');
|
||||
var clite = io.include('clite');
|
||||
var prompt = '$ ';
|
||||
var has_exited = false;
|
||||
var macro = {
|
||||
clear:function(args,io) {
|
||||
|
|
@ -96,16 +95,16 @@ clite.commands.load('sh',function(args,env,io) {
|
|||
history.index = history.data.length;
|
||||
},
|
||||
up:function() {
|
||||
if (history.index == 0)
|
||||
return;
|
||||
if (history.index < 1)
|
||||
return null;
|
||||
history.index--;
|
||||
term.ttyctrl('iset',history.getCurrent());
|
||||
return history.getCurrent();
|
||||
},
|
||||
down:function() {
|
||||
if (history.index >= history.data.length)
|
||||
return;
|
||||
return null;
|
||||
history.index++;
|
||||
term.ttyctrl('iset',history.getCurrent());
|
||||
return history.getCurrent();
|
||||
},
|
||||
setCurrent:function(txt) {
|
||||
history.current = txt;
|
||||
|
|
@ -126,6 +125,17 @@ clite.commands.load('sh',function(args,env,io) {
|
|||
}
|
||||
}
|
||||
|
||||
function help() {
|
||||
stdio.write(io.stdout,`
|
||||
sh - command interpreter (shell)
|
||||
Usage: sh [OPTION] [FILE]
|
||||
|
||||
Options:
|
||||
-? Print this help information
|
||||
|
||||
`);
|
||||
}
|
||||
|
||||
function resolvePATH(txt) {
|
||||
if (typeof env.PATH === 'undefined')
|
||||
env.PATH = '/bin';
|
||||
|
|
@ -196,12 +206,11 @@ clite.commands.load('sh',function(args,env,io) {
|
|||
return pptxt;
|
||||
}
|
||||
|
||||
function tabfill() {
|
||||
var c = '';//term.ttyctrl('iget');
|
||||
function tabfill(c) {
|
||||
var parts = clite.strToArgs(c);
|
||||
var ai = parts.length-1;
|
||||
if (ai < 0)
|
||||
return;
|
||||
return null;
|
||||
var a = parts[ai];
|
||||
var add = '';
|
||||
if (ai == 0) {
|
||||
|
|
@ -231,8 +240,9 @@ clite.commands.load('sh',function(args,env,io) {
|
|||
// TODO: path fill
|
||||
}
|
||||
if (add == '')
|
||||
return;
|
||||
term.ttyctrl('iset',c+add);
|
||||
return null;
|
||||
stdio.write(io.stdout,'\b'+add);
|
||||
return c+add;
|
||||
}
|
||||
|
||||
function parseScript(fd) {
|
||||
|
|
@ -323,7 +333,7 @@ clite.commands.load('sh',function(args,env,io) {
|
|||
if (typeof p === 'undefined')
|
||||
p = '${USER}:${PWD}'
|
||||
|
||||
prompt = preprocess(p);
|
||||
var prompt = preprocess(p);
|
||||
if (stdlib.getuid() == 0) {
|
||||
prompt += '# ';
|
||||
}else{
|
||||
|
|
@ -333,66 +343,146 @@ clite.commands.load('sh',function(args,env,io) {
|
|||
stdio.write(io.stdout,prompt);
|
||||
}
|
||||
|
||||
function inputControl(key) {
|
||||
switch(key) {
|
||||
case 'Tab':
|
||||
tabfill();
|
||||
break;
|
||||
case 'Down':
|
||||
case 'ArrowDown':
|
||||
history.down();
|
||||
break;
|
||||
case 'Up':
|
||||
case 'ArrowUp':
|
||||
history.up();
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
function input(str) {
|
||||
//if (str[0] == '\1') {
|
||||
//inputControl(str.substring(1));
|
||||
//inputRead();
|
||||
//return;
|
||||
//}
|
||||
|
||||
run(str,true);
|
||||
}
|
||||
function inputRead() {
|
||||
if (has_exited)
|
||||
return;
|
||||
|
||||
var c = '';
|
||||
var cc = 0;
|
||||
|
||||
function inputProcess(str) {
|
||||
switch (str) {
|
||||
case '\t': // tab
|
||||
case 9:
|
||||
var ct = tabfill(c);
|
||||
if (ct != null) {
|
||||
c = ct;
|
||||
cc = c.length;
|
||||
}
|
||||
break;
|
||||
case '\n': // enter
|
||||
term.ttyctrl('raw',false);
|
||||
run(c,true);
|
||||
c = '';
|
||||
cc = 0;
|
||||
return;
|
||||
break;
|
||||
case '\b':
|
||||
case 8:
|
||||
if (c.length > 0) {
|
||||
cc--;
|
||||
c = c.substring(0,cc);
|
||||
stdio.write(io.stdout,'\b \b');
|
||||
}
|
||||
break;
|
||||
case -3: // down arrow
|
||||
var ct = history.down();
|
||||
if (ct != null) {
|
||||
for (var i=0; i<c.length; i++) {
|
||||
stdio.write(io.stdout,'\b \b');
|
||||
}
|
||||
c = ct;
|
||||
cc = c.length;
|
||||
stdio.write(io.stdout,c);
|
||||
}
|
||||
break;
|
||||
case -4: // up arrow
|
||||
var ct = history.up();
|
||||
if (ct != null) {
|
||||
for (var i=0; i<c.length; i++) {
|
||||
stdio.write(io.stdout,'\b \b');
|
||||
}
|
||||
c = ct;
|
||||
cc = c.length;
|
||||
stdio.write(io.stdout,c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (typeof str === 'string') {
|
||||
c += str;
|
||||
cc++;
|
||||
history.setCurrent(c);
|
||||
}
|
||||
}
|
||||
stdio.read(io.stdin,inputProcess);
|
||||
}
|
||||
|
||||
// write the prompt
|
||||
writePrompt();
|
||||
// set tty to raw mode
|
||||
term.ttyctrl('raw',true);
|
||||
// then read from stdin
|
||||
stdio.read(io.stdin,input);
|
||||
stdio.read(io.stdin,inputProcess);
|
||||
}
|
||||
|
||||
// run a shell script
|
||||
if (!stdio.isatty(io.stdin)) {
|
||||
parseScript(io.stdin);
|
||||
return 0;
|
||||
// otherwise we have an interactive shell
|
||||
// so run /etc/shrc and ~/.shrc
|
||||
}else{
|
||||
var fd = stdio.open('/etc/shrc',stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
|
||||
if (fd) {
|
||||
parseScript(fd);
|
||||
stdio.close(fd);
|
||||
}
|
||||
fd = stdio.open(env.HOME+'/.shrc',stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
|
||||
if (fd) {
|
||||
function main(args) {
|
||||
var f = null;
|
||||
var s = false;
|
||||
for (var i=1; i<args.length; i++) {
|
||||
if (args[i][0] == '-') {
|
||||
for (var j=1; j<args[i].length; j++) {
|
||||
switch (args[i][j]) {
|
||||
case '?':
|
||||
help();
|
||||
return 0;
|
||||
break;
|
||||
case 's':
|
||||
s = true;
|
||||
break;
|
||||
default:
|
||||
stdio.fprintf(io.stderr,'unknown argument -%c\n',args[i][j]);
|
||||
}
|
||||
}
|
||||
}else if (f == null) {
|
||||
f = clite.resolvePath(args[i]);
|
||||
}else{
|
||||
stdio.fprintf(io.stderr,'unknown argument - %s\n',args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// run a shell script if one is specified
|
||||
if (f != null) {
|
||||
var fd = stdio.open(f,stdio.flags.O_RDONLY);
|
||||
if (!fd)
|
||||
return 1;
|
||||
parseScript(fd);
|
||||
stdio.close(fd);
|
||||
|
||||
stdlib.waitall(function() {
|
||||
io.exit(0);
|
||||
});
|
||||
// run a shell script from stdin
|
||||
}else if (!stdio.isatty(io.stdin)) {
|
||||
if (!s)
|
||||
return 0;
|
||||
parseScript(io.stdin);
|
||||
|
||||
stdlib.waitall(function() {
|
||||
io.exit(0);
|
||||
});
|
||||
// otherwise we have an interactive shell
|
||||
// so run /etc/shrc and ~/.shrc
|
||||
}else{
|
||||
var fd = stdio.open('/etc/shrc',stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
|
||||
if (fd) {
|
||||
parseScript(fd);
|
||||
stdio.close(fd);
|
||||
}
|
||||
fd = stdio.open(env.HOME+'/.shrc',stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
|
||||
if (fd) {
|
||||
parseScript(fd);
|
||||
stdio.close(fd);
|
||||
}
|
||||
stdlib.waitall(function() {
|
||||
history.clear();
|
||||
inputRead();
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//alert('shell');
|
||||
|
||||
stdlib.waitall(function() {
|
||||
history.clear();
|
||||
inputRead();
|
||||
});
|
||||
|
||||
return null;
|
||||
return main(args);
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue