mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
212 lines
7.3 KiB
C
212 lines
7.3 KiB
C
#include "cmd_parser.h"
|
|
#include "machine.h"
|
|
|
|
#pragma codeseg BANK2
|
|
#pragma constseg BANK2
|
|
|
|
// Position in the serial buffer
|
|
__xdata uint8_t l;
|
|
// Properties of currently edited command line in cmd_buffer[CMD_BUF_SIZE]
|
|
__xdata uint8_t cursor;
|
|
__xdata uint8_t cmd_line_len;
|
|
__xdata uint8_t current_cmdline[CMD_BUF_SIZE];
|
|
__xdata uint16_t history_editptr;
|
|
|
|
|
|
extern __xdata uint8_t cmd_history[CMD_HISTORY_SIZE];
|
|
extern __xdata uint16_t cmd_history_ptr;
|
|
|
|
void cmd_editor_init(void) __banked
|
|
{
|
|
l = sbuf_ptr; // We have printed out entered characters until l
|
|
cursor = 0;
|
|
cmd_line_len = 0;
|
|
cmd_available = 0;
|
|
history_editptr = 0xffff;
|
|
}
|
|
|
|
/*
|
|
* Allows editing the current command line held in cmd_buffer[CMD_BUF_SIZE] by
|
|
* identifying new characters typed or up to 4-byte escape sequences in the
|
|
* serial buffer ring sbuf[SBUF_SIZE].
|
|
* Upon detecting new characters or escape sequences, the cmd_buffer and the
|
|
* representation of the command line in the terminal are updated.
|
|
* To debug, the easist is to interpose a tty-interceptor between the physical
|
|
* serial device and a logical one created by interceptty:
|
|
* sudo interceptty -s 'ispeed 115200 ospeed 115200' /dev/ttyUSB0 /dev/tmpS
|
|
* picocom -b 115200 /dev/tmpS
|
|
*/
|
|
void cmd_edit(void) __banked
|
|
{
|
|
while (l != sbuf_ptr) {
|
|
if (sbuf[l] >= ' ' && sbuf[l] < 127) { // A printable character, copy to command line
|
|
// Reserve one byte for the terminating NUL written on Enter. When the
|
|
// line is full, drop the character but still fall through to advance the
|
|
// serial-ring read pointer below; a 'continue' here would spin forever.
|
|
if (cmd_line_len < CMD_BUF_SIZE - 1) {
|
|
write_char(sbuf[l]);
|
|
// Shift buffer to right
|
|
for (uint8_t i = cmd_line_len; i > cursor; i--)
|
|
cmd_buffer[i] = cmd_buffer[i-1];
|
|
// Insert char in comand buffer
|
|
cmd_buffer[cursor++] = sbuf[l];
|
|
cmd_line_len++;
|
|
// Print rest of line
|
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
|
write_char(cmd_buffer[i]);
|
|
// Move backwards
|
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
|
write_char('\010'); // BS works like cursor-left
|
|
}
|
|
} else if (sbuf[l] == '\033') { // ESC-Sequence
|
|
// Wait until we have at least 3 characters including the ESC character in the serial buffer
|
|
if (((sbuf_ptr + SBUF_SIZE - l) & SBUF_MASK) < 3)
|
|
continue;
|
|
if (((sbuf_ptr > l ? sbuf_ptr - l : SBUF_SIZE + sbuf_ptr - l) >= 4)
|
|
&& sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == '3' && sbuf[(l + 3) & SBUF_MASK] == '~') { // DEL
|
|
if (cursor < cmd_line_len) {
|
|
write_char('\033'); write_char('['); write_char('1'); write_char('P'); // Delete to end of line
|
|
cmd_line_len--;
|
|
for (uint8_t i = cursor; i < cmd_line_len; i++) {
|
|
cmd_buffer[i] = cmd_buffer[i+1];
|
|
write_char(cmd_buffer[i]);
|
|
}
|
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
|
write_char('\010');
|
|
}
|
|
l += 4;
|
|
l &= SBUF_MASK;
|
|
continue;
|
|
} else if (sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == 'D') { // <CURSOR-LEFT>
|
|
if (cursor) {
|
|
write_char('\010'); // BS works like cursor-left
|
|
cursor--;
|
|
}
|
|
l += 3;
|
|
l &= SBUF_MASK;
|
|
continue;
|
|
} else if (sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == 'C') { // <CURSOR-RIGHT>
|
|
if (cursor < cmd_line_len) {
|
|
write_char('\033'); write_char('['); write_char('C');
|
|
cursor++;
|
|
}
|
|
l += 3;
|
|
l &= SBUF_MASK;
|
|
continue;
|
|
} else if (sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == 'A') { // <CURSOR-UP>
|
|
for (uint8_t i = 0; i < cmd_line_len; i++)
|
|
current_cmdline[i] = cmd_buffer[i];
|
|
current_cmdline[cmd_line_len] = 0;
|
|
__xdata uint16_t p;
|
|
if (history_editptr == 0xffff)
|
|
p = (cmd_history_ptr - 2) & CMD_HISTORY_MASK;
|
|
else
|
|
p = history_editptr;
|
|
// Move cursor to beginning of line
|
|
write_char('\033'); write_char('['); itoa(cursor + 2); write_char('D');
|
|
cursor = 0;
|
|
while (cmd_history[p] && cmd_history[p] != '\n') {
|
|
cursor++;
|
|
p--;
|
|
p &= CMD_HISTORY_MASK;
|
|
}
|
|
history_editptr = (p - 1) & CMD_HISTORY_MASK;
|
|
p = (p + 1) & CMD_HISTORY_MASK;
|
|
if (cursor) {
|
|
print_string("\033[2K> "); // Clear entire line: ^[[2K and print new prompt
|
|
for (uint8_t i = 0; i < cursor; i++) {
|
|
cmd_buffer[i] = cmd_history[p];
|
|
write_char(cmd_buffer[i]);
|
|
p = (p+1) & CMD_HISTORY_MASK;
|
|
}
|
|
cmd_line_len = cursor;
|
|
} else {
|
|
print_string("\033[2C"); // Move 2 right to start of editing space
|
|
}
|
|
l += 3;
|
|
l &= SBUF_MASK;
|
|
continue;
|
|
} else if (sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == 'B') { // <CURSOR-DOWN>
|
|
if (history_editptr != 0xffff) {
|
|
__xdata uint16_t p = (history_editptr + 2) & CMD_HISTORY_MASK;
|
|
// Move cursor to beginning of line
|
|
write_char('\033'); write_char('['); itoa(cursor + 2); write_char('D');
|
|
print_string("\033[2K> "); // Clear entire line: ^[[2K and print new prompt
|
|
uint8_t i = 0;
|
|
while (cmd_history[p] && cmd_history[p] != '\n') {
|
|
p = (p + 1) & CMD_HISTORY_MASK;
|
|
}
|
|
p = (p + 1) & CMD_HISTORY_MASK;
|
|
while (cmd_history[p] && cmd_history[p] != '\n') {
|
|
cmd_buffer[i] = cmd_history[p];
|
|
write_char(cmd_buffer[i++]);
|
|
p = (p + 1) & CMD_HISTORY_MASK;
|
|
}
|
|
history_editptr = (p - 1) & CMD_HISTORY_MASK;
|
|
if (!i) {
|
|
if (current_cmdline[i]) {
|
|
while (current_cmdline[i]) {
|
|
cmd_buffer[i] = current_cmdline[i];
|
|
write_char(cmd_buffer[i++]);
|
|
}
|
|
} else {
|
|
write_char('\033'); write_char('['); write_char('C');
|
|
}
|
|
history_editptr = 0xffff;
|
|
// Move cursor right
|
|
}
|
|
cmd_line_len = i;
|
|
cursor = 0;
|
|
// Move cursor again to beginning of line
|
|
write_char('\033'); write_char('['); itoa(i); write_char('D');
|
|
} else {
|
|
// If we are at the last entry of the history, just move the cursor to the end of the line
|
|
if (cursor < cmd_line_len) {
|
|
write_char('\033'); write_char('['); itoa(cmd_line_len - cursor); write_char('C');
|
|
}
|
|
cursor = cmd_line_len;
|
|
}
|
|
l += 3;
|
|
l &= SBUF_MASK;
|
|
continue;
|
|
} else { // An unknown or not yet complete Escape sequence: wait
|
|
continue;
|
|
}
|
|
} else if (sbuf[l] == 127 || sbuf[l] == 8) { // Backspace DEL or BS/^H
|
|
if (cursor > 0) {
|
|
write_char('\010');
|
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
|
write_char(cmd_buffer[i]);
|
|
write_char(' '); // Overwrite end of line
|
|
// Move backwards n steps:
|
|
for (uint8_t i = cursor; i <= cmd_line_len; i++)
|
|
write_char('\010');
|
|
cursor--;
|
|
for (uint8_t i = cursor; i <= cmd_line_len; i++)
|
|
cmd_buffer[i] = cmd_buffer[i+1];
|
|
cmd_line_len--;
|
|
}
|
|
}
|
|
// If the command buffer is currently in use, we cannot copy to it
|
|
if (cmd_available)
|
|
break;
|
|
// Check whether return was pressed:
|
|
if (sbuf[l] == '\n' || sbuf[l] == '\r') {
|
|
write_char('\n');
|
|
cmd_buffer[cmd_line_len] = NUL;
|
|
// write_char('>'); print_string_x(cmd_buffer); write_char('<');
|
|
// If there is a command we print the prompt after execution
|
|
// otherwise immediately because there is nothing to execute
|
|
if (cmd_line_len)
|
|
cmd_available = 1;
|
|
else
|
|
print_cmd_prompt();
|
|
cursor = 0;
|
|
cmd_line_len = 0;
|
|
history_editptr = 0xffff;
|
|
}
|
|
l++;
|
|
l &= SBUF_MASK;
|
|
}
|
|
}
|