From 20e6856e01935db84d8a72bb4b748aa2d7647c54 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Thu, 11 Jan 2018 01:27:16 -0200 Subject: [PATCH] Initial support for (still stale) plugin columns This allows plugins to add columns, but they don't update their values yet. --- API.c | 77 +++++++++++++++++++++++++++++++++++++++++ API.h | 39 +++++++++++++++++++++ AvailableColumnsPanel.c | 41 ++++++++++++++++++++-- AvailableColumnsPanel.h | 6 +++- CategoriesPanel.c | 2 +- ColumnsPanel.c | 2 +- Makefile.am | 4 +-- Process.c | 14 ++++++++ Process.h | 1 + ProcessList.c | 39 +++++++++++++-------- ProcessList.h | 1 + Settings.c | 10 ++++++ Settings.h | 10 ++++++ htop.c | 1 + 14 files changed, 226 insertions(+), 21 deletions(-) create mode 100644 API.c create mode 100644 API.h diff --git a/API.c b/API.c new file mode 100644 index 0000000..8eecbf4 --- /dev/null +++ b/API.c @@ -0,0 +1,77 @@ + +#include "config.h" +#include "API.h" +#include "Process.h" + +#ifdef HAVE_LUA + +/*{ + +#include +#include +#include + +#define check_field(_name, _type, _err) \ + do { \ + int typ = lua_getfield(L, 1, _name); \ + if (typ != _type) { \ + lua_settop(L, 0); \ + lua_pushnil(L); \ + lua_pushliteral(L, _err); \ + return 2; \ + } \ + lua_pop(L, 1); \ + } while(0) + +#define assign_string(_var, _idx, _field) \ + do { \ + lua_getfield(L, _idx, _field); \ + _var = xStrdup(lua_tostring(L, -1)); \ + lua_pop(L, 1); \ + } while(0) + +}*/ + +int API_newColumn(lua_State* L) { + luaL_checktype(L, 1, LUA_TTABLE); + + check_field("name", LUA_TSTRING, "expected 'name' field of type string"); + check_field("description", LUA_TSTRING, "expected 'description' field of type string"); + check_field("header", LUA_TSTRING, "expected 'header' field of type string"); + check_field("format", LUA_TSTRING, "expected 'format' field of type string"); + check_field("run", LUA_TFUNCTION, "expected 'run' field of type function"); + + lua_getfield(L, LUA_REGISTRYINDEX, "htop_columns"); + lua_len(L, -1); + int len = lua_tonumber(L, -1); + lua_pop(L, 1); + ProcessFieldData* pfd = lua_newuserdata(L, sizeof(ProcessFieldData)); + + assign_string(pfd->name, 1, "name"); + assign_string(pfd->description, 1, "description"); + assign_string(pfd->title, 1, "header"); + assign_string(pfd->format, 1, "format"); + + lua_seti(L, -2, len + 1); + lua_settop(L, 0); + lua_pushboolean(L, 1); + return 1; +} + +static luaL_Reg API_functions[] = { + { .name = "new_column", .func = API_newColumn }, + { .name = NULL, .func = NULL }, +}; + +int API_new(lua_State* L) { + lua_settop(L, 0); + + lua_newtable(L); + lua_setfield(L, LUA_REGISTRYINDEX, "htop_columns"); + + lua_newtable(L); + luaL_setfuncs(L, API_functions, 0); + return 1; +} + +#endif diff --git a/API.h b/API.h new file mode 100644 index 0000000..5efd171 --- /dev/null +++ b/API.h @@ -0,0 +1,39 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_API +#define HEADER_API + +#ifdef HAVE_LUA + + +#include +#include +#include + +#define check_field(_name, _type, _err) \ + do { \ + int typ = lua_getfield(L, 1, _name); \ + if (typ != _type) { \ + lua_settop(L, 0); \ + lua_pushnil(L); \ + lua_pushliteral(L, _err); \ + return 2; \ + } \ + lua_pop(L, 1); \ + } while(0) + +#define assign_string(_var, _idx, _field) \ + do { \ + lua_getfield(L, _idx, _field); \ + _var = xStrdup(lua_tostring(L, -1)); \ + lua_pop(L, 1); \ + } while(0) + + +int API_newColumn(lua_State* L); + +int API_new(lua_State* L); + +#endif + +#endif diff --git a/AvailableColumnsPanel.c b/AvailableColumnsPanel.c index 1e548dc..1ca35cb 100644 --- a/AvailableColumnsPanel.c +++ b/AvailableColumnsPanel.c @@ -18,10 +18,14 @@ in the source distribution for its full text. /*{ #include "Panel.h" +#include "ProcessList.h" typedef struct AvailableColumnsPanel_ { Panel super; Panel* columns; + #ifdef HAVE_LUA + lua_State* L; + #endif } AvailableColumnsPanel; }*/ @@ -46,7 +50,22 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) { case KEY_F(5): { int at = Panel_getSelectedIndex(this->columns); - Panel_insert(this->columns, at, (Object*) ListItem_new(Process_fields[key].name, key)); + ListItem* item; + #ifdef HAVE_LUA + if (key > 1000) { + + lua_State* L = this->L; + lua_getfield(L, LUA_REGISTRYINDEX, "htop_columns"); + lua_geti(L, -1, key - 1000); + ProcessFieldData* pfd = (ProcessFieldData*) lua_touserdata(L, -1); + item = ListItem_new(pfd->name, key); + lua_pop(L, 2); + } else + #endif + { + item = ListItem_new(Process_fields[key].name, key); + } + Panel_insert(this->columns, at, (Object*) item); Panel_setSelected(this->columns, at+1); ColumnsPanel_update(this->columns); result = HANDLED; @@ -70,7 +89,7 @@ PanelClass AvailableColumnsPanel_class = { .eventHandler = AvailableColumnsPanel_eventHandler }; -AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) { +AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, ProcessList* pl) { AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel); Panel* super = (Panel*) this; FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL); @@ -85,6 +104,24 @@ AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) { Panel_add(super, (Object*) ListItem_new(description, i)); } } + #ifdef HAVE_LUA + lua_State* L = pl->L; + this->L = L; + int top = lua_gettop(L); + lua_getfield(L, LUA_REGISTRYINDEX, "htop_columns"); + lua_len(L, -1); + int len = lua_tointeger(L, -1); + lua_pop(L, 1); + for (int a = 1; a <= len; a++) { + lua_geti(L, -1, a); + ProcessFieldData* pfd = (ProcessFieldData*) lua_touserdata(L, -1); + char description[256]; + xSnprintf(description, sizeof(description), "%s - %s", pfd->name, pfd->description); + Panel_add(super, (Object*) ListItem_new(description, 1000 + a)); + lua_pop(L, 1); + } + lua_settop(L, top); + #endif this->columns = columns; return this; } diff --git a/AvailableColumnsPanel.h b/AvailableColumnsPanel.h index 5a8371d..651762e 100644 --- a/AvailableColumnsPanel.h +++ b/AvailableColumnsPanel.h @@ -10,15 +10,19 @@ in the source distribution for its full text. */ #include "Panel.h" +#include "ProcessList.h" typedef struct AvailableColumnsPanel_ { Panel super; Panel* columns; + #ifdef HAVE_LUA + lua_State* L; + #endif } AvailableColumnsPanel; extern PanelClass AvailableColumnsPanel_class; -AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns); +AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, ProcessList* pl); #endif diff --git a/CategoriesPanel.c b/CategoriesPanel.c index 437f1a7..3440bf8 100644 --- a/CategoriesPanel.c +++ b/CategoriesPanel.c @@ -66,7 +66,7 @@ static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) { static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) { Panel* columns = (Panel*) ColumnsPanel_new(this->settings); - Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns); + Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns, this->pl); ScreenManager_add(this->scr, columns, 20); ScreenManager_add(this->scr, availableColumns, -1); } diff --git a/ColumnsPanel.c b/ColumnsPanel.c index 8974ffd..babec52 100644 --- a/ColumnsPanel.c +++ b/ColumnsPanel.c @@ -160,7 +160,7 @@ void ColumnsPanel_update(Panel* super) { for (int i = 0; i < size; i++) { int key = ((ListItem*) Panel_get(super, i))->key; this->settings->fields[i] = key; - this->settings->flags |= Process_fields[key].flags; + this->settings->flags |= key < 1000 ? Process_fields[key].flags : 0; } this->settings->fields[size] = 0; } diff --git a/Makefile.am b/Makefile.am index bf46f45..8660697 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,7 +37,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 XAlloc.c API.c myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \ CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \ @@ -47,7 +47,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 +EnvScreen.h InfoScreen.h XAlloc.h API.h if HTOP_LINUX htop_CFLAGS += -rdynamic diff --git a/Process.c b/Process.c index 6551afd..bf9d8ca 100644 --- a/Process.c +++ b/Process.c @@ -150,6 +150,7 @@ typedef struct ProcessFieldData_ { const char* name; const char* title; const char* description; + const char* format; int flags; } ProcessFieldData; @@ -367,6 +368,19 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { int n = sizeof(buffer) - 1; bool coloring = this->settings->highlightMegabytes; + #ifdef HAVE_LUA + if (field > 1000) { + lua_State* L = this->settings->L; + lua_getfield(L, LUA_REGISTRYINDEX, "htop_columns"); + lua_geti(L, -1, field - 1000); + ProcessFieldData* pfd = (ProcessFieldData*) lua_touserdata(L, -1); + xSnprintf(buffer, n, pfd->format, 123); + lua_pop(L, 2); + RichString_append(str, attr, buffer); + return; + } + #endif + switch (field) { case PERCENT_CPU: { if (this->percent_cpu > 999.9) { diff --git a/Process.h b/Process.h index 5b8ffdb..4a93752 100644 --- a/Process.h +++ b/Process.h @@ -129,6 +129,7 @@ typedef struct ProcessFieldData_ { const char* name; const char* title; const char* description; + const char* format; int flags; } ProcessFieldData; diff --git a/ProcessList.c b/ProcessList.c index 1fc43ae..03b778b 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -10,6 +10,7 @@ in the source distribution for its full text. #include "CRT.h" #include "StringUtils.h" +#include "API.h" #include #include @@ -136,26 +137,22 @@ void ProcessList_done(ProcessList* this) { } #ifdef HAVE_LUA + void ProcessList_initScripting(ProcessList* this) { lua_State* L = luaL_newstate(); luaL_openlibs(L); this->L = L; - lua_newtable(L); - lua_pushvalue(L, 1); - lua_setglobal(L, "htop"); + luaL_requiref(L, "htop", API_new, 0); + lua_pop(L, 1); for (int i = 0; i < this->settings->nPlugins; i++) { char* plugin = this->settings->plugins[i]; lua_getglobal(L, "require"); lua_pushliteral(L, "htop-plugins."); lua_pushstring(L, plugin); lua_concat(L, 2); - int ok = lua_pcall(L, 1, 1, 0); - if (ok == LUA_OK) { - lua_setfield(L, 1, plugin); - } else { - lua_pop(L, 1); - } + lua_pcall(L, 1, 1, 0); + lua_pop(L, 1); } } #endif @@ -168,12 +165,26 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) { RichString_prune(header); ProcessField* fields = this->settings->fields; for (int i = 0; fields[i]; i++) { - const char* field = Process_fields[fields[i]].title; + unsigned int key = fields[i]; + const char* field; + #ifdef HAVE_LUA + if (key > 1000) { + lua_State* L = this->L; + lua_getfield(L, LUA_REGISTRYINDEX, "htop_columns"); + lua_geti(L, -1, key - 1000); + ProcessFieldData* pfd = (ProcessFieldData*) lua_touserdata(L, -1); + field = pfd->title; + lua_pop(L, 2); + } else + #endif + { + field = Process_fields[key].title; + } if (!field) field = "- "; - if (!this->settings->treeView && this->settings->sortKey == fields[i]) - RichString_append(header, CRT_colors[PANEL_SELECTION_FOCUS], field); - else - RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field); + int color = (!this->settings->treeView && this->settings->sortKey == key) + ? CRT_colors[PANEL_SELECTION_FOCUS] + : CRT_colors[PANEL_HEADER_FOCUS]; + RichString_append(header, color, field); } } diff --git a/ProcessList.h b/ProcessList.h index a627511..5da497e 100644 --- a/ProcessList.h +++ b/ProcessList.h @@ -90,6 +90,7 @@ ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* void ProcessList_done(ProcessList* this); #ifdef HAVE_LUA + void ProcessList_initScripting(ProcessList* this); #endif diff --git a/Settings.c b/Settings.c index 9723e15..7e574c0 100644 --- a/Settings.c +++ b/Settings.c @@ -23,6 +23,12 @@ in the source distribution for its full text. #include "Process.h" #include +#ifdef HAVE_LUA +#include +#include +#include +#endif + typedef struct { int len; char** names; @@ -32,6 +38,10 @@ typedef struct { typedef struct Settings_ { char* filename; + #ifdef HAVE_LUA + lua_State* L; + #endif + MeterColumnSettings columns[2]; char** plugins; diff --git a/Settings.h b/Settings.h index 2efe273..91948b0 100644 --- a/Settings.h +++ b/Settings.h @@ -14,6 +14,12 @@ in the source distribution for its full text. #include "Process.h" #include +#ifdef HAVE_LUA +#include +#include +#include +#endif + typedef struct { int len; char** names; @@ -23,6 +29,10 @@ typedef struct { typedef struct Settings_ { char* filename; + #ifdef HAVE_LUA + lua_State* L; + #endif + MeterColumnSettings columns[2]; char** plugins; diff --git a/htop.c b/htop.c index 94b8ae7..e15970f 100644 --- a/htop.c +++ b/htop.c @@ -197,6 +197,7 @@ int main(int argc, char** argv) { #ifdef HAVE_LUA ProcessList_initScripting(pl); + settings->L = pl->L; #endif Header* header = Header_new(pl, settings, 2); -- GitLab