From 32ecc2c05066bc0ddfdfa537f8d216d5f464df5e Mon Sep 17 00:00:00 2001 From: huwwa Date: Sun, 7 Jun 2026 14:04:37 +0300 Subject: [PATCH] shell: improve next-error * remove popups, sidepanes, helppanes. * verify file existence before opening. * refine error/source windows: * find window showing the error source buffer, split a new one if none are found. * if current window is showing error source buffer, find file in next window, split a new one if none are found. * center cursor after going to error. * show error line on window's first line. * center cursor after going to error. --- modes/shell.c | 66 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/modes/shell.c b/modes/shell.c index bd84e75..365b62e 100644 --- a/modes/shell.c +++ b/modes/shell.c @@ -3753,15 +3753,26 @@ static void do_compile(EditState *s, const char *cmd) static void do_next_error(EditState *s, int arg, int dir) { QEmacsState *qs = s->qs; - EditState *e; + EditState *e, *e_next; EditBuffer *b; int offset, found_offset; char filename[MAX_FILENAME_SIZE]; char fullpath[MAX_FILENAME_SIZE]; buf_t fnamebuf, *fname; - int line_num, col_num, len; + int line_num, col_num; char32_t c; - char error_message[128]; + struct stat sb; + + if (s->flags & (WF_POPUP | WF_MINIBUF)) { + put_error(s, "%s", "Please start command in a normal window"); + return; + } + + if (s->flags & WF_POPLEFT) { + /* avoid messing with the dired pane */ + s = find_window(s, KEY_RIGHT, s); + qs->active_window = s; + } if (arg != NO_ARG) { /* called with a prefix: set the error source to the current buffer */ @@ -3851,8 +3862,6 @@ static void do_next_error(EditState *s, int arg, int dir) goto next_line; c = eb_nextc(b, offset, &offset); } - len = eb_fgets(b, error_message, sizeof(error_message), offset, &offset); - error_message[len] = '\0'; /* strip the trailing newline if any */ if (line_num >= 1) { if (line_num != error_state.line_num || col_num != error_state.col_num @@ -3867,19 +3876,45 @@ static void do_next_error(EditState *s, int arg, int dir) offset = found_offset; } error_state.offset = found_offset; - /* update offsets */ - for (e = qs->first_window; e != NULL; e = e->next_window) { - if (e->b == b) { - e->offset = error_state.offset; - } + + for (e = qs->first_window; e != NULL; e = e_next) { + e_next = e->next_window; + if (e->flags & (WF_POPUP | WF_POPLEFT)) + edit_close(&e); } - /* CG: Should remove popups, sidepanes, helppanes... */ + /* check file and go to the error */ + if (stat(fullpath, &sb) < 0) { + // XXX: should prompt for fullpath as a fallback + put_error(qs->active_window, "Cannot find error in '%s': %s", + fullpath, strerror(errno)); + } else + if (!S_ISREG(sb.st_mode)) { + put_error(qs->active_window, "Cannot find error in '%s': %s", + fullpath, "not a regular file"); + } else { + /* find a window showing the error source + buffer, split a new one if none is found */ + if ((e = eb_find_window(b, NULL)) == NULL) + e = shell_target_window(s, b); - /* go to the error */ - /* XXX: should check for file existence */ - do_find_file(s, fullpath, 0); - do_goto_line(qs->active_window, line_num, col_num); + /* if there is only one window and is showing the error + source buffer then split a new window to find the file in */ + if (e == s && (s = get_next_window(s, WF_MINIBUF | WF_HIDDEN, 0)) == NULL) + s = shell_target_window(e, b); + + /* update error window */ + e->interactive = 0; + e->offset_top = e->offset = error_state.offset; + if (qs->shell_buffer_read_only) + b->flags |= BF_READONLY; + + /* set and update active window */ + qs->active_window = s; + do_find_file(s, fullpath, 0); + do_goto_line(s, line_num, col_num); + do_center_cursor(s, 1); + } #if 0 // conflicts with muscle memory (chqrlie) if (!qs->first_transient_key) { @@ -3887,7 +3922,6 @@ static void do_next_error(EditState *s, int arg, int dir) qe_register_transient_binding(qs, "previous-error", "M-p"); } #endif - put_status(s, "=> %s", error_message); } static int match_digits(const char32_t *buf, int n, char32_t sep) {