summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenji Dial <benji6283@gmail.com>2020-09-20 14:50:12 -0400
committerBenji Dial <benji6283@gmail.com>2020-09-20 14:50:12 -0400
commitfadd46012c9974931add6c36e69636d3cbc6906f (patch)
treed1af6084772830074be18cf7a9dd93c2ec3d3f59
parentde20d7430df08731d9108acb83e1234ba7f1fe16 (diff)
downloadportland-os-fadd46012c9974931add6c36e69636d3cbc6906f.tar.gz
history when getting line from user in knob
-rw-r--r--src/kernel/kbd.c2
-rw-r--r--src/user/highway/line.c17
-rw-r--r--src/user/highway/main.c3
-rw-r--r--src/user/include/knob/block.h3
-rw-r--r--src/user/include/knob/user.h7
-rw-r--r--src/user/include/pland/syscall.h2
-rw-r--r--src/user/knob/block.c12
-rw-r--r--src/user/knob/user.c125
8 files changed, 160 insertions, 11 deletions
diff --git a/src/kernel/kbd.c b/src/kernel/kbd.c
index c251db7..8808b74 100644
--- a/src/kernel/kbd.c
+++ b/src/kernel/kbd.c
@@ -110,7 +110,7 @@ enum {
CODE_NDOT,
CODE_NSLASH,
/* 0xc0 unassigned */
- CODE_DELETE,
+ CODE_DELETE = 0xc1,
CODE_HOME,
CODE_END,
CODE_PUP,
diff --git a/src/user/highway/line.c b/src/user/highway/line.c
index 40dccfa..b5a54c5 100644
--- a/src/user/highway/line.c
+++ b/src/user/highway/line.c
@@ -57,25 +57,28 @@ void run_line(const char *original_line) {
const char *space;
for (space = line; *space && (*space != ' '); ++space)
;
- if (blockequ(line, "source", space - line))
+ if (blockequ(line, "source ", 7))
source(space + 1);
- else if (blockequ(line, "set", space - line))
+ else if (blockequ(line, "set ", 4))
set(space + 1);
- else if (blockequ(line, "echo", space - line)) {
+ else if (blockequ(line, "echo ", 5)) {
tell_user_sz(space + 1);
tell_user_sz("\n");
}
- else if (blockequ(line, "vars", space - line))
+ else if (blockequ(line, "vars", 5))
dump_vars();
- else if (blockequ(line, "quit", space - line))
+ else if (blockequ(line, "quit", 5))
__pcrt_quit();
- else if (blockequ(line, "help", space - line))
+ else if (blockequ(line, "clear", 6))
+ _clear_screen();
+ else if (blockequ(line, "help", 5))
tell_user_sz("Highway is a command shell for Portland OS. It includes variables and a couple\n"
"of pseudo-commands. Variables are addressed by surrounding with \"$\". The\n"
"following list shows each of the pseudo-commands.\n\n"
" source FILE run each command in FILE\n"
- " set VAR VALUE set $VAR$ to VALUE\n"
+ " clear clear the screen\n"
" echo STRING print STRING\n"
+ " set VAR VALUE set $VAR$ to VALUE\n"
" vars dump variables\n"
" quit exit highway\n"
" help show this\n");
diff --git a/src/user/highway/main.c b/src/user/highway/main.c
index 61f736e..4599315 100644
--- a/src/user/highway/main.c
+++ b/src/user/highway/main.c
@@ -7,10 +7,11 @@ void main(const char *arg) {
source(*arg ? arg : "user/default.rc");
char cmd_buf[128];
yield_task();
+ struct history *cmd_hs = new_history(128);
tell_user_sz("Portland Highway\nType \"help\" for help.\n");
while (1) {
tell_user_sz("\n> ");
- ask_user_line_sz(cmd_buf, 127);
+ ask_user_line_sz_with_history(cmd_buf, 127, cmd_hs);
run_line(cmd_buf);
}
} \ No newline at end of file
diff --git a/src/user/include/knob/block.h b/src/user/include/knob/block.h
index 43137e1..56d3740 100644
--- a/src/user/include/knob/block.h
+++ b/src/user/include/knob/block.h
@@ -10,4 +10,7 @@ bool blockequ(const void *a, const void *b, uint32_t size) __attribute__ ((__pur
//returns length without null-terminator
uint32_t strcpy(char *to, const char *from);
+//allocates new memory
+char *strdup(const char *from);
+
#endif \ No newline at end of file
diff --git a/src/user/include/knob/user.h b/src/user/include/knob/user.h
index cd7676c..fb11c9b 100644
--- a/src/user/include/knob/user.h
+++ b/src/user/include/knob/user.h
@@ -4,6 +4,8 @@
#include <stdint.h>
#include <pland/syscall.h>
+struct history;
+
char key_to_char(_key_code_t key) __attribute__ ((const));
void tell_user_sz(const char *sz);
@@ -12,4 +14,9 @@ void tell_user_sz(const char *sz);
//returns the real length of the string
uint32_t ask_user_line_sz(char *sz, uint32_t max_length);
+struct history *new_history(uint32_t max_entries);
+void del_history(struct history *hs);
+
+uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs);
+
#endif \ No newline at end of file
diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h
index 331002e..14164aa 100644
--- a/src/user/include/pland/syscall.h
+++ b/src/user/include/pland/syscall.h
@@ -73,7 +73,7 @@ typedef enum {
_KEY_NDOT,
_KEY_NSLASH,
/* 0xc0 unassigned */
- _KEY_DELETE,
+ _KEY_DELETE = 0xc1,
_KEY_HOME,
_KEY_END,
_KEY_PUP,
diff --git a/src/user/knob/block.c b/src/user/knob/block.c
index 4ec0564..94bd073 100644
--- a/src/user/knob/block.c
+++ b/src/user/knob/block.c
@@ -1,5 +1,6 @@
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
+#include <knob/heap.h>
//unsophisticated, should copy by dwords where available
void blockcpy(void *to, const void *from, uint32_t size) {
@@ -23,4 +24,13 @@ uint32_t strcpy(char *to, const char *from) {
to[i] = from[i];
while (from[i++]);
return i - 1;
+}
+
+char *strdup(const char *from) {
+ const char *end = from;
+ while (*(end++))
+ ;
+ char *buf = get_block(end - from);
+ blockcpy(buf, from, end - from);
+ return buf;
} \ No newline at end of file
diff --git a/src/user/knob/user.c b/src/user/knob/user.c
index dfcb791..1e273bb 100644
--- a/src/user/knob/user.c
+++ b/src/user/knob/user.c
@@ -1,4 +1,6 @@
#include <pland/syscall.h>
+#include <knob/block.h>
+#include <knob/heap.h>
#include <stdint.h>
#include <stdbool.h>
@@ -171,4 +173,127 @@ uint32_t ask_user_line_sz(char *sz, uint32_t max_length) {
sz[i] = '\0';
return i;
+}
+
+struct history_entry {
+ struct history_entry *prev;
+ struct history_entry *next;
+ const char *contents;
+};
+
+struct history {
+ struct history_entry *earliest_history_item;
+ struct history_entry *latest_history_item;
+ uint32_t max_entries;
+ uint32_t cur_entries;
+};
+
+struct history *new_history(uint32_t max_entries) {
+ struct history *new = get_block(sizeof(struct history));
+ new->latest_history_item = 0;
+ new->earliest_history_item = 0;
+ new->max_entries = max_entries;
+ new->cur_entries = 0;
+ return new;
+}
+
+void del_history(struct history *hs) {
+ free_block(hs);
+ for (struct history_entry *he = hs->latest_history_item; he; he = he->prev) {
+ free_block(he);
+ free_block(he->contents);
+ }
+}
+
+//return value and max_length don't include null terminator
+uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs) {
+ char log_buf[2];
+ log_buf[1] = '\0';
+ struct history_entry *cur_he = 0;
+
+ uint32_t i;
+ for (i = 0; i != max_length; ++i) {
+ char key;
+ replace:
+ key = get_key_char();
+ if (!key)
+ goto replace;
+ if (key == (char)_KEY_UP) {
+ struct history_entry *new_cur_he = cur_he ? cur_he->prev : hs->latest_history_item;
+ if (new_cur_he) {
+ cur_he = new_cur_he;
+ for (uint32_t j = 0; j < i; ++j)
+ _log_string("\b");
+ i = strcpy(sz, cur_he->contents);
+ _log_string(sz);
+ }
+ goto replace;
+ }
+ if (key == (char)_KEY_DOWN) {
+ cur_he = cur_he ? cur_he->next : 0;
+ for (uint32_t j = 0; j < i; ++j)
+ _log_string("\b");
+ if (cur_he) {
+ i = strcpy(sz, cur_he->contents);
+ _log_string(sz);
+ }
+ else
+ i = 0;
+ goto replace;
+ }
+ if (key & 0x80)
+ goto replace;//TODO
+ if (key == '\b') {
+ if (i) {
+ --i;
+ _log_string("\b");
+ }
+ goto replace;
+ }
+
+ log_buf[0] = key;
+ _log_string(log_buf);
+
+ if (key == '\n')
+ break;
+ sz[i] = key;
+ }
+
+ sz[i] = '\0';
+
+ struct history_entry *new_he = get_block(sizeof(struct history_entry));
+ new_he->contents = strdup(sz);
+
+ new_he->next = 0;
+ if (hs->latest_history_item) {
+ new_he->prev = hs->latest_history_item;
+ hs->latest_history_item->next = new_he;
+ }
+ else
+ new_he->prev = 0;
+ hs->latest_history_item = new_he;
+ if (!hs->earliest_history_item)
+ hs->earliest_history_item = new_he;
+ if (hs->max_entries == hs->cur_entries) {
+ free_block(hs->earliest_history_item);
+ free_block(hs->earliest_history_item->contents);
+ hs->earliest_history_item->next->prev = 0;
+ hs->earliest_history_item = hs->earliest_history_item->next;
+ }
+ else
+ ++(hs->cur_entries);
+
+ for (struct history_entry *check_he = hs->latest_history_item->prev; check_he; check_he = check_he->prev) {
+ if (blockequ(check_he->contents, sz, i + 1)) {
+ check_he->next->prev = check_he->prev;
+ if (check_he->prev)
+ check_he->prev->next = check_he->next;
+ else
+ hs->earliest_history_item = check_he->next;
+ free_block(check_he);
+ free_block(check_he->contents);
+ }
+ }
+
+ return i;
} \ No newline at end of file