From e969b56700a0eb93fbd0f2770b386abd66033e60 Mon Sep 17 00:00:00 2001 From: Martin Dvorak Date: Sat, 18 Jan 2014 21:45:37 +0100 Subject: [PATCH] Moved ot curses based keyboard handling and fixed #36. --- man/hh.1 | 12 +- src/hstr.c | 314 +++++++++++++++++------------------ src/hstr_history.c | 5 + src/hstr_utils.c | 2 +- src/include/hstr_history.h | 1 + tests/src/test_curses_keyb.c | 54 ++++++ tests/src/test_keyb.c | 17 +- tests/test_curses.sh | 1 + 8 files changed, 231 insertions(+), 175 deletions(-) create mode 100644 tests/src/test_curses_keyb.c create mode 100755 tests/test_curses.sh diff --git a/man/hh.1 b/man/hh.1 index 7f77357..abe2862 100644 --- a/man/hh.1 +++ b/man/hh.1 @@ -17,10 +17,10 @@ hh allows removal of commands from history - for instance with a typo or with a Show configuration to be added to .bashrc .SH COMMANDS .TP -\fBpattern\fR\eC\-u +\fBpattern\fR Type to filter shell history. .TP -\fBCtrl\-i\fR +\fBCtrl\-u\fR Toggle case sensitive search. .TP \fBCtrl\-h\fR @@ -29,14 +29,20 @@ Toggle history as provided by shell vs. ranked history ordered by the number of \fBUP\fR arrow, \fBDOWN\fR arrow Navigate in the history list. .TP +\fBTAB\fR +Choose currently selected item for completion and let user to edit it on the command prompt. +.TP \fBENTER\fR -Choose currently selected item for completion. +Choose currently selected item for completion and execute it. .TP \fBCtrl\-r\fR Remove currently selected item from the shell history. .TP \fBCtrl\-x\fR Write changes to shell history and exit. +.TP +\fBCtrl\-g\fR +Exit with empty prompt. .SH INSTALLATION Add the following lines to ~/.bashrc: .nf diff --git a/src/hstr.c b/src/hstr.c index b6fcb75..1e9a1e9 100644 --- a/src/hstr.c +++ b/src/hstr.c @@ -34,29 +34,26 @@ #define Y_OFFSET_HISTORY 3 #define Y_OFFSET_ITEMS 4 -#define K_ESC 91 -#define K_ALT 27 - #define K_CTRL_A 1 #define K_CTRL_E 5 +#define K_CTRL_G 7 #define K_CTRL_H 8 -#define K_CTRL_I 9 #define K_CTRL_R 18 +#define K_CTRL_T 20 +#define K_CTRL_U 21 #define K_CTRL_X 24 +#define K_CTRL_Z 26 -#define K_ARROW_LEFT 68 -#define K_ARROW_RIGHT 67 -#define K_ARROW_UP 65 -#define K_ARROW_DOWN 66 +#define K_TAB 9 #define K_ENTER 10 -#define K_BACKSPACE 127 +#define K_ALT 27 #define DEBUG_KEYS #ifdef DEBUG_KEYS -#define LOGKEYS(Y,KEY, BRANCH) mvprintw(Y, 0, "%s Key number: '%3d' / Char: '%c'", BRANCH, KEY, KEY) +#define LOGKEYS(Y,KEY) mvprintw(Y, 0, "Key: '%3d' / Char: '%c'", KEY, KEY); clrtoeol() #else -#define LOGKEYS(Y,KEY, BRANCH) +#define LOGKEYS(Y,KEY) #endif #ifdef DEBUG_CURPOS @@ -66,7 +63,7 @@ #endif static const char *INSTALL_STRING= - "\n# Add this configuration to ~/.bashrc to let HH load and flush up to date history" + "\n# Add this configuration to ~/.bashrc to let HH load and flush up to date history" "\nshopt -s histappend" "\nexport PROMPT_COMMAND=\"history -a; history -n; ${PROMPT_COMMAND}\"" "\nbind '\"\\C-r\": \"\\C-ahh \\C-j\"'" @@ -116,7 +113,7 @@ void print_cmd_deleted_label(char *cmd, int occurences) // make this status row void print_history_label(HistoryItems *history) { - sprintf(screenLine, "- HISTORY - case:%s (C-i) - order:%s (C-h) - %d/%d ", + sprintf(screenLine, "- HISTORY - case:%s (C-u) - order:%s (C-h) - %d/%d ", (caseSensitive?"sensitive":"insensitive"), (defaultOrder?"history":"ranking"), history->count, @@ -331,11 +328,22 @@ void signal_callback_handler_ctrl_c(int signum) } } +char *prepare_result(int selectionCursorPosition, bool executeResult) +{ + cmdline[0]=0; + strcpy(cmdline,selection[selectionCursorPosition]); + if(executeResult) strcat(cmdline,"\n"); + alloc_selection(0); + return cmdline; +} + char *selection_loop(HistoryItems *history) { signal(SIGINT, signal_callback_handler_ctrl_c); initscr(); + keypad(stdscr, TRUE); + noecho(); color_start(); color_init_pair(1, COLOR_WHITE, COLOR_BLACK); color_attr_on(COLOR_PAIR(1)); @@ -343,156 +351,142 @@ char *selection_loop(HistoryItems *history) print_history_label(history); print_help_label(); print_selection(get_max_history_items(stdscr), NULL, history); - int basex = print_prompt(stdscr); - int x = basex; - int width=getmaxx(stdscr); + color_attr_off(COLOR_PAIR(1)); + bool done=FALSE, skip=TRUE, executeResult=FALSE; + int basex=print_prompt(stdscr); + int x=basex, y=1, c, cursorX=0, cursorY=0, maxHistoryItems, deleteOccurences; + int width=getmaxx(stdscr); int selectionCursorPosition=SELECTION_CURSOR_IN_PROMPT; int previousSelectionCursorPosition=SELECTION_CURSOR_IN_PROMPT; - - int y = 1, c, maxHistoryItems, cursorX=0, cursorY=0, deleteOccurences; - bool done = FALSE, skip=TRUE; + char *result="", *msg, *delete; char prefix[SELECTION_PREFIX_MAX_LNG]; prefix[0]=0; strcpy(prefix, cmdline); - char *result="", *msg, *delete; while (!done) { maxHistoryItems=get_max_history_items(stdscr); - noecho(); if(!skip) { c = wgetch(stdscr); } else { skip=FALSE; - } - //echo(); - - if(c==K_ALT) { continue; } - if(CTRL_CHAR(c)) { - switch (c) { - case K_CTRL_R: - if(selectionCursorPosition!=SELECTION_CURSOR_IN_PROMPT) { - delete=selection[selectionCursorPosition]; - msg=malloc(strlen(delete)+1); - strcpy(msg,delete); - selection_remove(delete, history); - deleteOccurences=history_mgmt_remove(delete); - result = print_selection(maxHistoryItems, prefix, history); - print_cmd_deleted_label(msg, deleteOccurences); - move(y, basex+strlen(prefix)); - } - print_history_label(history); - break; - case K_CTRL_I: - caseSensitive=!caseSensitive; + switch (c) { + case K_CTRL_R: + if(selectionCursorPosition!=SELECTION_CURSOR_IN_PROMPT) { + delete=selection[selectionCursorPosition]; + msg=malloc(strlen(delete)+1); + strcpy(msg,delete); + selection_remove(delete, history); + deleteOccurences=history_mgmt_remove(delete); result = print_selection(maxHistoryItems, prefix, history); - print_history_label(history); - break; - case K_CTRL_H: - defaultOrder=!defaultOrder; - result = print_selection(maxHistoryItems, prefix, history); - print_history_label(history); - break; - case K_CTRL_X: - result = NULL; - done = TRUE; - break; - case KEY_ENTER: - case K_ENTER: - if(selectionCursorPosition!=SELECTION_CURSOR_IN_PROMPT) { - result=selection[selectionCursorPosition]; - alloc_selection(0); - } - done = TRUE; - break; - default: - LOGKEYS(Y_OFFSET_HELP, c, "CTRL"); - // skip - break; - } - } else { - switch (c) { - case KEY_RESIZE: - print_history_label(history); + print_cmd_deleted_label(msg, deleteOccurences); move(y, basex+strlen(prefix)); - break; - case KEY_BACKSPACE: - case K_BACKSPACE: - if(strlen(prefix)>0) { - prefix[strlen(prefix)-1]=0; - x--; + } + print_history_label(history); + break; + case K_CTRL_U: + caseSensitive=!caseSensitive; + result = print_selection(maxHistoryItems, prefix, history); + print_history_label(history); + break; + case K_CTRL_H: + defaultOrder=!defaultOrder; + result = print_selection(maxHistoryItems, prefix, history); + print_history_label(history); + break; + case K_CTRL_X: + result = NULL; + done = TRUE; + break; + case KEY_RESIZE: + print_history_label(history); + move(y, basex+strlen(prefix)); + break; + case KEY_BACKSPACE: + if(strlen(prefix)>0) { + prefix[strlen(prefix)-1]=0; + x--; + wattron(stdscr,A_BOLD); + mvprintw(y, basex, "%s", prefix); + wattroff(stdscr,A_BOLD); + clrtoeol(); + } + + if(strlen(prefix)>0) { + make_selection(prefix, history, maxHistoryItems); + } else { + make_selection(NULL, history, maxHistoryItems); + } + result = print_selection(maxHistoryItems, prefix, history); + + move(y, basex+strlen(prefix)); + break; + case KEY_UP: + previousSelectionCursorPosition=selectionCursorPosition; + if(selectionCursorPosition>0) { + selectionCursorPosition--; + } else { + selectionCursorPosition=selectionSize-1; + } + highlight_selection(selectionCursorPosition, previousSelectionCursorPosition, prefix); + move(y, basex+strlen(prefix)); + break; + case KEY_DOWN: + if(selectionCursorPosition==SELECTION_CURSOR_IN_PROMPT) { + selectionCursorPosition=previousSelectionCursorPosition=0; + } else { + previousSelectionCursorPosition=selectionCursorPosition; + if((selectionCursorPosition+1)K_CTRL_Z) { + selectionCursorPosition=SELECTION_CURSOR_IN_PROMPT; + + if(strlen(prefix)<(width-basex-1)) { + strcat(prefix, (char*)(&c)); wattron(stdscr,A_BOLD); mvprintw(y, basex, "%s", prefix); + cursorX=getcurx(stdscr); + cursorY=getcury(stdscr); wattroff(stdscr,A_BOLD); clrtoeol(); } - if(strlen(prefix)>0) { - make_selection(prefix, history, maxHistoryItems); - } else { - make_selection(NULL, history, maxHistoryItems); - } result = print_selection(maxHistoryItems, prefix, history); - - move(y, basex+strlen(prefix)); - break; - case KEY_UP: - case K_ARROW_UP: - previousSelectionCursorPosition=selectionCursorPosition; - if(selectionCursorPosition>0) { - selectionCursorPosition--; - } else { - selectionCursorPosition=selectionSize-1; - } - highlight_selection(selectionCursorPosition, previousSelectionCursorPosition, prefix); - move(y, basex+strlen(prefix)); - break; - case KEY_DOWN: - case K_ARROW_DOWN: - if(selectionCursorPosition==SELECTION_CURSOR_IN_PROMPT) { - selectionCursorPosition=previousSelectionCursorPosition=0; - } else { - previousSelectionCursorPosition=selectionCursorPosition; - if((selectionCursorPosition+1)CMDLINE_LNG) break; + if(strstr(argv[i], " ")) { + strcat(cmdline, "\""); + } + strcat(cmdline, argv[i]); + if(strstr(argv[i], " ")) { + strcat(cmdline, "\""); + } + if((i+1CMDLINE_LNG) break; - printf("%d %s\n", i, argv[i]); - if(strstr(argv[i], " ")) { - strcat(cmdline, "\""); - } - strcat(cmdline, argv[i]); - if(strstr(argv[i], " ")) { - strcat(cmdline, "\""); - } - if((i+10) { diff --git a/src/hstr_history.c b/src/hstr_history.c index 7e3edb8..1ba72e7 100644 --- a/src/hstr_history.c +++ b/src/hstr_history.c @@ -154,6 +154,11 @@ void history_mgmt_open() dirty=false; } +void history_clear_dirty() +{ + dirty=false; +} + int history_mgmt_remove(char *cmd) { int offset=history_search_pos(cmd, 0, 0), occurences=0; diff --git a/src/hstr_utils.c b/src/hstr_utils.c index d855e8e..e59f078 100644 --- a/src/hstr_utils.c +++ b/src/hstr_utils.c @@ -24,7 +24,7 @@ void tiocsti() void fill_terminal_input(char *cmd, bool padding) { - if(cmd) { + if(cmd && strlen(cmd)>0) { size_t size = strlen(cmd); unsigned i; char *c; diff --git a/src/include/hstr_history.h b/src/include/hstr_history.h index 0f13947..229473b 100644 --- a/src/include/hstr_history.h +++ b/src/include/hstr_history.h @@ -43,6 +43,7 @@ HistoryItems *prioritize_history(HistoryItems *historyFileItems); void free_prioritized_history(); void history_mgmt_open(); +void history_clear_dirty(); int history_mgmt_remove(char *cmd); void history_mgmt_close(); diff --git a/tests/src/test_curses_keyb.c b/tests/src/test_curses_keyb.c new file mode 100644 index 0000000..873ba19 --- /dev/null +++ b/tests/src/test_curses_keyb.c @@ -0,0 +1,54 @@ +/* + ============================================================================ + Name : test_curses_keyb.c + Author : martin.dvorak@midforger.com + Copyright : Apache 2.0 + Description : A test + ============================================================================ +*/ + +#include +#include + +int main(int argc, char *argv[]) +{ + initscr(); + noecho(); + keypad(stdscr, TRUE); + + int c; + while(TRUE) { + c = getch(); + + mvprintw(1, 0, "Key number: '%3d' / Char: '%c'", c, c); + + switch(c) { + // ctrl-r, ctrl-h, ctrl-i + case KEY_BACKSPACE: + case KEY_LEFT: + case KEY_RIGHT: + case KEY_UP: + case KEY_DOWN: + mvprintw(5, 0, "CATCHED! %3d",c); + break; + + case KEY_STAB: + case KEY_BTAB: + case KEY_CTAB: + mvprintw(5, 0, "TAB! %3d",c); + break; + + case KEY_RESIZE: + mvprintw(5, 0, "RESIZE! %3d",c); + break; + + case KEY_ENTER: + endwin(); + exit(0); + default: + break; + } + } + + endwin(); +} diff --git a/tests/src/test_keyb.c b/tests/src/test_keyb.c index 6594896..1d5dc96 100644 --- a/tests/src/test_keyb.c +++ b/tests/src/test_keyb.c @@ -11,16 +11,23 @@ #include #include -int main(int argc, char *argv[]) +void echo_printable_characters() { int c; + for(c=0; c<255; c++) { + printf("Key number: '%3d' / Char: '%c' Meta: \n", c, c, c&meta_character_bit); + } +} -// for(c=0; c<255; c++) { -// printf("Key number: '%3d' / Char: '%c' Meta: \n", c, c, c&meta_character_bit); -// } - +void echo_keyb_characters() { + int c; while(1) { c = getc(stdin); printf("Key number: '%3d' / Char: '%c' Meta: %d Ctrl: %d Ctrl mask: %d\n", c, c, META_CHAR(c), CTRL_CHAR(c), c&control_character_mask); } } + +int main(int argc, char *argv[]) +{ + +} diff --git a/tests/test_curses.sh b/tests/test_curses.sh new file mode 100755 index 0000000..c783782 --- /dev/null +++ b/tests/test_curses.sh @@ -0,0 +1 @@ +gcc ./src/test_curses_keyb.c -lcurses -o _curses