]> granicus.if.org Git - procps-ng/commitdiff
top: extend 'Ctrl' bottom window for focus via tab key
authorJim Warner <james.warner@comcast.net>
Thu, 12 May 2022 05:00:00 +0000 (00:00 -0500)
committerCraig Small <csmall@dropbear.xyz>
Mon, 16 May 2022 10:05:59 +0000 (20:05 +1000)
This commit introduces the 'tab' key which can be used
to highlight individual elements in that bottom 'Ctrl'
window. This can really help when reviewing such data.

[ note, normal ongoing monitoring continues unabated ]

Signed-off-by: Jim Warner <james.warner@comcast.net>
top/top.c
top/top.h

index ed1792cb7647b079d9216caa55b2e4cf2110e5b9..2e45199f482e6520e6c0ebc777118fca9db7082f 100644 (file)
--- a/top/top.c
+++ b/top/top.c
@@ -104,20 +104,25 @@ static int   Screen_cols, Screen_rows, Max_lines;
 
         // these are for the special separate bottom 'window'
 #define      SCREEN_ROWS ( Screen_rows - Bot_rsvd )
-#define      BOT_MAXIMUM  10
-#define      BOT_DELIMIT  -1
-#define      BOT_MISC_NS  +1
+#define      BOT_MAXIMUM  10           // size of tagged item array
+#define      BOT_DELIMIT  -1           // fenchpost with item array
+#define      BOT_UNFOCUS  -1           // tab focus not established
+#define      BOT_TAB_YES  -1           // tab focus could be active
+#define      BOT_MISC_NS  +1           // data for namespaces req'd
         // 1 for horizontal separator
 #define      BOT_RSVD  1
 #define      BOT_KEEP  Bot_func = NULL
 #define      BOT_TOSS  do { Bot_func = NULL; Bot_item[0] = BOT_DELIMIT; \
-                Bot_task = Bot_rsvd = Bot_misc = 0; \
+                Bot_task = Bot_rsvd = Bot_what = 0; \
+                Bot_indx = BOT_UNFOCUS; \
                 } while(0)
 static int   Bot_task,
-             Bot_misc,
+             Bot_what,
              Bot_rsvd,
+             Bot_indx = BOT_UNFOCUS,
              Bot_item[BOT_MAXIMUM] = { BOT_DELIMIT };
