]> granicus.if.org Git - procps-ng/commitdiff
top: add variable width data display without scrolling
authorJim Warner <james.warner@comcast.net>
Sat, 30 Apr 2022 05:00:00 +0000 (00:00 -0500)
committerCraig Small <csmall@dropbear.xyz>
Tue, 3 May 2022 09:21:21 +0000 (19:21 +1000)
There are times when one might want to see some task's
particular variable width data. However, prior to this
commit, the only way was to first turn on a field then
scroll through it via repeated right arrow keystrokes.

[ this also required that field to be displayed last ]

Needless to say, given the potential length of some of
that variable data this could be extremely cumbersome.

Now with this patch, a Ctrl keystroke combination will
create a separate window at the bottom of the terminal
screen where such variable width data is seen in full.

[ the targeted task is the 1st task displayed, which ]
[ is a convention employed in some existing commands ]

[ the targeted data was determined by these Ctrl key ]
[ combinations: CtrlG = ctrl group; CtrlK = cmdline; ]
[ CtrlU = supplementary groups; plus CtrlV = environ ]

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

index ca33aaf2e70658b814d8ef6be1b1802dfbd1ce81..b8833f161d4b07f5ac3be2f0af567ec0e7eb6568 100644 (file)
--- a/top/top.c
+++ b/top/top.c
@@ -100,7 +100,19 @@ static int Monpidsidx = 0;
                  basis (see the WIN_t).  Max_lines is the total number of
                  screen rows after deducting summary information overhead. */
         /* Current terminal screen size. */
