mirror of https://github.com/xzeldon/htop.git
parent
3f3213b2e2
commit
11092662ee
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
131
htop.c
131
htop.c
|
@ -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;
|
||||||
|
@ -334,12 +345,7 @@ int main(int argc, char** argv) {
|
||||||
Settings* settings;
|
Settings* settings;
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
@ -364,13 +370,25 @@ int main(int argc, char** argv) {
|
||||||
pl->direction = 1;
|
pl->direction = 1;
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
const char* defaultFunctions[] = {"Help ", "Setup ", "Search", "Invert", "Tree ",
|
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);
|
||||||
|
|
Loading…
Reference in New Issue