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.main
parent
5233817122
commit
f4bb50294a
5 changed files with 108 additions and 3 deletions
@ -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)); |
||||
} |
||||
@ -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 |
||||
Loading…
Reference in new issue