--- lbbs/src/screen.c 2025/05/30 00:20:53 1.80 +++ lbbs/src/screen.c 2025/06/01 14:32:41 1.87 @@ -231,11 +231,13 @@ int get_data(int row, int col, char *pro return len; } -int display_data(const void *p_data, long line_total, const long *p_line_offsets, int begin_line, int wait) +int display_data(const void *p_data, long line_total, const long *p_line_offsets, int begin_line, int eof_exit, + display_data_key_handler key_handler, const char *help_filename) { static int show_help = 1; char buffer[LINE_BUFFER_LEN]; - int ch = KEY_NULL; + DISPLAY_CTX ctx; + int ch = 0; int input_ok, line, max_lines; long int line_current = 0; long int len; @@ -247,16 +249,22 @@ int display_data(const void *p_data, lon line = begin_line; max_lines = SCREEN_ROWS - 1; + // update msg_ext with extended key handler + if (key_handler(&ch, &ctx) != 0) + { + return ch; + } + loop = 1; while (!SYS_server_exit && loop) { - if (line_current >= line_total && line_total <= SCREEN_ROWS - 2) + if (eof_exit > 0 && line_current >= line_total && line_total <= SCREEN_ROWS - 2) { - if (wait) + if (eof_exit == 1) { ch = press_any_key(); } - else + else // if (eof_exit == 2) { iflush(); } @@ -267,25 +275,31 @@ int display_data(const void *p_data, lon if (line_current >= line_total || line >= max_lines) { + ctx.reach_begin = (line_current < line ? 1 : 0); + if (line_current - (line - 1) + (SCREEN_ROWS - 2) < line_total) { percentile = (line_current - (line - 1) + (SCREEN_ROWS - 2)) * 100 / line_total; + ctx.reach_end = 0; } else { percentile = 100; + ctx.reach_end = 1; } + ctx.line_top = line_current - (line - 1) + 1; + ctx.line_bottom = MIN(line_current - (line - 1) + (SCREEN_ROWS - 2), line_total); + snprintf(buffer, sizeof(buffer), - "\033[1;44;33m第\033[32m%ld\033[33m-\033[32m%ld\033[33m行 (\033[32m%ld%%\033[33m) │ " - "返回[\033[32m←\033[33m,\033[32mESC\033[33m] │ 移动[\033[32m↑\033[33m/\033[32m↓\033[33m/\033[32mPgUp\033[33m/\033[32mPgDn\033[33m] │ " - "帮助[\033[32mh\033[33m] │", - line_current - (line - 1) + 1, - MIN(line_current - (line - 1) + (SCREEN_ROWS - 2), line_total), - percentile); + "\033[1;44;33m第\033[32m%ld\033[33m-\033[32m%ld\033[33m行 (\033[32m%ld%%\033[33m) %s", + ctx.line_top, + ctx.line_bottom, + percentile, + ctx.msg); len = split_line(buffer, SCREEN_COLS, &eol, &display_len); - for (;display_len < SCREEN_COLS; display_len++) + for (; display_len < SCREEN_COLS; display_len++) { buffer[len++] = ' '; } @@ -301,25 +315,40 @@ int display_data(const void *p_data, lon { ch = igetch_t(MAX_DELAY_TIME); input_ok = 1; + + // extended key handler + if (key_handler(&ch, &ctx) != 0) + { + goto cleanup; + } + switch (ch) { case KEY_NULL: case KEY_TIMEOUT: goto cleanup; case KEY_HOME: + if (line_current - line < 0) // Reach begin + { + break; + } line_current = 0; line = begin_line; max_lines = SCREEN_ROWS - 1; clrline(begin_line, SCREEN_ROWS); break; case KEY_END: + if (line_total < SCREEN_ROWS - 2) + { + break; + } line_current = line_total - (SCREEN_ROWS - 2); line = begin_line; max_lines = SCREEN_ROWS - 1; clrline(begin_line, SCREEN_ROWS); break; case KEY_UP: - if (line_current - line < 0) // Reach top + if (line_current - line < 0) // Reach begin { break; } @@ -333,7 +362,7 @@ int display_data(const void *p_data, lon igetch_reset(); case KEY_SPACE: case KEY_DOWN: - if (line_current + ((SCREEN_ROWS - 2) - (line - 1)) >= line_total) // Reach bottom + if (line_current + ((SCREEN_ROWS - 2) - (line - 1)) >= line_total) // Reach end { break; } @@ -345,7 +374,7 @@ int display_data(const void *p_data, lon prints("\033[S"); // Scroll up 1 line break; case KEY_PGUP: - if (line_current - line < 0) // Reach top + if (line_current - line < 0) // Reach begin { break; } @@ -359,7 +388,7 @@ int display_data(const void *p_data, lon clrline(begin_line, SCREEN_ROWS); break; case KEY_PGDN: - if (line_current + (SCREEN_ROWS - 2) - (line - 1) >= line_total) // Reach bottom + if (line_current + (SCREEN_ROWS - 2) - (line - 1) >= line_total) // Reach end { break; } @@ -377,22 +406,24 @@ int display_data(const void *p_data, lon loop = 0; break; case 'h': - if (!show_help) + if (!show_help) // Not reentrant { break; } // Display help information show_help = 0; - display_file(DATA_READ_HELP, begin_line, 1); + display_file(help_filename, begin_line, 1); show_help = 1; - + case KEY_F5: // Refresh after display help information line_current -= (line - 1); line = begin_line; max_lines = SCREEN_ROWS - 1; clrline(begin_line, SCREEN_ROWS); break; + case 0: // Refresh bottom line + break; default: input_ok = 0; break; @@ -407,10 +438,16 @@ int display_data(const void *p_data, lon len = p_line_offsets[line_current + 1] - p_line_offsets[line_current]; if (len >= LINE_BUFFER_LEN) { - log_error("buffer overflow: len=%ld(%ld - %ld) line=%ld \n", + log_error("Buffer overflow: len=%ld(%ld - %ld) line=%ld \n", len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current); len = LINE_BUFFER_LEN - 1; } + else if (len < 0) + { + log_error("Incorrect line offsets: len=%ld(%ld - %ld) line=%ld \n", + len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current); + len = 0; + } memcpy(buffer, (const char *)p_data + p_line_offsets[line_current], (size_t)len); buffer[len] = '\0'; @@ -426,9 +463,24 @@ cleanup: return ch; } -int display_file(const char *filename, int begin_line, int wait) +static int display_file_key_handler(int *p_key, DISPLAY_CTX *p_ctx) { - int ch = KEY_NULL; + switch (*p_key) + { + case 0: // Set msg + snprintf(p_ctx->msg, sizeof(p_ctx->msg), + "| 返回[\033[32m←\033[33m,\033[32mESC\033[33m] | " + "移动[\033[32m↑\033[33m/\033[32m↓\033[33m/\033[32mPgUp\033[33m/\033[32mPgDn\033[33m] | " + "帮助[\033[32mh\033[33m] |"); + break; + } + + return 0; +} + +int display_file(const char *filename, int begin_line, int eof_exit) +{ + int ret; const void *p_shm; size_t data_len; long line_total; @@ -441,14 +493,14 @@ int display_file(const char *filename, i return KEY_NULL; } - ch = display_data(p_data, line_total, p_line_offsets, begin_line, wait); + ret = display_data(p_data, line_total, p_line_offsets, begin_line, eof_exit, display_file_key_handler, DATA_READ_HELP); if (detach_file_shm(p_shm) < 0) { log_error("detach_file_shm(%s) error\n", filename); } - return ch; + return ret; } int show_top(const char *str_left, const char *str_middle, const char *str_right)