From faacac77ea4fbf37922dd1441f5f32ad05a79bb6 Mon Sep 17 00:00:00 2001 From: kang-hyuck Date: Sat, 12 Aug 2023 20:11:35 +0900 Subject: [PATCH] tui: Add Ctrl+u/d, Ctrl+e/y keys to move half page and scroll line problem: tui needs to move the cursor to the top and bottom to see the previous or next page code. solution: Add the keys to move the page by plcaing the cursor on the result that you are interested in. Those are functions in vim and I implemented it. you can move and search the result more flexibly. Fixed: #1802 Signed-off-by: kang-hyuck --- cmds/tui.c | 188 ++++++++++++++++++++++++++++++++++++++++++ doc/ko/uftrace-tui.md | 2 + doc/uftrace-tui.md | 2 + 3 files changed, 192 insertions(+) diff --git a/cmds/tui.c b/cmds/tui.c index 5389dd0c4..0575883e2 100644 --- a/cmds/tui.c +++ b/cmds/tui.c @@ -25,6 +25,12 @@ #define KEY_ESCAPE 27 #define BLANK 32 +/* ncurses format - octal number */ +#define KEY_CTRL_D 0004 +#define KEY_CTRL_E 0005 +#define KEY_CTRL_U 0025 +#define KEY_CTRL_Y 0031 + #define TUI_ASSERT(cond) \ do { \ endwin(); \ @@ -150,6 +156,8 @@ static const char *help[] = { "ARROW Navigation", "PgUp/Dn", "Home/End", + "Ctrl + u/d Move half page up/down", + "Ctrl + e/y Scroll line up/down", "Enter Fold/unfold graph or Select session", "G Show (full) call graph", "g Show call graph for this function", @@ -2079,6 +2087,170 @@ static void tui_window_move_end(struct tui_window *win) } } +static void tui_window_move_scroll_line_up(struct tui_window *win) +{ + void *node = win->ops->next(win, win->top, true); + + /* cannot go top next */ + if (node == NULL) + return; + + /* can go top next */ + win->top_index++; + if (win->ops->needs_blank(win, win->top, node)) + win->top_index++; + + /* update win->top */ + win->top = node; + + /* update win->curr - out of cursor line case*/ + if (win->top_index > win->curr_index) { + win->curr = win->top; + win->curr_index = win->top_index; + } +} + +static void tui_window_move_scroll_line_down(struct tui_window *win) +{ + void *node = win->ops->prev(win, win->top, true); + + /* cannot go top prev */ + if (node == NULL) + return; + + /* can go top prev */ + win->top_index--; + if (win->ops->needs_blank(win, node, win->top)) // (win, prev_node, curr_node) + win->top_index--; + + /* update win->top */ + win->top = node; + + /* update win->curr - out of cursor line case, cursor must follow top in ranges */ + while (win->curr_index - win->top_index >= LINES - 2) { + /* find prev node */ + node = win->ops->prev(win, win->curr, false); + win->curr_index--; + + /* blank check */ + if (win->ops->needs_blank(win, node, win->curr)) + win->curr_index--; + + /* update win->curr */ + win->curr = node; + } +} + +static void tui_window_move_halfpage_up(struct tui_window *win) +{ + void *node; + int move_cnt = 0; + + /* move win->top */ + while (move_cnt < (LINES - 2) / 2 - 1) { + /* find prev node */ + node = win->ops->prev(win, win->top, true); + + /* cannot go top prev */ + if (node == NULL) + break; + + /* can go top prev */ + win->top_index--; + move_cnt++; + + /* blank check */ + if (win->ops->needs_blank(win, node, win->top)) { + win->top_index--; + move_cnt++; + } + + /* update win->top */ + win->top = node; + } + + /* init move_cnt */ + move_cnt = 0; + + /* move win->curr */ + while (move_cnt < (LINES - 2) / 2 - 1) { + /* find prev node */ + node = win->ops->prev(win, win->curr, false); + + /* cannot go curr prev */ + if (node == NULL) + break; + + /* can go curr prev */ + win->curr_index--; + move_cnt++; + + /* blank check */ + if (win->ops->needs_blank(win, node, win->curr)) { + win->curr_index--; + move_cnt++; + } + + /* update win->curr */ + win->curr = node; + } +} + +static void tui_window_move_halfpage_down(struct tui_window *win) +{ + void *node; + int move_cnt = 0; + + /* move win->top */ + while (move_cnt < (LINES - 2) / 2 - 1) { + /* find next node */ + node = win->ops->next(win, win->top, true); + + /* cannot go top next */ + if (node == NULL) + break; + + /* can go top next */ + win->top_index++; + move_cnt++; + + /* blank check */ + if (win->ops->needs_blank(win, win->top, node)) { + win->top_index++; + move_cnt++; + } + + /* update win->top */ + win->top = node; + } + + /* init move_cnt */ + move_cnt = 0; + + /* move win->curr */ + while (move_cnt < (LINES - 2) / 2 - 1) { + /* find next node */ + node = win->ops->next(win, win->curr, false); + + /* cannot go curr next */ + if (node == NULL) + break; + + /* can go curr next */ + win->curr_index++; + move_cnt++; + + /* blank check */ + if (win->ops->needs_blank(win, win->curr, node)) { + win->curr_index++; + move_cnt++; + } + + /* update win->curr */ + win->curr = node; + } +} + /* move to the previous sibling */ static bool tui_window_move_prev(struct tui_window *win) { @@ -2770,6 +2942,22 @@ static void tui_main_loop(struct uftrace_opts *opts, struct uftrace_data *handle cancel_search(); tui_window_move_end(win); break; + case KEY_CTRL_U: + cancel_search(); + tui_window_move_halfpage_up(win); + break; + case KEY_CTRL_D: + cancel_search(); + tui_window_move_halfpage_down(win); + break; + case KEY_CTRL_E: + cancel_search(); + tui_window_move_scroll_line_up(win); + break; + case KEY_CTRL_Y: + cancel_search(); + tui_window_move_scroll_line_down(win); + break; case KEY_ENTER: case '\n': full_redraw = tui_window_enter(win, win->curr); diff --git a/doc/ko/uftrace-tui.md b/doc/ko/uftrace-tui.md index ef5415c41..86dc152a2 100644 --- a/doc/ko/uftrace-tui.md +++ b/doc/ko/uftrace-tui.md @@ -168,6 +168,8 @@ TUI 창에서 다음과 같은 키들을 사용할 수 있음: * `Up`, `Down`: 커서를 위/아래로 움직임 * `PageUp`, `PageDown`: 페이지를 위/아래로 움직임 * `Home`, `End`: 첫번째/마지막 항목으로 이동 + * `Ctrl` + `u`/`d`: 페이지 절반을 위/아래로 움직임 + * `Ctrl` + `e`/`y`: 스크롤 라인 위/아래 움직임 * `Enter`: 그래프 접기/펴기 또는 세션 선택 * `G`: 현재 세션의 전체 그래프 창으로 전환 * `g`: 현재 함수의 백트레이스와 부분 호출 그래프 창으로 전환 diff --git a/doc/uftrace-tui.md b/doc/uftrace-tui.md index 7e7506f76..84753bf5b 100644 --- a/doc/uftrace-tui.md +++ b/doc/uftrace-tui.md @@ -180,6 +180,8 @@ Following keys can be used in the TUI window: * `Up`, `Down`: Move cursor up/down * `PageUp`, `PageDown`: Move page up/down * `Home`, `End`: Move to the first/last entry + * `Ctrl` + `u`/`d`: Move half page up/down + * `Ctrl` + `e`/`y`: Scroll line up/down * `Enter`: Fold/unfold graph or Select session * `G`: Show full graph of the current session * `g`: Show backtrace and call graph of the current function