xaizek / hstr (License: Apachev2) (since 2018-12-07)
Bash and Zsh shell history suggest box - easily view, navigate, search and manage your command history.
Commit 9428399e1c2a206972974ca419ae5bf9c47c0c3f

Fixed #30 - added safe color selected row highlighting, metric/history based ordering, case (in)sensitive search display @ row.
Author: Martin Dvorak
Author date (UTC): 2014-01-09 21:12
Committer name: Martin Dvorak
Committer date (UTC): 2014-01-09 21:12
Parent(s): 7130e1c91f4936c7b05d2ae5790b701594cdc90b
Signing key:
Tree: b741fee56715924f85cd4d80896dfd8ffefa0748
File Lines added Lines deleted
src/hstr.c 113 81
src/hstr_history.c 1 0
src/include/hstr_history.h 1 0
File src/hstr.c changed (mode: 100644) (index 5cccaa6..a6d2487)
22 22 #include "include/hstr_utils.h" #include "include/hstr_utils.h"
23 23 #include "include/hstr_history.h" #include "include/hstr_history.h"
24 24
25 #define LABEL_HISTORY " HISTORY "
26 25 #define FILE_BASHRC ".bashrc" #define FILE_BASHRC ".bashrc"
27 26 #define SELECTION_CURSOR_IN_PROMPT -1 #define SELECTION_CURSOR_IN_PROMPT -1
28 27 #define SELECTION_PREFIX_MAX_LNG 500 #define SELECTION_PREFIX_MAX_LNG 500
 
... ... static const char *BUILD_STRING=
67 66 "HH build: "__DATE__" " __TIME__""; "HH build: "__DATE__" " __TIME__"";
68 67
69 68 static const char *LABEL_HELP= static const char *LABEL_HELP=
70 "Type to filter, UP/DOWN to move, Ctrl-r to remove, ENTER to select, Ctrl-x to exit";
69 "Type to filter, UP/DOWN to move, C-r to remove, ENTER to select, C-x to exit";
71 70
72 71 static char **selection=NULL; static char **selection=NULL;
73 72 static unsigned selectionSize=0; static unsigned selectionSize=0;
74 73 static bool terminalHasColors=FALSE; static bool terminalHasColors=FALSE;
74 static bool caseSensitive=FALSE;
75 static bool defaultOrder=FALSE;
75 76 static char screenLine[1000]; static char screenLine[1000];
76 77
77 int print_prompt(WINDOW *win)
78 int print_prompt()
78 79 { {
79 80 char *hostname = get_hostname(); char *hostname = get_hostname();
80 81 char *user = getenv(ENV_VAR_USER); char *user = getenv(ENV_VAR_USER);
81 82 int xoffset = 1; int xoffset = 1;
82 83
83 mvwprintw(win, xoffset, Y_OFFSET_PROMPT, "%s@%s$ ", user, hostname);
84 mvwprintw(stdscr, xoffset, Y_OFFSET_PROMPT, "%s@%s$ ", user, hostname);
84 85 refresh(); refresh();
85 86
86 87 return xoffset+strlen(user)+1+strlen(hostname)+1; return xoffset+strlen(user)+1+strlen(hostname)+1;
87 88 } }
88 89
89 void print_help_label(WINDOW *win)
90 void print_help_label()
90 91 { {
91 snprintf(screenLine, getmaxx(win), "%s", LABEL_HELP);
92 mvwprintw(win, Y_OFFSET_HELP, 0, screenLine);
92 snprintf(screenLine, getmaxx(stdscr), "%s", LABEL_HELP);
93 mvwprintw(stdscr, Y_OFFSET_HELP, 0, screenLine);
93 94 refresh(); refresh();
94 95 } }
95 96
96 void print_cmd_deleted_label(WINDOW *win, char *cmd, int occurences)
97 void print_cmd_deleted_label(char *cmd, int occurences)
97 98 { {
98 snprintf(screenLine, getmaxx(win), "History item '%s' deleted (%d occurrence%s)", cmd, occurences, (occurences==1?"":"s"));
99 mvwprintw(win, Y_OFFSET_HELP, 0, screenLine);
99 snprintf(screenLine, getmaxx(stdscr), "History item '%s' deleted (%d occurrence%s)", cmd, occurences, (occurences==1?"":"s"));
100 mvwprintw(stdscr, Y_OFFSET_HELP, 0, screenLine);
100 101 clrtoeol(); clrtoeol();
101 102 refresh(); refresh();
102 103 } }
103 104
104 void print_history_label(WINDOW *win)
105 // make this status row
106 void print_history_label(HistoryItems *history)
105 107 { {
106 char message[512];
107
108 int width=getmaxx(win);
109
110 strcpy(message, LABEL_HISTORY);
111 width -= strlen(LABEL_HISTORY);
108 sprintf(screenLine, "- HISTORY - case:%s (C-i) - order:%s (C-h) - %d/%d ",
109 (caseSensitive?"sensitive":"insensitive"),
110 (defaultOrder?"history":"ranking"),
111 history->count,
112 history->rawCount);
113 int width=getmaxx(stdscr);
114 width -= strlen(screenLine);
115 if(width<0) {
116 width = 0;
117 screenLine[getmaxx(stdscr)]=0;
118 }
112 119 unsigned i; unsigned i;
113 120 for (i=0; i < width; i++) { for (i=0; i < width; i++) {
114 strcat(message, " ");
121 strcat(screenLine, "-");
115 122 } }
116
117 wattron(win, A_REVERSE);
118 mvwprintw(win, Y_OFFSET_HISTORY, 0, message);
119 wattroff(win, A_REVERSE);
120
123 wattron(stdscr, A_REVERSE);
124 mvwprintw(stdscr, Y_OFFSET_HISTORY, 0, screenLine);
125 wattroff(stdscr, A_REVERSE);
121 126 refresh(); refresh();
122 127 } }
123 128
124 unsigned get_max_history_items(WINDOW *win)
129 unsigned get_max_history_items()
125 130 { {
126 return (getmaxy(win)-Y_OFFSET_ITEMS);
131 return (getmaxy(stdscr)-Y_OFFSET_ITEMS);
127 132 } }
128 133
129 134
 
