From 37bd818dc2479082df14e9875f361b03e70ab1f0 Mon Sep 17 00:00:00 2001
From: Abanoub Sameh <abanoubsameh@...>
Date: Mon, 31 May 2021 19:33:49 +0200
Subject: [PATCH] Add vim visual mode behavior
This patch adds vim visual mode behavior, it enables the user to move
around and select processes, like selecting lines in vim.
It is not perfect because in vim lines don't usually change on their own,
meanwhile, in htop, they do. But I think that this would be good enough
for vim users.
Another patch can make it more consistant, but would sacrifice performance,
because we need to (periodically) check each line between the current and
the first selected line and make sure all lines in between are also select.
Signed-off-by: Abanoub Sameh <abanoubsameh@...>
---
Action.c | 43 +++++++++++++++++++++++++++++++------------
Action.h | 8 ++++++++
MainPanel.c | 4 +++-
Panel.c | 16 ++++++++++++++++
4 files changed, 58 insertions(+), 13 deletions(-)
diff --git a/Action.c b/Action.c
index 1810871..2ace84d 100644
--- a/Action.c
+++ b/Action.c
@@ -40,6 +40,8 @@ in the source distribution for its full text.
#endif
+static int selectMode = -1;
+
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) {
MainPanel* mainPanel = st->mainPanel;
Header* header = st->header;
@@ -427,14 +429,14 @@ static Htop_Reaction actionStrace(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
-static Htop_Reaction actionTag(State* st) {
- Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
+// this function can be removed
+void actionTag(Panel* p) {
+ Process* pan = (Process*) Panel_getSelected(p);
if (!p)
- return HTOP_OK;
+ return;
- Process_toggleTag(p);
- Panel_onKey((Panel*)st->mainPanel, KEY_DOWN);
- return HTOP_OK;
+ Process_toggleTag(pan);
+ //Panel_onKey((Panel*)st->mainPanel, KEY_DOWN);
}
static Htop_Reaction actionRedraw(ATTR_UNUSED State* st) {
@@ -606,12 +608,12 @@ static Htop_Reaction actionHelp(State* st) {
return HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_KEEP_FOLLOWING;
}
-static Htop_Reaction actionUntagAll(State* st) {
- for (int i = 0; i < Panel_size((Panel*)st->mainPanel); i++) {
- Process* p = (Process*) Panel_get((Panel*)st->mainPanel, i);
+// this can be deleted
+void actionUntagAll(Panel* panel) {
+ for (int i = 0; i < Panel_size(panel); i++) {
+ Process* p = (Process*) Panel_get(panel, i);
p->tag = false;
}
- return HTOP_REFRESH;
}
static Htop_Reaction actionTagAllChildren(State* st) {
@@ -649,8 +651,26 @@ static Htop_Reaction actionShowCommandScreen(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
+static Htop_Reaction enableSelect(State *st) {
+ if (selectMode == -1)
+ selectMode = ((Panel*)st->mainPanel)->selected;
+ // if actionTag is deleted, maybe do its function once here
+ actionTag(((Panel*)st->mainPanel));
+ return HTOP_OK;
+}
+
+void disableSelect(Panel *p) {
+ selectMode = -1;
+ // if actionUntagAll is deleted, make sure to add its fuctionally here
+ actionUntagAll(p);
+}
+
+int getSelectMode(void) {
+ return selectMode;
+}
+
void Action_setBindings(Htop_Action* keys) {
- keys[' '] = actionTag;
+ keys['v'] = enableSelect;
keys['*'] = actionExpandOrCollapseAllBranches;
keys['+'] = actionExpandOrCollapse;
keys[','] = actionSetSortColumn;
@@ -671,7 +691,6 @@ void Action_setBindings(Htop_Action* keys) {
keys['P'] = actionSortByCPU;
keys['S'] = actionSetup;
keys['T'] = actionSortByTime;
- keys['U'] = actionUntagAll;
keys['Z'] = actionTogglePauseProcessUpdate;
keys['['] = actionLowerPriority;
keys['\014'] = actionRedraw; // Ctrl+L
diff --git a/Action.h b/Action.h
index 8e86569..67b28fc 100644
--- a/Action.h
+++ b/Action.h
@@ -58,6 +58,14 @@ Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
Htop_Reaction Action_follow(State* st);
+void actionTag(Panel* p);
+
+void actionUntagAll(Panel* panel);
+
+int getSelectMode(void);
+
+void disableSelect(Panel *p);
+
void Action_setBindings(Htop_Action* keys);
#endif
diff --git a/MainPanel.c b/MainPanel.c
index 5a75af3..aa0af4a 100644
--- a/MainPanel.c
+++ b/MainPanel.c
@@ -11,6 +11,7 @@ in the source distribution for its full text.
#include <ctype.h>
#include <stdlib.h>
+#include "Action.h"
#include "CRT.h"
#include "FunctionBar.h"
#include "Platform.h"
@@ -94,7 +95,8 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
}
result = HANDLED;
} else if (ch == 27) {
- this->state->hideProcessSelection = true;
+ //this->state->hideProcessSelection = true;
+ disableSelect(super);
return HANDLED;
} else if (ch != ERR && ch > 0 && ch < KEY_MAX && this->keys[ch]) {
reaction |= (this->keys[ch])(this->state);
diff --git a/Panel.c b/Panel.c
index 832dfb4..813bca9 100644
--- a/Panel.c
+++ b/Panel.c
@@ -14,6 +14,7 @@ in the source distribution for its full text.
#include <string.h>
#include <strings.h>
+#include "Action.h"
#include "CRT.h"
#include "ListItem.h"
#include "Macros.h"
@@ -337,6 +338,17 @@ static int Panel_headerHeight(const Panel* this) {
return RichString_sizeVal(this->header) > 0 ? 1 : 0;
}
+static void fixTags(const Panel *this, int direction) {
+ Process *pan = (Process*) Panel_getSelected((Panel*)this);
+
+ if (this->selected > getSelectMode() && direction == 1)
+ pan->tag = false;
+ else if (this->selected < getSelectMode() && direction == 0)
+ pan->tag = false;
+ else
+ pan->tag = true;
+}
+
bool Panel_onKey(Panel* this, int key) {
assert (this != NULL);
@@ -355,6 +367,8 @@ bool Panel_onKey(Panel* this, int key) {
#ifdef KEY_C_DOWN
case KEY_C_DOWN:
#endif
+ if (getSelectMode() != -1)
+ fixTags(this, 0);
this->selected++;
break;
@@ -363,6 +377,8 @@ bool Panel_onKey(Panel* this, int key) {
#ifdef KEY_C_UP
case KEY_C_UP:
#endif
+ if (getSelectMode() != -1)
+ fixTags(this, 1);
this->selected--;
break;
--
2.31.1