incremental filtering

plus some fixes
This commit is contained in:
Hisham Muhammad 2011-09-08 01:17:26 +00:00
parent 3f3213b2e2
commit 11092662ee
4 changed files with 101 additions and 41 deletions

View File

@ -6,6 +6,8 @@ What's new in version 0.9.1
* Meters update in every screen (no longer halting while on Setup, etc.) * Meters update in every screen (no longer halting while on Setup, etc.)
* Stricter checks for command-line options * Stricter checks for command-line options
(thanks to Sebastian Pipping) (thanks to Sebastian Pipping)
* Incremental filtering
(thanks to Seth Heeren for the idea and initial implementation)
* BUGFIX: Support larger numbers for process times. * BUGFIX: Support larger numbers for process times.
(thanks to Tristan Nakagawa for the report.) (thanks to Tristan Nakagawa for the report.)
* BUGFIX: Segfault in BarMeterMode_draw() for small terminal widths * BUGFIX: Segfault in BarMeterMode_draw() for small terminal widths

View File

@ -67,7 +67,12 @@ Incremental process search: type in part of a process command line and
the selection highlight will be moved to it. While in search mode, the selection highlight will be moved to it. While in search mode,
pressing this key will cycle through matching occurrences. pressing this key will cycle through matching occurrences.
.TP .TP
.B F4, I .B F4, \
Incremental process filtering: type in part of a process command line and
only processes whose names match will be shown. To cancel filtering,
enter the Filter option again and press Esc.
.TP
.B I
Invert sort order: if sort order is increasing, switch to decreasing, Invert sort order: if sort order is increasing, switch to decreasing,
and vice-versa. and vice-versa.
.TP .TP

127
htop.c
View File