... ... void alloc_selection(unsigned size)
139 144 } }
140 145 } }
141 146
142 unsigned make_selection(char *prefix, HistoryItems *history, int maxSelectionCount, bool caseSensitive, bool raw)
147 unsigned make_selection(char *prefix, HistoryItems *history, int maxSelectionCount)
143 148 { {
144 149 alloc_selection(sizeof(char*) * maxSelectionCount); // TODO realloc alloc_selection(sizeof(char*) * maxSelectionCount); // TODO realloc
145 150 unsigned i, selectionCount=0; unsigned i, selectionCount=0;
146 char **source=(raw?history->raw:history->items);
151 char **source=(defaultOrder?history->raw:history->items);
147 152
148 153 for(i=0; i<history->count && selectionCount<maxSelectionCount; i++) { for(i=0; i<history->count && selectionCount<maxSelectionCount; i++) {
149 154 if(source[i]) { if(source[i]) {
 
... ... unsigned make_selection(char *prefix, HistoryItems *history, int maxSelectionCou
184 189 return selectionCount; return selectionCount;
185 190 } }
186 191
187 char *print_selection(WINDOW *win, unsigned maxHistoryItems, char *prefix, HistoryItems *history, bool caseSensitive, bool raw)
192 void color_init_pair(short int x, short int y, short int z)
193 {
194 if(terminalHasColors) {
195 init_pair(x, y, z);
196 }
197 }
198
199 void color_attr_on(int c)
200 {
201 if(terminalHasColors) {
202 attron(c);
203 }
204 }
205
206 void print_selection_row(char *text, int y, int width, char *prefix) {
207 snprintf(screenLine, width, " %s", text);
208 mvwprintw(stdscr, y, 0, screenLine);
209 if(prefix!=NULL && strlen(prefix)>0) {
210 wattron(stdscr,A_BOLD);
211 char *p;
212 if(caseSensitive) {
213 p=strstr(text, prefix);
214 mvwprintw(stdscr, y, 1+(p-text), "%s", prefix);
215 } else {
216 p=strcasestr(text, prefix);
217 snprintf(screenLine, strlen(prefix)+1, "%s", p);
218 mvwprintw(stdscr, y, 1+(p-text), "%s", screenLine);
219 }
220 wattroff(stdscr,A_BOLD);
221 }
222
223 }
224
225 void print_highlighted_selection_row(char *text, int y, int width) {
226 wattron(stdscr, A_REVERSE);
227 wattron(stdscr, A_BOLD);
228 snprintf(screenLine, getmaxx(stdscr), "%s%s", (terminalHasColors?" ":">"), text);
229 mvprintw(y, 0, "%s", screenLine);
230 wattroff(stdscr, A_BOLD);
231 wattroff(stdscr, A_REVERSE);
232 }
233
234 char *print_selection(unsigned maxHistoryItems, char *prefix, HistoryItems *history)
188 235 { {
189 236 char *result=""; char *result="";
190 unsigned selectionCount=make_selection(prefix, history, maxHistoryItems, caseSensitive, raw);
237 unsigned selectionCount=make_selection(prefix, history, maxHistoryItems);
191 238 if (selectionCount > 0) { if (selectionCount > 0) {
192 239 result = selection[0]; result = selection[0];
193 240 } }
194 241
195 int height=get_max_history_items(win);
196 int width=getmaxx(win);
242 int height=get_max_history_items(stdscr);
243 int width=getmaxx(stdscr);
197 244 unsigned i; unsigned i;
198 245 int y=Y_OFFSET_ITEMS; int y=Y_OFFSET_ITEMS;
199 246
200 247 move(Y_OFFSET_ITEMS, 0); move(Y_OFFSET_ITEMS, 0);
201 wclrtobot(win);
248 wclrtobot(stdscr);
202 249
203 char *p;
204 250 for (i = 0; i<height; ++i) { for (i = 0; i<height; ++i) {
205 251 if(i<selectionSize) { if(i<selectionSize) {
206 snprintf(screenLine, width, " %s", selection[i]);
207 mvwprintw(win, y++, 0, screenLine);
208 if(prefix!=NULL && strlen(prefix)>0) {
209 wattron(win,A_BOLD);
210 if(caseSensitive) {
211 p=strstr(selection[i], prefix);
212 mvwprintw(win, (y-1), 1+(p-selection[i]), "%s", prefix);
213 } else {
214 p=strcasestr(selection[i], prefix);
215 snprintf(screenLine, strlen(prefix)+1, "%s", p);
216 mvwprintw(win, (y-1), 1+(p-selection[i]), "%s", screenLine);
217 }
218
219 wattroff(win,A_BOLD);
220 }
252 print_selection_row(selection[i], y++, width, prefix);
221 253 } else { } else {
222 mvwprintw(win, y++, 0, " ");
254 mvwprintw(stdscr, y++, 0, " ");
223 255 } }
224 256 } }
225 257 refresh(); refresh();
 
... ... char *print_selection(WINDOW *win, unsigned maxHistoryItems, char *prefix, Histo
227 259 return result; return result;
228 260 } }
229 261
230 void highlight_selection(int selectionCursorPosition, int previousSelectionCursorPosition)
262 void highlight_selection(int selectionCursorPosition, int previousSelectionCursorPosition, char *prefix)
231 263 { {
232 264 if(previousSelectionCursorPosition!=SELECTION_CURSOR_IN_PROMPT) { if(previousSelectionCursorPosition!=SELECTION_CURSOR_IN_PROMPT) {
233 mvprintw(Y_OFFSET_ITEMS+previousSelectionCursorPosition, 0, " ");
265 print_selection_row(
266 selection[previousSelectionCursorPosition],
267 Y_OFFSET_ITEMS+previousSelectionCursorPosition,
268 getmaxx(stdscr),
269 prefix);
234 270 } }
235 271 if(selectionCursorPosition!=SELECTION_CURSOR_IN_PROMPT) { if(selectionCursorPosition!=SELECTION_CURSOR_IN_PROMPT) {
236 mvprintw(Y_OFFSET_ITEMS+selectionCursorPosition, 0, ">");
272 print_highlighted_selection_row(
273 selection[selectionCursorPosition],
274 Y_OFFSET_ITEMS+selectionCursorPosition,
275 getmaxx(stdscr));
237 276 } }
238 277 } }
239 278
 
... ... void color_start()
245 284 } }
246 285 } }
247 286
248 void color_init_pair(short int x, short int y, short int z)
249 {
250 if(terminalHasColors) {
251 init_pair(x, y, z);
252 }
253 }
254
255 void color_attr_on(int c)
256 {
257 if(terminalHasColors) {
258 attron(c);
259 }
260 }
261
262 287 void color_attr_off(int c) void color_attr_off(int c)
263 288 { {
264 289 if(terminalHasColors) { if(terminalHasColors) {
 
... ... char *selection_loop(HistoryItems *history)
287 312
288 313 color_init_pair(1, COLOR_WHITE, COLOR_BLACK); color_init_pair(1, COLOR_WHITE, COLOR_BLACK);
289 314 color_attr_on(COLOR_PAIR(1)); color_attr_on(COLOR_PAIR(1));
290 print_history_label(stdscr);
291 print_help_label(stdscr);
292 bool caseSensitive=FALSE;
293 bool raw=FALSE;
294 print_selection(stdscr, get_max_history_items(stdscr), NULL, history, caseSensitive, raw);
315 print_history_label(history);
316 print_help_label();
317 print_selection(get_max_history_items(stdscr), NULL, history);
295 318 int basex = print_prompt(stdscr); int basex = print_prompt(stdscr);
296 319 int x = basex; int x = basex;
297 320 int width=getmaxx(stdscr); int width=getmaxx(stdscr);
 
... ... char *selection_loop(HistoryItems *history)
313 336
314 337 switch (c) { switch (c) {
315 338 case KEY_RESIZE: case KEY_RESIZE:
339 print_history_label(history);
340 move(y, basex+strlen(prefix));
341 break;
316 342 case K_CTRL_A: case K_CTRL_A:
317 343 case K_CTRL_E: case K_CTRL_E:
318 344 case K_ARROW_LEFT: case K_ARROW_LEFT:
 
... ... char *selection_loop(HistoryItems *history)
326 352 strcpy(msg,delete); strcpy(msg,delete);
327 353 selection_remove(delete, history); selection_remove(delete, history);
328 354 deleteOccurences=history_mgmt_remove(delete); deleteOccurences=history_mgmt_remove(delete);
329 result = print_selection(stdscr, maxHistoryItems, prefix, history, caseSensitive, raw);
330 print_cmd_deleted_label(stdscr, msg, deleteOccurences);
355 result = print_selection(maxHistoryItems, prefix, history);
356 print_cmd_deleted_label(msg, deleteOccurences);
331 357 move(y, basex+strlen(prefix)); move(y, basex+strlen(prefix));
332 358 } }
359 print_history_label(history);
333 360 break; break;
334 361 case KEY_BACKSPACE: case KEY_BACKSPACE:
335 362 case K_BACKSPACE: case K_BACKSPACE:
 
... ... char *selection_loop(HistoryItems *history)
343 370 } }
344 371
345 372 if(strlen(prefix)>0) { if(strlen(prefix)>0) {
346 make_selection(prefix, history, maxHistoryItems, caseSensitive, raw);
373 make_selection(prefix, history, maxHistoryItems);
347 374 } else { } else {
348 make_selection(NULL, history, maxHistoryItems, caseSensitive, raw);
375 make_selection(NULL, history, maxHistoryItems);
349 376 } }
350 result = print_selection(stdscr, maxHistoryItems, prefix, history, caseSensitive, raw);
377 result = print_selection(maxHistoryItems, prefix, history);
351 378
352 379 move(y, basex+strlen(prefix)); move(y, basex+strlen(prefix));
353 380 break; break;
 
... ... char *selection_loop(HistoryItems *history)
359 386 } else { } else {
360 387 selectionCursorPosition=selectionSize-1; selectionCursorPosition=selectionSize-1;
361 388 } }
362 highlight_selection(selectionCursorPosition, previousSelectionCursorPosition);
389 highlight_selection(selectionCursorPosition, previousSelectionCursorPosition, prefix);
390 move(y, basex+strlen(prefix));
363 391 break; break;
364 392 case KEY_DOWN: case KEY_DOWN:
365 393 case K_DOWN: case K_DOWN:
 
... ... char *selection_loop(HistoryItems *history)
373 401 selectionCursorPosition=0; selectionCursorPosition=0;
374 402 } }
375 403 } }
376 highlight_selection(selectionCursorPosition, previousSelectionCursorPosition);
404 highlight_selection(selectionCursorPosition, previousSelectionCursorPosition, prefix);
405 move(y, basex+strlen(prefix));
377 406 break; break;
378 407 case KEY_ENTER: case KEY_ENTER:
379 408 case K_ENTER: case K_ENTER:
 
