summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorryenus <ryenus@gmail.com>2017-08-03 17:43:28 +0800
committercgzones <cgzones@googlemail.com>2020-09-24 19:22:25 +0200
commitf4bb50294a31c0d46dbcd742c4002f4fbb20d2a8 (patch)
tree4ea66a688d2967e80888c5c73edb801668b2de60
parent52338171220af1ff009ea30114a290c80847b2dd (diff)
show selected command wrapped in a separate window
For a process with a very long command, especially with many long command line arguments, inspecting the command and its arguments could become inconvenient. Meanwhile htop supports the concept of "screen", or window, which is extended here to create a dedicated "CommandScreen", making it possible to display the command of the selected process in a separate window meanwhile being wrapped into multiple lines. Another benefit of using a command screen is, the user can navigate through the wrapped lines of the command and perform actions like searching and filtering.
-rw-r--r--Action.c14
-rw-r--r--CommandScreen.c74
-rw-r--r--CommandScreen.h16
-rw-r--r--Makefile.am4
-rw-r--r--htop.1.in3
5 files changed, 108 insertions, 3 deletions
diff --git a/Action.c b/Action.c
index eac7f1f6..f36e0bd2 100644
--- a/Action.c
+++ b/Action.c
@@ -13,6 +13,7 @@ in the source distribution for its full text.
#include "CategoriesPanel.h"
#include "CRT.h"
#include "EnvScreen.h"
+#include "CommandScreen.h"
#include "MainPanel.h"
#include "OpenFilesScreen.h"
#include "Process.h"
@@ -422,8 +423,8 @@ static const struct { const char* key; const char* info; } helpRight[] = {
{ .key = " e: ", .info = "show process environment" },
{ .key = " i: ", .info = "set IO priority" },
{ .key = " l: ", .info = "list open files with lsof" },
+ { .key = " M: ", .info = "show process command in multiple lines" },
{ .key = " s: ", .info = "trace syscalls with strace" },
- { .key = " ", .info = "" },
{ .key = " F2 C S: ", .info = "setup" },
{ .key = " F1 h: ", .info = "show this help screen" },
{ .key = " F10 q: ", .info = "quit" },
@@ -530,6 +531,16 @@ static Htop_Reaction actionShowEnvScreen(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
+static Htop_Reaction actionShowCommandScreen(State* st) {
+ Process* p = (Process*) Panel_getSelected(st->panel);
+ if (!p) return HTOP_OK;
+ CommandScreen* cmdScr = CommandScreen_new(p);
+ InfoScreen_run((InfoScreen*)cmdScr);
+ CommandScreen_delete((Object*)cmdScr);
+ clear();
+ CRT_enableDelay();
+ return HTOP_REFRESH | HTOP_REDRAW_BAR;
+}
void Action_setBindings(Htop_Action* keys) {
keys[KEY_RESIZE] = actionResize;
@@ -584,4 +595,5 @@ void Action_setBindings(Htop_Action* keys) {
keys['U'] = actionUntagAll;
keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen;
+ keys['M'] = actionShowCommandScreen;
}
diff --git a/CommandScreen.c b/CommandScreen.c
new file mode 100644
index 00000000..0e261175
--- /dev/null
+++ b/CommandScreen.c
@@ -0,0 +1,74 @@
+#include "CommandScreen.h"
+
+#include "config.h"
+#include "CRT.h"
+#include "IncSet.h"
+#include "ListItem.h"
+#include "Platform.h"
+#include "StringUtils.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static void CommandScreen_addLine(InfoScreen* this, char* line, const char* p, int line_offset, int len) {
+ memcpy(line, p - line_offset, len);
+ line[len] = '\0';
+ InfoScreen_addLine(this, line);
+}
+
+static void CommandScreen_scan(InfoScreen* this) {
+ Panel* panel = this->display;
+ int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
+
+ Panel_prune(panel);
+
+ const char* p = this->process->comm;
+ char* line = xMalloc(COLS + 1);
+ int line_offset = 0, last_spc = -1, len;
+ for (; *p != '\0'; p++, line_offset++) {
+ if (*p == ' ') last_spc = line_offset;
+
+ if (line_offset == COLS) {
+ len = (last_spc == -1) ? line_offset : last_spc;
+ CommandScreen_addLine(this, line, p, line_offset, len);
+ line_offset -= len;
+ last_spc = -1;
+ }
+ }
+
+ if (line_offset > 0) CommandScreen_addLine(this, line, p, line_offset, line_offset);
+
+ free(line);
+ Panel_setSelected(panel, idx);
+}
+
+static void CommandScreen_draw(InfoScreen* this) {
+ char* title = xMalloc(COLS + 1);
+ int len = snprintf(title, COLS + 1, "Command of process %d - %s", this->process->pid, this->process->comm);
+ if (len > COLS) {
+ memset(&title[COLS - 3], '.', 3);
+ }
+
+ InfoScreen_drawTitled(this, "%s", title);
+ free(title);
+}
+
+InfoScreenClass CommandScreen_class = {
+ .super = {
+ .extends = Class(Object),
+ .delete = CommandScreen_delete
+ },
+ .scan = CommandScreen_scan,
+ .draw = CommandScreen_draw
+};
+
+CommandScreen* CommandScreen_new(Process* process) {
+ CommandScreen* this = AllocThis(CommandScreen);
+ return (CommandScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " ");
+}
+
+void CommandScreen_delete(Object* this) {
+ free(InfoScreen_done((InfoScreen*)this));
+}
diff --git a/CommandScreen.h b/CommandScreen.h
new file mode 100644
index 00000000..a1604a3e
--- /dev/null
+++ b/CommandScreen.h
@@ -0,0 +1,16 @@
+#ifndef HEADER_CommandScreen
+#define HEADER_CommandScreen
+
+#include "InfoScreen.h"
+
+typedef struct CommandScreen_ {
+ InfoScreen super;
+} CommandScreen;
+
+extern InfoScreenClass CommandScreen_class;
+
+CommandScreen* CommandScreen_new(Process* process);
+
+void CommandScreen_delete(Object* this);
+
+#endif
diff --git a/Makefile.am b/Makefile.am
index c97ae938..441ea80e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,7 +22,7 @@ BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c \
TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c \
-InfoScreen.c XAlloc.c
+InfoScreen.c CommandScreen.c XAlloc.c
myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \
@@ -32,7 +32,7 @@ BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h
ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h \
TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \
AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \
-EnvScreen.h InfoScreen.h XAlloc.h Macros.h
+EnvScreen.h InfoScreen.h CommandScreen.h XAlloc.h Macros.h
# Linux
# -----
diff --git a/htop.1.in b/htop.1.in
index 424cc157..215d92c5 100644
--- a/htop.1.in
+++ b/htop.1.in
@@ -116,6 +116,9 @@ update of system calls issued by the process.
Display open files for a process: if lsof(1) is installed, pressing this key
will display the list of file descriptors opened by the process.
.TP
+.B M
+Display the command line of the highlighted process in multiple lines.
+.TP
.B F1, h, ?
Go to the help screen
.TP

© 2014-2024 Faster IT GmbH | imprint | privacy policy