@ -118,7 +118,7 @@ static void showHelp(ProcessList* pl) {
mvaddstr( 9, 0, " Arrows: scroll process list F5 t: tree view"); mvaddstr( 9, 0, " Arrows: scroll process list F5 t: tree view");
mvaddstr(10, 0, " Digits: incremental PID search u: show processes of a single user"); mvaddstr(10, 0, " Digits: incremental PID search u: show processes of a single user");
mvaddstr(11, 0, " F3 /: incremental name search H: hide/show user threads"); mvaddstr(11, 0, " F3 /: incremental name search H: hide/show user threads");
mvaddstr(12, 0, " K: hide/show kernel threads"); mvaddstr(12, 0, " F4 \\: incremental name filtering K: hide/show kernel threads");
mvaddstr(13, 0, " Space: tag processes F: cursor follows process"); mvaddstr(13, 0, " Space: tag processes F: cursor follows process");
mvaddstr(14, 0, " U: untag all processes + -: expand/collapse tree"); mvaddstr(14, 0, " U: untag all processes + -: expand/collapse tree");
mvaddstr(15, 0, " F9 k: kill process/tagged processes P: sort by CPU%"); mvaddstr(15, 0, " F9 k: kill process/tagged processes P: sort by CPU%");
@ -126,10 +126,10 @@ static void showHelp(ProcessList* pl) {
mvaddstr(17, 0, " [ F8: lower priority (+ nice) T: sort by TIME"); mvaddstr(17, 0, " [ F8: lower priority (+ nice) T: sort by TIME");
#ifdef HAVE_PLPA #ifdef HAVE_PLPA
if (pl->cpuCount > 1) if (pl->cpuCount > 1)
mvaddstr(18, 0, " a: set CPU affinity F4 I: invert sort order"); mvaddstr(18, 0, " a: set CPU affinity I: invert sort order");
else else
#endif #endif
mvaddstr(18, 0, " F4 I: invert sort order"); mvaddstr(18, 0, " I: invert sort order");
mvaddstr(19, 0, " F2 S: setup F6 >: select sort column"); mvaddstr(19, 0, " F2 S: setup F6 >: select sort column");
mvaddstr(20, 0, " F1 h: show this help screen l: list open files with lsof"); mvaddstr(20, 0, " F1 h: show this help screen l: list open files with lsof");
mvaddstr(21, 0, " F10 q: quit s: trace syscalls with strace"); mvaddstr(21, 0, " F10 q: quit s: trace syscalls with strace");
@ -138,7 +138,7 @@ static void showHelp(ProcessList* pl) {
mvaddstr( 9, 0, " Arrows"); mvaddstr( 9,40, " F5 t"); mvaddstr( 9, 0, " Arrows"); mvaddstr( 9,40, " F5 t");
mvaddstr(10, 0, " Digits"); mvaddstr(10,40, " u"); mvaddstr(10, 0, " Digits"); mvaddstr(10,40, " u");
mvaddstr(11, 0, " F3 /"); mvaddstr(11,40, " H"); mvaddstr(11, 0, " F3 /"); mvaddstr(11,40, " H");
mvaddstr(12,40, " K"); mvaddstr(12, 0, " F4 \\"); mvaddstr(12,40, " K");
mvaddstr(13, 0, " Space"); mvaddstr(13,40, " F"); mvaddstr(13, 0, " Space"); mvaddstr(13,40, " F");
mvaddstr(14, 0, " U"); mvaddstr(14,40, " + -"); mvaddstr(14, 0, " U"); mvaddstr(14,40, " + -");
mvaddstr(15, 0, " F9 k"); mvaddstr(15,40, " P"); mvaddstr(15, 0, " F9 k"); mvaddstr(15,40, " P");
@ -246,6 +246,17 @@ static inline void setSortKey(ProcessList* pl, ProcessField sortKey, Panel* pane
ProcessList_printHeader(pl, Panel_getHeader(panel)); ProcessList_printHeader(pl, Panel_getHeader(panel));
} }
typedef struct IncBuffer_ {
char buffer[INCSEARCH_MAX];
int index;
FunctionBar* bar;
} IncBuffer;
static void IncBuffer_reset(IncBuffer* inc) {
inc->index = 0;
inc->buffer[0] = 0;
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
int delay = -1; int delay = -1;
@ -335,11 +346,6 @@ int main(int argc, char** argv) {
Panel* killPanel = NULL; Panel* killPanel = NULL;
char incSearchBuffer[INCSEARCH_MAX];
int incSearchIndex = 0;
incSearchBuffer[0] = 0;
bool incSearchMode = false;
ProcessList* pl = NULL; ProcessList* pl = NULL;
UsersTable* ut = UsersTable_new(); UsersTable* ut = UsersTable_new();
@ -365,12 +371,24 @@ int main(int argc, char** argv) {
} }
ProcessList_printHeader(pl, Panel_getHeader(panel)); ProcessList_printHeader(pl, Panel_getHeader(panel));
const char* searchFunctions[] = {"Next ", "Exit ", " Search: ", NULL}; IncBuffer incSearch, incFilter;
bool filtering = false;
memset(&incSearch, 0, sizeof(IncBuffer));
const char* searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
const char* searchKeys[] = {"F3", "Esc", " "}; const char* searchKeys[] = {"F3", "Esc", " "};
int searchEvents[] = {KEY_F(3), 27, ERR}; int searchEvents[] = {KEY_F(3), 27, ERR};
FunctionBar* searchBar = FunctionBar_new(searchFunctions, searchKeys, searchEvents); incSearch.bar = FunctionBar_new(searchFunctions, searchKeys, searchEvents);
const char* defaultFunctions[] = {"Help ", "Setup ", "Search", "Invert", "Tree ", memset(&incFilter, 0, sizeof(IncBuffer));
const char* filterFunctions[] = {"Done ", "Clear ", " Filter: ", NULL};
const char* filterKeys[] = {"Enter", "Esc", " "};
int filterEvents[] = {13, 27, ERR};
incFilter.bar = FunctionBar_new(filterFunctions, filterKeys, filterEvents);
IncBuffer* incMode = NULL;
const char* defaultFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ",
"SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL}; "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
FunctionBar* defaultBar = FunctionBar_new(defaultFunctions, NULL, NULL); FunctionBar* defaultBar = FunctionBar_new(defaultFunctions, NULL, NULL);
@ -397,6 +415,7 @@ int main(int argc, char** argv) {
if (recalculate) if (recalculate)
oldTime = newTime; oldTime = newTime;
if (doRefresh) { if (doRefresh) {
int currPos = Panel_getSelectedIndex(panel); int currPos = Panel_getSelectedIndex(panel);
pid_t currPid = 0; pid_t currPid = 0;
int currScrollV = panel->scrollV; int currScrollV = panel->scrollV;
@ -414,8 +433,15 @@ int main(int argc, char** argv) {
int size = ProcessList_size(pl); int size = ProcessList_size(pl);
int idx = 0; int idx = 0;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
bool hidden = false;
Process* p = ProcessList_get(pl, i); Process* p = ProcessList_get(pl, i);
if (p->show && (!userOnly || (p->st_uid == userId))) {
if ( (!p->show)
|| (userOnly && (p->st_uid != userId))
|| (filtering && !(String_contains_i(p->comm, incFilter.buffer))) )
hidden = true;
if (!hidden) {
Panel_set(panel, idx, (Object*)p); Panel_set(panel, idx, (Object*)p);
if ((!follow && idx == currPos) || (follow && p->pid == currPid)) { if ((!follow && idx == currPos) || (follow && p->pid == currPid)) {
Panel_setSelected(panel, idx); Panel_setSelected(panel, idx);
@ -431,10 +457,11 @@ int main(int argc, char** argv) {
Panel_draw(panel, true); Panel_draw(panel, true);
int prev = ch; int prev = ch;
move(LINES-1, CRT_cursorX);
ch = getch(); ch = getch();
if (ch == ERR) { if (ch == ERR) {
if (!incSearchMode) if (!incMode)
refreshTimeout--; refreshTimeout--;
if (prev == ch && !recalculate) { if (prev == ch && !recalculate) {
closeTimeout++; closeTimeout++;
@ -446,7 +473,7 @@ int main(int argc, char** argv) {
continue; continue;
} }
if (incSearchMode) { if (incMode) {
doRefresh = false; doRefresh = false;
int size = Panel_size(panel); int size = Panel_size(panel);
if (ch == KEY_F(3)) { if (ch == KEY_F(3)) {
@ -456,22 +483,40 @@ int main(int argc, char** argv) {
if (i == size) if (i == size)
i = 0; i = 0;
Process* p = (Process*) Panel_get(panel, i); Process* p = (Process*) Panel_get(panel, i);
if (String_contains_i(p->comm, incSearchBuffer)) { if (String_contains_i(p->comm, incMode->buffer)) {
Panel_setSelected(panel, i); Panel_setSelected(panel, i);
break; break;
} }
i++; i++;
} }
continue; continue;
} else if (isprint((char)ch) && (incSearchIndex < INCSEARCH_MAX)) { } else if (isprint((char)ch) && (incMode->index < INCSEARCH_MAX)) {
incSearchBuffer[incSearchIndex] = ch; incMode->buffer[incMode->index] = ch;
incSearchIndex++; incMode->index++;
incSearchBuffer[incSearchIndex] = 0; incMode->buffer[incMode->index] = 0;
} else if ((ch == KEY_BACKSPACE || ch == 127) && (incSearchIndex > 0)) { if (incMode == &incFilter) {
incSearchIndex--; doRefresh = true;
incSearchBuffer[incSearchIndex] = 0; if (incFilter.index == 1) filtering = true;
}
} else if ((ch == KEY_BACKSPACE || ch == 127) && (incMode->index > 0)) {
incMode->index--;
incMode->buffer[incMode->index] = 0;
if (incMode == &incFilter) {
doRefresh = true;
if (incFilter.index == 0) {
filtering = false;
IncBuffer_reset(incMode);
}
}
} else { } else {
incSearchMode = false; if (incMode == &incFilter) {
doRefresh = true;
if (ch == 27) {
filtering = false;
IncBuffer_reset(incMode);
}
}
incMode = NULL;
FunctionBar_draw(defaultBar, NULL); FunctionBar_draw(defaultBar, NULL);
continue; continue;
} }
@ -479,16 +524,16 @@ int main(int argc, char** argv) {
bool found = false; bool found = false;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
Process* p = (Process*) Panel_get(panel, i); Process* p = (Process*) Panel_get(panel, i);
if (String_contains_i(p->comm, incSearchBuffer)) { if (String_contains_i(p->comm, incSearch.buffer)) {
Panel_setSelected(panel, i); Panel_setSelected(panel, i);
found = true; found = true;
break; break;
} }
} }
if (found) if (found)
FunctionBar_draw(searchBar, incSearchBuffer); FunctionBar_draw(incMode->bar, incMode->buffer);
else else
FunctionBar_drawAttr(searchBar, incSearchBuffer, CRT_colors[FAILED_SEARCH]); FunctionBar_drawAttr(incMode->bar, incMode->buffer, CRT_colors[FAILED_SEARCH]);
continue; continue;
} }
if (isdigit((char)ch)) { if (isdigit((char)ch)) {
@ -527,7 +572,7 @@ int main(int argc, char** argv) {
continue; continue;
} if (mevent.y == LINES - 1) { } if (mevent.y == LINES - 1) {
FunctionBar* bar; FunctionBar* bar;
if (incSearchMode) bar = searchBar; if (incMode) bar = incMode->bar;
else bar = defaultBar; else bar = defaultBar;
ch = FunctionBar_synthesizeEvent(bar, mevent.x); ch = FunctionBar_synthesizeEvent(bar, mevent.x);
} }
@ -544,8 +589,8 @@ int main(int argc, char** argv) {
switch (ch) { switch (ch) {
case KEY_RESIZE: case KEY_RESIZE:
Panel_resize(panel, COLS, LINES-headerHeight-1); Panel_resize(panel, COLS, LINES-headerHeight-1);
if (incSearchMode) if (incMode)
FunctionBar_draw(searchBar, incSearchBuffer); FunctionBar_draw(incMode->bar, incMode->buffer);
else else
FunctionBar_draw(defaultBar, NULL); FunctionBar_draw(defaultBar, NULL);
break; break;
@ -653,11 +698,11 @@ int main(int argc, char** argv) {
if (picked) { if (picked) {
if (picked == allUsers) { if (picked == allUsers) {
userOnly = false; userOnly = false;
break;
} else { } else {
setUserOnly(ListItem_getRef(picked), &userOnly, &userId); setUserOnly(ListItem_getRef(picked), &userOnly, &userId);
} }
} }
Panel_delete((Object*)usersPanel);
break; break;
} }
case '+': case '+':
@ -773,7 +818,6 @@ int main(int argc, char** argv) {
break; break;
} }
case 'I': case 'I':
case KEY_F(4):
{ {
refreshTimeout = 0; refreshTimeout = 0;
settings->changed = true; settings->changed = true;
@ -794,11 +838,17 @@ int main(int argc, char** argv) {
} }
case KEY_F(3): case KEY_F(3):
case '/': case '/':
incSearchIndex = 0; incMode = &incSearch;
incSearchBuffer[0] = 0; IncBuffer_reset(incMode);
incSearchMode = true; FunctionBar_draw(incSearch.bar, incSearch.buffer);
FunctionBar_draw(searchBar, incSearchBuffer);
break; break;
case KEY_F(4):
case '\\':
incMode = &incFilter;
refreshTimeout = 0;
doRefresh = true;
FunctionBar_draw(incFilter.bar, incFilter.buffer);
continue;
case 't': case 't':
case KEY_F(5): case KEY_F(5):
refreshTimeout = 0; refreshTimeout = 0;
@ -837,9 +887,10 @@ int main(int argc, char** argv) {
Settings_write(settings); Settings_write(settings);
Header_delete(header); Header_delete(header);
ProcessList_delete(pl); ProcessList_delete(pl);
FunctionBar_delete((Object*)searchBar); FunctionBar_delete((Object*)incFilter.bar);
FunctionBar_delete((Object*)incSearch.bar);
FunctionBar_delete((Object*)defaultBar); FunctionBar_delete((Object*)defaultBar);
((Object*)panel)->delete((Object*)panel); Panel_delete((Object*)panel);
if (killPanel) if (killPanel)
((Object*)killPanel)->delete((Object*)killPanel); ((Object*)killPanel)->delete((Object*)killPanel);
UsersTable_delete(ut); UsersTable_delete(ut);

2
htop.h
View File

@ -43,6 +43,8 @@ in the source distribution for its full text.
#define COPYRIGHT "(C) 2004-2011 Hisham Muhammad" #define COPYRIGHT "(C) 2004-2011 Hisham Muhammad"
typedef struct IncBuffer_;
int main(int argc, char** argv); int main(int argc, char** argv);
#endif #endif