-static char *Bot_name;
+static char *Bot_name,
+             Bot_sep;
 static void(*Bot_func)(void);
 
         /* This is really the number of lines needed to display the summary
@@ -4897,29 +4902,65 @@ static inline const char *forest_display (const WIN_t *q, int idx) {
 /*######  Special Separate Bottom Window support  ########################*/
 
         /*
-         * This guy actually draws the bottom window, |
-         * including the contents passed as a string. | */
-static void bot_do_see (const char *str, const char *pgm) {
+         * This guy actually draws the parsed strings |
+         * including adding a highlight if necessary. | */
+static void bot_do (const char *str, int focus) {
+   while (*str == ' ') putchar(*(str++));
+   putp(fmtmk("%s%s%s"
+      , focus ? Cap_reverse : Cap_norm
+      , str
+      , Cap_norm));
+} // end: bot_do
+
+
+        /*
+         * This guy draws that bottom window's header |
+         * then parses/arranges to show the contents. |
+         * ( returns the number of elements printed ) | */
+static int bot_focus (const char *hdr, const char *str) {
  #define maxRSVD ( Screen_rows - 1 )
-   char buf[SMLBUFSIZ];
+   static char sav[BIGBUFSIZ*2];
+   const char *end, *beg;
+   char tmp[SCREENMAX];
+   int n, x;
 
-   snprintf(buf, sizeof(buf), "%s for pid %d, %s"
-      , Bot_name, Bot_task, pgm);
-   if (!str || !*str || !strcmp(str, "-")) str = "n/a";
-   Bot_rsvd = 1 + BOT_RSVD + (strlen(str) / Screen_cols);
-   if (Bot_rsvd > maxRSVD) Bot_rsvd = maxRSVD;
-   putp(fmtmk("%s%s%-*s", tg2(0, SCREEN_ROWS), Curwin->capclr_hdr, Screen_cols, buf));
-   putp(fmtmk("%s%s", tg2(0, SCREEN_ROWS + 1), Cap_clr_eos));
-   putp(fmtmk("%s%s", tg2(0, SCREEN_ROWS + 1), Cap_norm));
-   fputs(str, stdout);
+   if (str) {
+      if (!*str || !strcmp(str, "-")) strcpy(sav, "n/a");
+      else memccpy(sav, str, '\0', sizeof(sav) - 1);
+      Bot_rsvd = 1 + BOT_RSVD + (strlen(sav) / Screen_cols);
+      if (Bot_rsvd > maxRSVD) Bot_rsvd = maxRSVD;
+      // caller itself may have used fmtmk, so we'll old school it ...
+      snprintf(tmp, sizeof(tmp), "%s%s%-*s", tg2(0, SCREEN_ROWS), Curwin->capclr_hdr, Screen_cols, hdr);
+      putp(tmp);
+   }
+   // now fmtmk is safe to use ...
+   putp(fmtmk("%s%s%s", tg2(0, SCREEN_ROWS + 1), Cap_clr_eos, Cap_norm));
+
+   beg = &sav[0];
+   x = BOT_UNFOCUS;
+
+   while (*beg) {
+      if (!(end = strchr(beg, Bot_sep)))
+         end = beg + strlen(beg);
+      if ((n = end - beg) >= sizeof(tmp))
+         n = sizeof(tmp) - 1;
+      memccpy(tmp, beg, '\0', n);
+      tmp[n] = '\0';
+      bot_do(tmp, (++x == Bot_indx));
+      if (*(beg += n))
+         putchar(*(beg++));
+      while (*beg == ' ') putchar(*(beg++));
+   }
+   return x;
  #undef maxRSVD
-} // end: bot_do_see
+} // end: bot_focus
 
 
         /*
-         * This guy manages the bottom margin window, |
+         * This guy manages that bottom margin window |
          * showing misc stuff based on a single item. | */
 static void bot_item_show (void) {
+ #define mkHDR  fmtmk("%s for pid %d, %s", Bot_name, Bot_task, PID_VAL(EU_CMD, str, p))
    struct pids_stack *p;
    int i;
 
@@ -4929,7 +4970,7 @@ static void bot_item_show (void) {
          break;
    }
    if (i < PIDSmaxt) {
-      bot_do_see(PID_VAL(Bot_item[0], str, p), PID_VAL(EU_CMD, str, p));
+      bot_focus(mkHDR, PID_VAL(Bot_item[0], str, p));
    }
 #ifdef BOT_DEAD_ZAP
    else
@@ -4937,18 +4978,21 @@ static void bot_item_show (void) {
 #else
    BOT_KEEP;
 #endif
+ #undef mkHDR
 } // end: bot_item_show
 
 
         /*
-         * This guy toggles between displaying a Ctrl |
+         * This guy can toggle between displaying the |
          * bottom window or arranging to turn it off. | */
-static void bot_item_toggle (enum pflag item, const char *name) {
+static void bot_item_toggle (enum pflag item, const char *name, char sep) {
    // if already targeted, assume user wants to turn it off ...
    if (Bot_item[0] == item) {
       BOT_TOSS;
    } else {
-      Bot_misc = 0;
+      Bot_sep = sep;
+      Bot_what = BOT_TAB_YES;
+      Bot_indx = BOT_UNFOCUS;
       Bot_item[0] = item;
       Bot_item[1] = BOT_DELIMIT;
       Bot_name = (char*)name;
@@ -4968,20 +5012,26 @@ static struct {
    { EU_NS5, PROCPS_NS_USER   }, { EU_NS6, PROCPS_NS_UTS  }
 };
 
+
         /*
          * A helper function that will gather various |
          * stuff for dislay by the bot_misc_show guy. | */
 static char *bot_misc_hlp (struct pids_stack *p) {
-   static char buf[BIGBUFSIZ], *b;
+   static char tmp[SMLBUFSIZ], buf[BIGBUFSIZ], *b;
    int i;
 
    buf[0] = '\0';
-   switch (Bot_misc) {
+   switch (Bot_what) {
       case BOT_MISC_NS:
          b = &buf[0];
-         for (i = 0; i < MAXTBL(ns_tab); i++)
-            b = scat(b, fmtmk("%s: %-10lu  "
-               , procps_ns_get_name(ns_tab[i].that), PID_VAL(ns_tab[i].this, ul_int, p)));
+         for (i = 0; i < MAXTBL(ns_tab); i++) {
+            // caller itself may have used fmtmk, so we'll old school it ...
+            snprintf(tmp, sizeof(tmp), "%s: %-10lu"
+               , procps_ns_get_name(ns_tab[i].that)
+               , PID_VAL(ns_tab[i].this, ul_int, p));
+            b = scat(b, tmp);
+            if (i < (MAXTBL(ns_tab) - 1)) b = scat(b, ", ");
+         }
          break;
       default:
          break;
@@ -4991,9 +5041,10 @@ static char *bot_misc_hlp (struct pids_stack *p) {
 
 
         /*
-         * This guy manages the bottom margin window, |
+         * This guy manages that bottom margin window |
          * showing misc data based on multiple items. | */
 static void bot_misc_show (void) {
+ #define mkHDR  fmtmk("%s for pid %d, %s", Bot_name, Bot_task, PID_VAL(EU_CMD, str, p))
    struct pids_stack *p;
    int i;
 
@@ -5003,25 +5054,26 @@ static void bot_misc_show (void) {
          break;
    }
    if (i < PIDSmaxt) {
-      bot_do_see(bot_misc_hlp(p), PID_VAL(EU_CMD, str, p));
+      bot_focus(mkHDR, bot_misc_hlp(p));
    }
-#ifdef BOT_DEATH
+#ifdef BOT_DEAD_ZAP
    else
       BOT_TOSS;
 #else
    BOT_KEEP;
 #endif
+ #undef mkHDR
 } // end: bot_misc_show
 
 
         /*
-         * This guy toggles between displaying a Ctrl |
+         * This guy can toggle between displaying the |
          * bottom window or arranging to turn it off. | */
-static void bot_misc_toggle (int what) {
+static void bot_misc_toggle (int what, char sep) {
    int i;
 
    // if already targeted, assume user wants to turn it off ...
-   if (Bot_misc == what) {
+   if (Bot_what == what) {
       BOT_TOSS;
    } else {
       switch (what) {
@@ -5034,7 +5086,9 @@ static void bot_misc_toggle (int what) {
          default:
             break;
       }
-      Bot_misc = what;
+      Bot_sep = sep;
+      Bot_what = what;
+      Bot_indx = BOT_UNFOCUS;
       Bot_func = bot_misc_show;
       Bot_task = PID_VAL(EU_PID, s_int, Curwin->ppt[Curwin->begtask]);
    }
@@ -5415,16 +5469,23 @@ static void keys_global (int ch) {
 #endif
          break;
       case kbd_CtrlG:
-         bot_item_toggle(EU_CGR, "control groups");
+         bot_item_toggle(EU_CGR, "control groups", '/');
+         break;
+      case kbd_CtrlI:
+         if (Bot_what) {
+            ++Bot_indx;
+            if (Bot_indx > bot_focus(NULL, NULL))
+               Bot_indx = BOT_UNFOCUS;
+         }
          break;
       case kbd_CtrlK:
-         bot_item_toggle(eu_CMDLINE, "command line");
+         bot_item_toggle(eu_CMDLINE, "command line", ' ');
          break;
       case kbd_CtrlN:
-         bot_item_toggle(EU_ENV, "environment");
+         bot_item_toggle(EU_ENV, "environment", ' ');
          break;
       case kbd_CtrlP:
-         bot_misc_toggle(BOT_MISC_NS);
+         bot_misc_toggle(BOT_MISC_NS, ',');
          break;
       case kbd_CtrlR:
          if (Secure_mode)
@@ -5453,7 +5514,7 @@ static void keys_global (int ch) {
          }
          break;
       case kbd_CtrlU:
-         bot_item_toggle(EU_SGN, "supplementary groups");
+         bot_item_toggle(EU_SGN, "supplementary groups", ',');
          break;
       case kbd_ENTER:             // these two have the effect of waking us
       case kbd_SPACE:             // from 'pselect', refreshing the display
@@ -6295,7 +6356,7 @@ static void do_key (int ch) {
       { keys_global,
          { '?', 'B', 'd', 'E', 'e', 'f', 'g', 'H', 'h'
          , 'I', 'k', 'r', 's', 'X', 'Y', 'Z', '0'
-         , kbd_CtrlE, kbd_CtrlG, kbd_CtrlK, kbd_CtrlN, kbd_CtrlP, kbd_CtrlR, kbd_CtrlU
+         , kbd_CtrlE, kbd_CtrlG, kbd_CtrlI, kbd_CtrlK, kbd_CtrlN, kbd_CtrlP, kbd_CtrlR, kbd_CtrlU
          , kbd_ENTER, kbd_SPACE, '\0' } },
       { keys_summary,
          { '!', '1', '2', '3', '4', 'C', 'l', 'm', 't', '\0' } },
index bbee25fa51fb4c6c319ac948156f72dc5388b84b..3299dd3d94105c610d69f1df08b4d974c63c88b8 100644 (file)
--- a/top/top.h
+++ b/top/top.h
@@ -173,6 +173,7 @@ char *strcasestr(const char *haystack, const char *needle);
 #define kbd_DEL    139
 #define kbd_CtrlE  '\005'
 #define kbd_CtrlG  '\007'
+#define kbd_CtrlI  '\011'
 #define kbd_CtrlK  '\013'
 #define kbd_CtrlN  '\016'
 #define kbd_CtrlO  '\017'
@@ -735,12 +736,13 @@ typedef struct WIN_t {
 //atic void          forest_config (WIN_t *q);
 //atic inline const char *forest_display (const WIN_t *q, int idx);
 /*------  Special Separate Bottom Window support  ------------------------*/
-//atic void          bot_do_see (const char *str, const char *pgm);
+//atic void          bot_do (const char *str, int focus);
+//atic int           bot_focus (const char *hdr, const char *str);
 //atic void          bot_item_show (void);
-//atic void          bot_item_toggle (enum pflag item, const char *name);
+//atic void          bot_item_toggle (enum pflag item, const char *name, char sep);
 //atic char         *bot_misc_hlp (struct pids_stack *p);
 //atic void          bot_misc_show (void);
-//atic void          bot_misc_toggle (int what);
+//atic void          bot_misc_toggle (int what, char sep);
 /*------  Interactive Input Tertiary support  ----------------------------*/
 //atic inline int    find_ofs (const WIN_t *q, const char *buf);
 //atic void          find_string (int ch);