-static int Screen_cols, Screen_rows, Max_lines;
+static int   Screen_cols, Screen_rows, Max_lines;
+
+        // these are used to potentially set aside a bottom 'window'
+#define      SCREEN_ROWS ( Screen_rows - Tagged_rsvd )
+        // 1 for horizontal separator
+#define      TAGGED_RSVD ( 1 )
+#define      TAGGED_UNDO do { Tagged_task = Tagged_rsvd = Tagged_enum = 0; \
+                              Fieldstab[eu_GENERIC].item = PIDS_extra; } while (0)
+static int   Tagged_task,
+             Tagged_rsvd,
+             Tagged_enum;
+static char *Tagged_name;
+static void(*Tagged_func)(void);
 
         /* This is really the number of lines needed to display the summary
            information (0 - nn), but is used as the relative row where we
@@ -1791,7 +1803,7 @@ static struct {
    int           width;         // field width, if applicable
    int           scale;         // scaled target, if applicable
    const int     align;         // the default column alignment flag
-   const enum pids_item item;   // the new libproc item enum identifier
+   enum pids_item item;         // the new libproc item enum identifier
 } Fieldstab[] = {
    // these identifiers reflect the default column alignment but they really
    // contain the WIN_t flag used to check/change justification at run-time!
@@ -1888,12 +1900,14 @@ static struct {
 #define eu_TREE_HID    eu_LAST +4
 #define eu_TREE_LVL    eu_LAST +5
 #define eu_TREE_ADD    eu_LAST +6
+#define eu_GENERIC     eu_LAST +7
    , {  -1, -1, -1,  PIDS_CMDLINE     }  // str      ( if Show_CMDLIN, eu_CMDLINE    )
    , {  -1, -1, -1,  PIDS_TICS_ALL_C  }  // ull_int  ( if Show_CTIMES, eu_TICS_ALL_C )
    , {  -1, -1, -1,  PIDS_ID_FUID     }  // u_int    ( if a usrseltyp, eu_ID_FUID    )
    , {  -1, -1, -1,  PIDS_extra       }  // s_ch     ( if Show_FOREST, eu_TREE_HID   )
    , {  -1, -1, -1,  PIDS_extra       }  // s_int    ( if Show_FOREST, eu_TREE_LVL   )
    , {  -1, -1, -1,  PIDS_extra       }  // s_int    ( if Show_FOREST, eu_TREE_ADD   )
+   , {  -1, -1, -1,  PIDS_extra       }  // str      {  special 'tag', eu_GENERIC    }
  #undef A_left
  #undef A_right
 };
@@ -2078,6 +2092,9 @@ static void build_headers (void) {
          f = w->rc.sortindx;
          if (EU_CMD == f) ckCMDS(w);
          else ckITEM(f);
+
+         // lastly, accommodate any special non-display 'tagged' needs...
+         if (Tagged_enum) ckITEM(Tagged_enum);
       } // end: VIZISw(w)
 
       if (Rc.mode_altscr) w = w->next;
@@ -4331,13 +4348,14 @@ static void win_reset (WIN_t *q) {
 #else
          q->rc.maxtasks = q->usrseltyp = q->begpflg = q->begtask = q->begnext = q->focus_pid = 0;
 #endif
-         // these next two are global, not really windows based
-         Monpidsidx = 0;
-         Rc.tics_scaled = 0;
-
          osel_clear(q);
          q->findstr[0] = '\0';
          q->rc.combine_cpus = 0;
+
+         // these next guys are global, not really windows based
+         Monpidsidx = 0;
+         Rc.tics_scaled = 0;
+         TAGGED_UNDO;
 } // end: win_reset
 
 
@@ -4609,6 +4627,64 @@ static void wins_stage_2 (void) {
 } // end: wins_stage_2
 
 
+        /*
+         * This guy manages the bottom margin window |
+         * & the tagged process command line display | */
+static void wins_tag_cmdline (void) {
+   char buf[SMLBUFSIZ];
+   const char *p;
+   int i;
+
+   for (i = 0; i < PIDSmaxt; i++) {
+      if (Tagged_task == PID_VAL(EU_PID, s_int, Curwin->ppt[i]))
+         break;
+   }
+   if (i < PIDSmaxt) {
+      snprintf(buf, sizeof(buf), "command line for pid %d:", Tagged_task);
+#ifndef TAG_CMD_MUST
+      p = PID_VAL(eu_CMDLINE, str, Curwin->ppt[i]);
+      if (!p || !*p) p = "n/a";
+#else
+      p = CHKw(Curwin, Show_CMDLIN) ? PID_VAL(eu_CMDLINE, str, Curwin->ppt[i]) : "n/a";
+#endif
+      Tagged_rsvd = 1 + TAGGED_RSVD + (strlen(p) / Screen_cols);
+      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(p, stdout);
+   } else {
+      TAGGED_UNDO;
+   }
+} // end: wins_tag_cmdline
+
+
+        /*
+         * This guy manages the bottom margin window |
+         * showing miscellaneous variable width data | */
+static void wins_tag_generic (void) {
+   char buf[SMLBUFSIZ];
+   const char *p;
+   int i;
+
+   for (i = 0; i < PIDSmaxt; i++) {
+      if (Tagged_task == PID_VAL(EU_PID, s_int, Curwin->ppt[i]))
+         break;
+   }
+   if (i < PIDSmaxt) {
+      snprintf(buf, sizeof(buf), "%s for pid %d:", Tagged_name, Tagged_task);
+      p = PID_VAL(eu_GENERIC, str, Curwin->ppt[i]);
+      if (!p || !*p || !strcmp(p, "-")) p = "n/a";
+      Tagged_rsvd = 1 + TAGGED_RSVD + (strlen(p) / Screen_cols);
+      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(p, stdout);
+   } else {
+      TAGGED_UNDO;
+   }
+} // end: wins_tag_generic
+
+
         /*
          * Determine if this task matches the 'u/U' selection
          * criteria for a given window */
@@ -4799,7 +4875,7 @@ static void forest_config (WIN_t *q) {
       // if some task 'above' us ended, try to maintain focus
       // ( but allow scrolling when there are many children )
       if (q->begtask > q->focus_beg
-      && (Screen_rows > (q->focus_end - q->focus_beg))) {
+      && (SCREEN_ROWS > (q->focus_end - q->focus_beg))) {
          q->begtask = q->focus_beg;
          q->begnext = 0;     // as 'mkVIZoff' but in any window
       }
@@ -5222,6 +5298,33 @@ static void keys_global (int ch) {
             Rc.tics_scaled = 0;
 #endif
          break;
+      case kbd_CtrlG:
+         def = PID_VAL(EU_PID, s_int, w->ppt[w->begtask]);
+         // if already targeted, assume user wants to turn it off ...
+         if (Tagged_task && Fieldstab[eu_GENERIC].item == PIDS_CGROUP) {
+            TAGGED_UNDO;
+         } else {
+            Tagged_task = def;
+            Tagged_enum = eu_GENERIC;
+            Tagged_name = "control groups";
+            Tagged_func = wins_tag_generic;
+            Fieldstab[eu_GENERIC].item = PIDS_CGROUP;
+         }
+         break;
+      case kbd_CtrlK:
+         def = PID_VAL(EU_PID, s_int, w->ppt[w->begtask]);
+         // if already targeted, assume user wants to turn it off ...
+         if (Tagged_task && Tagged_func == wins_tag_cmdline) {
+            TAGGED_UNDO;
+         } else {
+            Tagged_task = def;
+#ifndef TAG_CMD_MUST
+            Tagged_enum = eu_CMDLINE;
+#endif
+            Tagged_func = wins_tag_cmdline;
+            Fieldstab[eu_GENERIC].item = PIDS_extra;
+         }
+         break;
       case kbd_CtrlR:
          if (Secure_mode)
             show_msg(N_txt(NOT_onsecure_txt));
@@ -5248,6 +5351,32 @@ static void keys_global (int ch) {
             }
          }
          break;
+      case kbd_CtrlU:
+         def = PID_VAL(EU_PID, s_int, w->ppt[w->begtask]);
+         // if already targeted, assume user wants to turn it off ...
+         if (Tagged_task && Fieldstab[eu_GENERIC].item == PIDS_SUPGROUPS) {
+            TAGGED_UNDO;
+         } else {
+            Tagged_task = def;
+            Tagged_enum = eu_GENERIC;
+            Tagged_name = "supplementary groups";
+            Tagged_func = wins_tag_generic;
+            Fieldstab[eu_GENERIC].item = PIDS_SUPGROUPS;
+         }
+         break;
+      case kbd_CtrlV:
+         def = PID_VAL(EU_PID, s_int, w->ppt[w->begtask]);
+         // if already targeted, assume user wants to turn it off ...
+         if (Tagged_task && Fieldstab[eu_GENERIC].item == PIDS_ENVIRON) {
+            TAGGED_UNDO;
+         } else {
+            Tagged_task = def;
+            Tagged_enum = eu_GENERIC;
+            Tagged_name = "environment";
+            Tagged_func = wins_tag_generic;
+            Fieldstab[eu_GENERIC].item = PIDS_ENVIRON;
+         }
+         break;
       case kbd_ENTER:             // these two have the effect of waking us
       case kbd_SPACE:             // from 'pselect', refreshing the display
          break;                   // and updating any hot-plugged resources
@@ -5874,7 +6003,7 @@ static int sum_unify (struct stat_stack *this, int nobuf) {
          * A helper function that displays cpu and/or numa node stuff |
          * ( so as to keep the 'summary_show' guy a reasonable size ) | */
 static void do_cpus (void) {
- #define noMAS (Msg_row + 1 >= Screen_rows - 1)
+ #define noMAS (Msg_row + 1 >= SCREEN_ROWS - 1)
    char tmp[MEDBUFSIZ];
    int i;
 
@@ -6088,7 +6217,8 @@ 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_CtrlR, kbd_ENTER, kbd_SPACE, '\0' } },
+         , kbd_CtrlE, kbd_CtrlG, kbd_CtrlK, kbd_CtrlR, kbd_CtrlU, kbd_CtrlV
+         , kbd_ENTER, kbd_SPACE, '\0' } },
       { keys_summary,
          { '!', '1', '2', '3', '4', 'C', 'l', 'm', 't', '\0' } },
       { keys_task,
@@ -6157,7 +6287,7 @@ all_done:
          *    2) Display task/cpu states (maybe)
          *    3) Display memory & swap usage (maybe) */
 static void summary_show (void) {
- #define isROOM(f,n) (CHKw(Curwin, f) && Msg_row + (n) < Screen_rows - 1)
+ #define isROOM(f,n) (CHKw(Curwin, f) && Msg_row + (n) < SCREEN_ROWS - 1)
 
    if (Restrict_some) {
 #ifdef THREADED_TSK
@@ -6712,7 +6842,7 @@ static void frame_make (void) {
 
    Tree_idx = Pseudo_row = Msg_row = scrlins = 0;
    summary_show();
-   Max_lines = (Screen_rows - Msg_row) - 1;
+   Max_lines = (SCREEN_ROWS - Msg_row) - 1;
 
    // we're now on Msg_row so clear out any residual messages ...
    putp(Cap_clr_eol);
@@ -6739,8 +6869,8 @@ static void frame_make (void) {
       PSU_CLREOS(Pseudo_row);
    }
 
-   if (CHKw(w, View_SCROLL) && VIZISw(Curwin))
-      show_scroll();
+   if (CHKw(w, View_SCROLL) && VIZISw(Curwin)) show_scroll();
+   if (Tagged_task) Tagged_func();
    fflush(stdout);
 
    /* we'll deem any terminal not supporting tgoto as dumb and disable
index 0627170073629a7c9101e6140331066e0474e59a..b7ab4afd8b501c07d6a1411e07e6f2a93138f3f1 100644 (file)
--- a/top/top.h
+++ b/top/top.h
@@ -54,6 +54,7 @@
 //#define SCROLLVAR_NO            /* disable intra-column horizontal scrolls */
 //#define SCROLLV_BY_1            /* when scrolling left/right do not move 8 */
 //#define STRINGCASENO            /* case insenstive compare/locate versions */
+//#define TAG_CMD_MUST            /* CtrlK (cmdline) needs proper 'c' toggle */
 //#define TERMIOS_ONLY            /* use native input only (just limp along) */
 //#define THREADED_CPU            /* separate background thread for cpu updt */
 //#define THREADED_MEM            /* separate background thread for mem updt */
@@ -171,8 +172,12 @@ char *strcasestr(const char *haystack, const char *needle);
 #define kbd_INS    138
 #define kbd_DEL    139
 #define kbd_CtrlE  '\005'
+#define kbd_CtrlG  '\007'
+#define kbd_CtrlK  '\013'
 #define kbd_CtrlO  '\017'
 #define kbd_CtrlR  '\022'
+#define kbd_CtrlU  '\025'
+#define kbd_CtrlV  '\026'
 
         /* Special value in Pseudo_row to force an additional procs refresh
            -- used at startup and for task/thread mode transitions */
@@ -721,6 +726,8 @@ typedef struct WIN_t {
 //atic void          wins_reflag (int what, int flg);
 //atic void          wins_stage_1 (void);
 //atic void          wins_stage_2 (void);
+//atic void          wins_tag_cmdline (void);
+//atic void          wins_tag_generic (void);
 //atic inline int    wins_usrselect (const WIN_t *q, int idx);
 /*------  Forest View support  -------------------------------------------*/
 //atic void          forest_adds (const int self, int level);
index 23a83851ea7a05fd2c4e2c6426debe39b81f2bd6..03ddedc545437b3af6c0884ff392d4a2bd38a8c2 100644 (file)
@@ -651,7 +651,8 @@ static void build_uniq_nlstab (void) {
       "  V,v,F   . Toggle: '~1V~2' forest view; '~1v~2' hide/show children; '~1F~2' keep focused\n"
       "\n"
       "%s"
-      "  W,Y,!,^E  Write cfg '~1W~2'; Inspect '~1Y~2'; Combine Cpus '~1!~2'; Scale time ~1Ctrl~2+'~1E~2'\n"
+      "  ^G,K,U,V  View: ctl groups ~1^g~2; cmdline ~1^k~2; supp groups ~1^u~2; environment ~1^v~2\n"
+      "  W,Y,!,^E  Write cfg '~1W~2'; Inspect '~1Y~2'; Combine Cpus '~1!~2'; Scale time ~1^e~2'\n"
       "  q         Quit\n"
       "          ( commands shown with '.' require a ~1visible~2 task display ~1window~2 ) \n"
       "Press '~1h~2' or '~1?~2' for help with ~1Windows~2,\n"
@@ -722,8 +723,7 @@ static void build_uniq_nlstab (void) {
    .                 also imbedded in the translatable text (along with escape seqs)
    .                 should never themselves be translated. */
    Uniq_nlstab[KEYS_helpext_fmt] = _(""
-      "  k,r,^R,   Tasks: '~1k~2' kill; '~1r~2' renice; ~1Ctrl~2+'~1R~2' renice autogroup\n"
-      "  d or s    Set update interval\n");
+      "  d,k,r,^R, '~1d~2' set delay; '~1k~2' kill; '~1r~2' renice; ~1Ctrl~2+'~1R~2' renice autogroup\n");
 
 /* Translation Hint:
    .  This Fields Management header should be 3 lines long so as