... ... char *selection_loop(HistoryItems *history)
385 414 break; break;
386 415 case K_CTRL_I: case K_CTRL_I:
387 416 caseSensitive=!caseSensitive; caseSensitive=!caseSensitive;
417 result = print_selection(maxHistoryItems, prefix, history);
418 print_history_label(history);
388 419 break; break;
389 420 case K_CTRL_H: case K_CTRL_H:
390 raw=!raw;
391 result = print_selection(stdscr, maxHistoryItems, prefix, history, caseSensitive, raw);
421 defaultOrder=!defaultOrder;
422 result = print_selection(maxHistoryItems, prefix, history);
423 print_history_label(history);
392 424 break; break;
393 425 case K_CTRL_X: case K_CTRL_X:
394 426 result = NULL; result = NULL;
 
... ... char *selection_loop(HistoryItems *history)
411 443 clrtoeol(); clrtoeol();
412 444 } }
413 445
414 result = print_selection(stdscr, maxHistoryItems, prefix, history, caseSensitive, raw);
446 result = print_selection(maxHistoryItems, prefix, history);
415 447 move(cursorY, cursorX); move(cursorY, cursorX);
416 448 refresh(); refresh();
417 449 } }
File src/hstr_history.c changed (mode: 100644) (index 2822ace..9390796)
... ... HistoryItems *get_prioritized_history()
123 123 RadixItem **prioritizedRadix=radixsort_dump(&rs); RadixItem **prioritizedRadix=radixsort_dump(&rs);
124 124 prioritizedHistory=malloc(sizeof(HistoryItems)); prioritizedHistory=malloc(sizeof(HistoryItems));
125 125 prioritizedHistory->count=rs.size; prioritizedHistory->count=rs.size;
126 prioritizedHistory->rawCount=historyState->length;
126 127 prioritizedHistory->items=malloc(rs.size * sizeof(char*)); prioritizedHistory->items=malloc(rs.size * sizeof(char*));
127 128 prioritizedHistory->raw=rawHistory; prioritizedHistory->raw=rawHistory;
128 129 for(i=0; i<rs.size; i++) { for(i=0; i<rs.size; i++) {
File src/include/hstr_history.h changed (mode: 100644) (index c8c8e85..0f13947)
... ... typedef struct {
31 31 char **items; char **items;
32 32 char **raw; char **raw;
33 33 unsigned count; unsigned count;
34 unsigned rawCount;
34 35 } HistoryItems; } HistoryItems;
35 36
36 37 HistoryItems *get_prioritized_history(); HistoryItems *get_prioritized_history();
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/hstr

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/hstr

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master