Commit 20e6856e authored by Hisham Muhammad's avatar Hisham Muhammad
Browse files

Initial support for (still stale) plugin columns

This allows plugins to add columns, but they don't update
their values yet.
parent df003a63
#include "config.h"
#include "API.h"
#include "Process.h"
#ifdef HAVE_LUA
/*{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#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
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_API
#define HEADER_API
#ifdef HAVE_LUA
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#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
...@@ -18,10 +18,14 @@ in the source distribution for its full text. ...@@ -18,10 +18,14 @@ in the source distribution for its full text.
/*{ /*{
#include "Panel.h" #include "Panel.h"
#include "ProcessList.h"
typedef struct AvailableColumnsPanel_ { typedef struct AvailableColumnsPanel_ {
Panel super; Panel super;
Panel* columns; Panel* columns;
#ifdef HAVE_LUA
lua_State* L;
#endif
} AvailableColumnsPanel; } AvailableColumnsPanel;
}*/ }*/
...@@ -46,7 +50,22 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) { ...@@ -46,7 +50,22 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
case KEY_F(5): case KEY_F(5):
{ {
int at = Panel_getSelectedIndex(this->columns); 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); Panel_setSelected(this->columns, at+1);
ColumnsPanel_update(this->columns); ColumnsPanel_update(this->columns);
result = HANDLED; result = HANDLED;
...@@ -70,7 +89,7 @@ PanelClass AvailableColumnsPanel_class = { ...@@ -70,7 +89,7 @@ PanelClass AvailableColumnsPanel_class = {
.eventHandler = AvailableColumnsPanel_eventHandler .eventHandler = AvailableColumnsPanel_eventHandler
}; };
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) { AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, ProcessList* pl) {
AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel); AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel);
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL); FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL);
...@@ -85,6 +104,24 @@ AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) { ...@@ -85,6 +104,24 @@ AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) {
Panel_add(super, (Object*) ListItem_new(description, i)); 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; this->columns = columns;
return this; return this;
} }
...@@ -10,15 +10,19 @@ in the source distribution for its full text. ...@@ -10,15 +10,19 @@ in the source distribution for its full text.
*/ */
#include "Panel.h" #include "Panel.h"
#include "ProcessList.h"
typedef struct AvailableColumnsPanel_ { typedef struct AvailableColumnsPanel_ {
Panel super; Panel super;
Panel* columns; Panel* columns;
#ifdef HAVE_LUA
lua_State* L;
#endif
} AvailableColumnsPanel; } AvailableColumnsPanel;
extern PanelClass AvailableColumnsPanel_class; extern PanelClass AvailableColumnsPanel_class;
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns); AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, ProcessList* pl);
#endif #endif
...@@ -66,7 +66,7 @@ static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) { ...@@ -66,7 +66,7 @@ static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) { static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) {
Panel* columns = (Panel*) ColumnsPanel_new(this->settings); 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, columns, 20);
ScreenManager_add(this->scr, availableColumns, -1); ScreenManager_add(this->scr, availableColumns, -1);
} }
......
...@@ -160,7 +160,7 @@ void ColumnsPanel_update(Panel* super) { ...@@ -160,7 +160,7 @@ void ColumnsPanel_update(Panel* super) {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
int key = ((ListItem*) Panel_get(super, i))->key; int key = ((ListItem*) Panel_get(super, i))->key;
this->settings->fields[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; this->settings->fields[size] = 0;
} }
......
...@@ -37,7 +37,7 @@ BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \ ...@@ -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 \ SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c \
TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \ TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.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 \ myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.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 ...@@ -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 \ ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h \
TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.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 \ 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 if HTOP_LINUX
htop_CFLAGS += -rdynamic htop_CFLAGS += -rdynamic
......
...@@ -150,6 +150,7 @@ typedef struct ProcessFieldData_ { ...@@ -150,6 +150,7 @@ typedef struct ProcessFieldData_ {
const char* name; const char* name;
const char* title; const char* title;
const char* description; const char* description;
const char* format;
int flags; int flags;
} ProcessFieldData; } ProcessFieldData;
...@@ -367,6 +368,19 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { ...@@ -367,6 +368,19 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
int n = sizeof(buffer) - 1; int n = sizeof(buffer) - 1;
bool coloring = this->settings->highlightMegabytes; 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) { switch (field) {
case PERCENT_CPU: { case PERCENT_CPU: {
if (this->percent_cpu > 999.9) { if (this->percent_cpu > 999.9) {
......
...@@ -129,6 +129,7 @@ typedef struct ProcessFieldData_ { ...@@ -129,6 +129,7 @@ typedef struct ProcessFieldData_ {
const char* name; const char* name;
const char* title; const char* title;
const char* description; const char* description;
const char* format;
int flags; int flags;
} ProcessFieldData; } ProcessFieldData;
......
...@@ -10,6 +10,7 @@ in the source distribution for its full text. ...@@ -10,6 +10,7 @@ in the source distribution for its full text.
#include "CRT.h" #include "CRT.h"
#include "StringUtils.h" #include "StringUtils.h"
#include "API.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
...@@ -136,26 +137,22 @@ void ProcessList_done(ProcessList* this) { ...@@ -136,26 +137,22 @@ void ProcessList_done(ProcessList* this) {
} }
#ifdef HAVE_LUA #ifdef HAVE_LUA
void ProcessList_initScripting(ProcessList* this) { void ProcessList_initScripting(ProcessList* this) {
lua_State* L = luaL_newstate(); lua_State* L = luaL_newstate();
luaL_openlibs(L); luaL_openlibs(L);
this->L = L; this->L = L;
lua_newtable(L); luaL_requiref(L, "htop", API_new, 0);
lua_pushvalue(L, 1); lua_pop(L, 1);
lua_setglobal(L, "htop");
for (int i = 0; i < this->settings->nPlugins; i++) { for (int i = 0; i < this->settings->nPlugins; i++) {
char* plugin = this->settings->plugins[i]; char* plugin = this->settings->plugins[i];
lua_getglobal(L, "require"); lua_getglobal(L, "require");
lua_pushliteral(L, "htop-plugins."); lua_pushliteral(L, "htop-plugins.");
lua_pushstring(L, plugin); lua_pushstring(L, plugin);
lua_concat(L, 2); lua_concat(L, 2);
int ok = lua_pcall(L, 1, 1, 0); lua_pcall(L, 1, 1, 0);
if (ok == LUA_OK) { lua_pop(L, 1);
lua_setfield(L, 1, plugin);
} else {
lua_pop(L, 1);
}
} }
} }
#endif #endif
...@@ -168,12 +165,26 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) { ...@@ -168,12 +165,26 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) {
RichString_prune(header); RichString_prune(header);
ProcessField* fields = this->settings->fields; ProcessField* fields = this->settings->fields;
for (int i = 0; fields[i]; i++) { 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 (!field) field = "- ";
if (!this->settings->treeView && this->settings->sortKey == fields[i]) int color = (!this->settings->treeView && this->settings->sortKey == key)
RichString_append(header, CRT_colors[PANEL_SELECTION_FOCUS], field); ? CRT_colors[PANEL_SELECTION_FOCUS]
else : CRT_colors[PANEL_HEADER_FOCUS];
RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field); RichString_append(header, color, field);
} }
} }
......
...@@ -90,6 +90,7 @@ ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* ...@@ -90,6 +90,7 @@ ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable*
void ProcessList_done(ProcessList* this); void ProcessList_done(ProcessList* this);
#ifdef HAVE_LUA #ifdef HAVE_LUA
void ProcessList_initScripting(ProcessList* this); void ProcessList_initScripting(ProcessList* this);
#endif #endif
......
...@@ -23,6 +23,12 @@ in the source distribution for its full text. ...@@ -23,6 +23,12 @@ in the source distribution for its full text.
#include "Process.h" #include "Process.h"
#include <stdbool.h> #include <stdbool.h>
#ifdef HAVE_LUA
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#endif
typedef struct { typedef struct {
int len; int len;
char** names; char** names;
...@@ -32,6 +38,10 @@ typedef struct { ...@@ -32,6 +38,10 @@ typedef struct {
typedef struct Settings_ { typedef struct Settings_ {
char* filename; char* filename;
#ifdef HAVE_LUA
lua_State* L;
#endif
MeterColumnSettings columns[2]; MeterColumnSettings columns[2];
char** plugins; char** plugins;
......
...@@ -14,6 +14,12 @@ in the source distribution for its full text. ...@@ -14,6 +14,12 @@ in the source distribution for its full text.
#include "Process.h" #include "Process.h"
#include <stdbool.h> #include <stdbool.h>
#ifdef HAVE_LUA
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#endif
typedef struct { typedef struct {
int len; int len;
char** names; char** names;
...@@ -23,6 +29,10 @@ typedef struct { ...@@ -23,6 +29,10 @@ typedef struct {
typedef struct Settings_ { typedef struct Settings_ {
char* filename; char* filename;
#ifdef HAVE_LUA
lua_State* L;
#endif
MeterColumnSettings columns[2]; MeterColumnSettings columns[2];
char** plugins; char** plugins;
......
...@@ -197,6 +197,7 @@ int main(int argc, char** argv) { ...@@ -197,6 +197,7 @@ int main(int argc, char** argv) {
#ifdef HAVE_LUA #ifdef HAVE_LUA
ProcessList_initScripting(pl); ProcessList_initScripting(pl);
settings->L = pl->L;
#endif #endif
Header* header = Header_new(pl, settings, 2); Header* header = Header_new(pl, settings, 2);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment