[PATCH v2 1/2] perf hists browser: Support horizontal scrolling with '<' and '>' key

Namhyung Kim
2015-08-09T08:23:49Z

Currently perf TUI report browser doesn't support horizontal scrolling.
So if terminal width is smaller than the actual contents, there's no way
to see them. This patch adds support horizontal movement by '<' and '>'
keys.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/ui/browsers/hists.c | 66 +++++++++++++++++++++++++++++++++---------
1 file changed, 53 insertions(+), 13 deletions(-)

diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index fa67613976a8..9f6e960be3a6 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -20,6 +20,8 @@
#include "map.h"
#include "annotate.h"

+#define SKIP_COLS_STEP 10
+
struct hist_browser {
struct ui_browser b;
struct hists *hists;
@@ -29,6 +31,7 @@ struct hist_browser {
struct pstack *pstack;
struct perf_session_env *env;
int print_seq;
+ int skip_cols;
bool show_dso;
bool show_headers;
float min_pcnt;
@@ -491,6 +494,17 @@ static int hist_browser__run(struct hist_browser *browser, const char *help)
browser->show_headers = !browser->show_headers;
hist_browser__update_rows(browser);
break;
+ case '>':
+ browser->skip_cols += SKIP_COLS_STEP;
+ browser->b.navkeypressed = true;
+ break;
+ case '<':
+ if (browser->skip_cols > SKIP_COLS_STEP)
+ browser->skip_cols -= SKIP_COLS_STEP;
+ else
+ browser->skip_cols = 0;
+ browser->b.navkeypressed = true;
+ break;
case K_ENTER:
if (hist_browser__toggle_fold(browser))
break;
@@ -663,8 +677,27 @@ struct hpp_arg {
struct ui_browser *b;
char folded_sign;
bool current_entry;
+ int skip_cols;
};

+/* returns actual printed length (not skipped) */
+static int hpp_print_skip(struct perf_hpp *hpp, char *buf, size_t size)
+{
+ struct hpp_arg *arg = hpp->ptr;
+ int ret = size;
+
+ if (ret > arg->skip_cols) {
+ slsmg_printf("%s", buf + arg->skip_cols);
+ ret -= arg->skip_cols;
+ arg->skip_cols = 0;
+ } else {
+ arg->skip_cols -= ret;
+ ret = 0;
+ }
+
+ return ret;
+}
+
static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
{
struct hpp_arg *arg = hpp->ptr;
@@ -680,7 +713,7 @@ static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
ui_browser__set_percent_color(arg->b, percent, arg->current_entry);

ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
- slsmg_printf("%s", hpp->buf);
+ ret = hpp_print_skip(hpp, hpp->buf, ret);

advance_hpp(hpp, ret);
return ret;
@@ -716,9 +749,8 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
int len = fmt->user_len ?: fmt->len; \
int ret = scnprintf(hpp->buf, hpp->size, \
"%*s", len, "N/A"); \
- slsmg_printf("%s", hpp->buf); \
\
- return ret; \
+ return hpp_print_skip(hpp, hpp->buf, ret); \
} \
return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
" %*.2f%%", __hpp__slsmg_color_printf, true); \
@@ -778,6 +810,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
.b = &browser->b,
.folded_sign = folded_sign,
.current_entry = current_entry,
+ .skip_cols = browser->skip_cols,
};
struct perf_hpp hpp = {
.buf = s,
@@ -801,20 +834,20 @@ static int hist_browser__show_entry(struct hist_browser *browser,

if (first) {
if (symbol_conf.use_callchain) {
- slsmg_printf("%c ", folded_sign);
- width -= 2;
+ snprintf(s, sizeof(s), "%c ", folded_sign);
+ width -= hpp_print_skip(&hpp, s, 2);
}
first = false;
} else {
- slsmg_printf(" ");
- width -= 2;
+ strcpy(s, " ");
+ width -= hpp_print_skip(&hpp, s, 2);
}

if (fmt->color) {
width -= fmt->color(fmt, &hpp, entry);
} else {
- width -= fmt->entry(fmt, &hpp, entry);
- slsmg_printf("%s", s);
+ int ret = fmt->entry(fmt, &hpp, entry);
+ width -= hpp_print_skip(&hpp, s, ret);
}
}

@@ -873,7 +906,7 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
if (symbol_conf.use_callchain) {
ret = scnprintf(buf, size, " ");
if (advance_hpp_check(&dummy_hpp, ret))
- return ret;
+ goto out;
}

perf_hpp__for_each_format(fmt) {
@@ -889,17 +922,23 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
break;
}

- return ret;
+out:
+ return dummy_hpp.buf - buf;
}

static void hist_browser__show_headers(struct hist_browser *browser)
{
char headers[1024];
+ int width = browser->b.width + 1;
+ int ret;

- hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
+ ret = hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
ui_browser__gotorc(&browser->b, 0, 0);
ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
- slsmg_write_nstring(headers, browser->b.width + 1);
+ if (browser->skip_cols < ret)
+ slsmg_write_nstring(headers + browser->skip_cols, width);
+ else
+ slsmg_write_nstring("", width);
}

static void ui_browser__hists_init_top(struct ui_browser *browser)
@@ -1707,6 +1746,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
#define HIST_BROWSER_HELP_COMMON \
"h/?/F1 Show this window\n" \
"UP/DOWN/PGUP\n" \
+ "</> (angle brackets)\n" \
"PGDN/SPACE Navigate\n" \
"q/ESC/CTRL+C Exit browser\n\n" \
"For multiple event sessions:\n\n" \
--
2.5.0