From bccfbef8a00b82edfc652699fdd92acbabb06225 Mon Sep 17 00:00:00 2001 From: Charlie Gordon Date: Wed, 19 Aug 2015 19:20:57 +0000 Subject: [PATCH] window handling, bufed/dired: fixed bugs, simplified code - make show_popup(b) return the window - pass an extra window argument to find_window() as a default return value - add check_buffer(EditBuffer **sp) to validate a buffer pointer - changed eb_find_window(): find a different window attached to a given buffer - removed edit_find(), use eb_find_window() instead - change edit_attach(): take window before which to move arg window, use NULL to append at the end. If qs->active_window is NULL, set it to the first window - add buffer flags BF_IS_LOG and BF_IS_STYLE - create style buffers with a meaningful name - create log buffers with a meaningful name - add window flag WF_POPLEFT for dired interactive buffers - no longer create process buffer and find files in dired pop left pane - remember last buffer upon switch_to_buffer for predict_switch_to_buffer() - rename do_file1() as extern qe_load_file() and make it return success status - prevent do_find_file_other_window() from splitting window if too shallow - fix window fusion algorithm when deleting left pane with split right pane - prevent delete-other-windows() from minibuf and poups - use mode structure as signature for bufed-mode, shell-mode - make list-buffers open an interactive popup window - toggle full buffer list with '.' --- bufed.c | 133 ++++++++++++------------- buffer.c | 39 +++++--- dired.c | 12 +-- qe.c | 291 +++++++++++++++++++++++++++---------------------------- qe.h | 23 +++-- shell.c | 35 ++++--- 6 files changed, 277 insertions(+), 256 deletions(-) diff --git a/bufed.c b/bufed.c index 8988102..ac93086 100644 --- a/bufed.c +++ b/bufed.c @@ -22,16 +22,17 @@ #include "qe.h" enum { - BUFED_ALL_VISIBLE = 1 + BUFED_HIDE_SYSTEM = 0, + BUFED_ALL_VISIBLE = 1, }; -static int bufed_signature; - typedef struct BufedState { - void *signature; - StringArray items; + ModeDef *signature; int flags; - int last_index; + EditState *cur_window; + EditBuffer *cur_buffer; + EditBuffer *last_buffer; + StringArray items; } BufedState; static ModeDef bufed_mode; @@ -40,7 +41,7 @@ static BufedState *bufed_get_state(EditState *s, int status) { BufedState *bs = s->b->priv_data; - if (bs && bs->signature == &bufed_signature) + if (bs && bs->signature == &bufed_mode) return bs; if (status) @@ -90,6 +91,12 @@ static void build_bufed_list(EditState *s) char path[MAX_FILENAME_SIZE]; const char *mode_name; + if (b1->flags & BF_IS_LOG) { + mode_name = "log"; + } else + if (b1->flags & BF_IS_STYLE) { + mode_name = "style"; + } else if (b1->saved_mode) { mode_name = b1->saved_mode->name; } else @@ -102,8 +109,8 @@ static void build_bufed_list(EditState *s) mode_name = "none"; } - eb_printf(b, " %10d %c %-8s %-8s %s", - b1->total_size, " 1234567"[b1->style_bytes & 7], + eb_printf(b, " %10d %1.0d %-8s %-8s %s", + b1->total_size, b1->style_bytes & 7, b1->charset->name, mode_name, make_user_path(path, sizeof(path), b1->filename)); } @@ -131,39 +138,36 @@ static EditBuffer *bufed_get_buffer(EditState *s) static void bufed_select(EditState *s, int temp) { BufedState *bs; - StringItem *item; - EditBuffer *b; + EditBuffer *b, *last_buffer; EditState *e; int index; if (!(bs = bufed_get_state(s, 1))) return; - index = list_get_pos(s); - if (index < 0 || index >= bs->items.nb_items) - return; + if (temp < 0) { + b = check_buffer(&bs->cur_buffer); + last_buffer = check_buffer(&bs->last_buffer); + } else { + index = list_get_pos(s); + if (index < 0 || index >= bs->items.nb_items) + return; - if (temp && index == bs->last_index) - return; - - item = bs->items.items[index]; - b = eb_find(item->str); - if (!b) - return; - e = find_window(s, KEY_RIGHT); - if (temp) { - if (e) { - bs->last_index = index; - switch_to_buffer(e, b); - } - return; + b = eb_find(bs->items.items[index]->str); + last_buffer = bs->cur_buffer; } - if (e) { + e = check_window(&bs->cur_window); + if (e && b) { + switch_to_buffer(e, b); + e->last_buffer = last_buffer; + } + if (temp <= 0) { /* delete bufed window */ do_delete_window(s, 1); - switch_to_buffer(e, b); + if (e) + e->qe_state->active_window = e; } else { - switch_to_buffer(s, b); + do_refresh_complete(s); } } @@ -218,31 +222,38 @@ static void bufed_kill_buffer(EditState *s) /* show a list of buffers */ static void do_list_buffers(EditState *s, int argval) { - QEmacsState *qs = s->qe_state; BufedState *bs; - EditBuffer *b, *b0; - EditState *e, *e1; - int width, i; + EditBuffer *b; + EditState *e; + int i; - /* remember current buffer for target positioning, because - * s may be destroyed by insert_window_left - * CG: remove this kludge once we have delayed EditState free - */ - b = b0 = s->b; + /* ignore command from the minibuffer and popups */ + if (s->minibuf || (s->flags & WF_POPUP)) + return; - if ((bs = bufed_get_state(s, 0)) == NULL) { - /* XXX: must close this buffer when destroying window: add a - special buffer flag to tell this */ - b = eb_scratch("*bufed*", BF_READONLY | BF_SYSTEM | BF_UTF8); + if (s->flags & WF_POPLEFT) { + /* avoid messing with the dired pane */ + s = find_window(s, KEY_RIGHT, s); + s->qe_state->active_window = s; } - width = qs->width / 5; - e = insert_window_left(b, width, WF_MODELINE); + b = eb_scratch("*bufed*", BF_READONLY | BF_SYSTEM | BF_UTF8); + if (!b) + return; + + e = show_popup(b); + if (!e) + return; + edit_set_mode(e, &bufed_mode); if (!(bs = bufed_get_state(e, 1))) return; + bs->cur_window = s; + bs->cur_buffer = s->b; + bs->last_buffer = s->last_buffer; + if (argval == NO_ARG) { bs->flags &= ~BUFED_ALL_VISIBLE; } else { @@ -250,20 +261,13 @@ static void do_list_buffers(EditState *s, int argval) } build_bufed_list(e); - e1 = find_window(e, KEY_RIGHT); - if (e1) - b0 = e1->b; - /* if active buffer is found, go directly on it */ for (i = 0; i < bs->items.nb_items; i++) { - if (strequal(bs->items.items[i]->str, b0->name)) { + if (strequal(bs->items.items[i]->str, s->b->name)) { e->offset = eb_goto_pos(e->b, i, 0); break; } } - - /* modify active window */ - qs->active_window = e; } static void bufed_clear_modified(EditState *s) @@ -309,14 +313,15 @@ static void bufed_display_hook(EditState *s) if (s->offset && s->offset == s->b->total_size) do_up_down(s, -1); - bufed_select(s, 1); + if (s->flags & WF_POPUP) + bufed_select(s, 1); } static int bufed_mode_probe(ModeDef *mode, ModeProbeData *p) { if (p->b->priv_data) { BufedState *bs = p->b->priv_data; - if (bs->signature == &bufed_signature) + if (bs->signature == &bufed_mode) return 95; else return 0; @@ -328,7 +333,7 @@ static void bufed_close(EditBuffer *b) { BufedState *bs = b->priv_data; - if (bs && bs->signature == &bufed_signature) { + if (bs && bs->signature == &bufed_mode) { free_strings(&bs->items); } @@ -346,7 +351,7 @@ static int bufed_mode_init(EditState *s, EditBuffer *b, int flags) if (s) { if (s->b->priv_data) { bs = s->b->priv_data; - if (bs->signature != &bufed_signature) + if (bs->signature != &bufed_mode) return -1; } else { /* XXX: should be allocated by buffer_load API */ @@ -354,8 +359,7 @@ static int bufed_mode_init(EditState *s, EditBuffer *b, int flags) if (!bs) return -1; - bs->signature = &bufed_signature; - bs->last_index = -1; + bs->signature = &bufed_mode; s->b->priv_data = bs; s->b->close = bufed_close; } @@ -365,11 +369,11 @@ static int bufed_mode_init(EditState *s, EditBuffer *b, int flags) /* specific bufed commands */ static CmdDef bufed_commands[] = { - CMD1( KEY_RET, KEY_RIGHT, + CMD1( KEY_RET, KEY_NONE, "bufed-select", bufed_select, 0) /* bufed-abort should restore previous buffer in right-window */ - CMD1( KEY_CTRL('g'), KEY_NONE, - "bufed-abort", do_delete_window, 0) + CMD1( KEY_CTRL('g'), KEY_CTRLX(KEY_CTRL('g')), + "bufed-abort", bufed_select, -1) CMD1( ' ', KEY_CTRL('t'), "bufed-toggle-selection", list_toggle_selection, 1) CMD1( KEY_DEL, KEY_NONE, @@ -379,7 +383,7 @@ static CmdDef bufed_commands[] = { "bufed-clear-modified", bufed_clear_modified) CMD0( '%', KEY_NONE, "bufed-toggle-read-only", bufed_toggle_read_only) - CMD1( 'a', KEY_NONE, + CMD1( 'a', '.', "bufed-toggle-all-visible", bufed_refresh, 1) CMD1( 'n', KEY_CTRL('n'), /* KEY_DOWN */ "bufed-next-line", do_up_down, 1) @@ -406,7 +410,6 @@ static int bufed_init(void) bufed_mode.name = "bufed"; bufed_mode.mode_probe = bufed_mode_probe; bufed_mode.mode_init = bufed_mode_init; - /* CG: not a good idea, display hook has side effect on layout */ bufed_mode.display_hook = bufed_display_hook; /* first register mode */ diff --git a/buffer.c b/buffer.c index d8c5ca4..31beb0d 100644 --- a/buffer.c +++ b/buffer.c @@ -395,6 +395,21 @@ int eb_insert(EditBuffer *b, int offset, const void *buf, int size) return size; } +/* Verify that window still exists, return argument or NULL, + * update handle if window is invalid. + */ +EditBuffer *check_buffer(EditBuffer **sp) +{ + QEmacsState *qs = &qe_state; + EditBuffer *b; + + for (b = qs->first_buffer; b != NULL; b = b->next) { + if (b == *sp) + return b; + } + return *sp = NULL; +} + /* We must have : 0 <= offset <= b->total_size, * return actual number of bytes removed. */ @@ -663,19 +678,17 @@ EditBuffer *eb_find_file(const char *filename) return NULL; } -/* Find the next window showing a given buffer */ -EditState *eb_find_window(EditBuffer *b, EditState *e) +/* Find a window attached to a given buffer, different from s */ +EditState *eb_find_window(EditBuffer *b, EditState *s) { QEmacsState *qs = &qe_state; + EditState *e; - for (e = e ? e->next_window : qs->first_window; - e != NULL; - e = e->next_window) - { - if (e->b == b) - return e; + for (e = qs->first_window; e != NULL; e = e->next_window) { + if (e != s && e->b == b) + break; } - return NULL; + return e; } void eb_trace_bytes(const void *buf, int size, int state) @@ -800,7 +813,9 @@ int eb_create_style_buffer(EditBuffer *b, int flags) if (b->b_styles) { return 0; } else { - b->b_styles = eb_new("*", BF_SYSTEM | BF_RAW); + char name[MAX_BUFFERNAME_SIZE]; + snprintf(name, sizeof(name), "*S<%s>", b->name); + b->b_styles = eb_new(name, BF_SYSTEM | BF_IS_STYLE | BF_RAW); b->flags |= flags & BF_STYLES; b->style_shift = ((flags & BF_STYLES) / BF_STYLE1) - 1; b->style_bytes = 1 << b->style_shift; @@ -904,8 +919,8 @@ static void eb_addlog(EditBuffer *b, enum LogOperation op, * should not be a problem since this log buffer is never * referenced by name. */ - snprintf(buf, sizeof(buf), "*log <%s>*", b->name); - b->log_buffer = eb_new(buf, BF_SYSTEM | BF_RAW); + snprintf(buf, sizeof(buf), "*L<%s>", b->name); + b->log_buffer = eb_new(buf, BF_SYSTEM | BF_IS_LOG | BF_RAW); if (!b->log_buffer) return; } diff --git a/dired.c b/dired.c index 0da44bc..88dfa59 100644 --- a/dired.c +++ b/dired.c @@ -854,7 +854,7 @@ static void dired_select(EditState *s) } else if (S_ISREG(st.st_mode)) { /* do explore files pointed to by symlinks */ - e = find_window(s, KEY_RIGHT); + e = find_window(s, KEY_RIGHT, NULL); if (e) { #if 1 s->qe_state->active_window = e; @@ -874,8 +874,9 @@ static void dired_view_file(EditState *s, const char *filename) { EditBuffer *b; EditState *e; + int rc; - e = find_window(s, KEY_RIGHT); + e = find_window(s, KEY_RIGHT, NULL); if (!e) return; @@ -890,10 +891,6 @@ static void dired_view_file(EditState *s, const char *filename) * new buffer as BF_PREVIEW, to trigger paging mode and so that it * will get freed if closed. */ -#if 1 - /* XXX: need a way to verify that file was correctly loaded */ - do_find_file(e, filename, BF_PREVIEW); -#else rc = qe_load_file(e, filename, 0, 0, BF_PREVIEW); if (rc >= 0) { /* disable wrapping to get nicer display */ @@ -904,7 +901,6 @@ static void dired_view_file(EditState *s, const char *filename) /* if file failed to load, show a scratch buffer */ switch_to_buffer(e, eb_new("*scratch*", BF_SAVELOG | BF_UTF8 | BF_PREVIEW)); } -#endif } static void dired_execute(EditState *s) @@ -920,7 +916,7 @@ static void dired_parent(EditState *s) char filename[MAX_FILENAME_SIZE]; if (s->b->flags & BF_PREVIEW) { - EditState *e = find_window(s, KEY_LEFT); + EditState *e = find_window(s, KEY_LEFT, NULL); if (e && (e->b->flags & BF_DIRED)) { s->qe_state->active_window = e; return; diff --git a/qe.c b/qe.c index ddfbdd9..33e02de 100644 --- a/qe.c +++ b/qe.c @@ -958,7 +958,7 @@ void do_left_right(EditState *s, int dir) { #ifndef CONFIG_TINY if (s->b->flags & BF_PREVIEW) { - EditState *e = find_window(s, KEY_LEFT); + EditState *e = find_window(s, KEY_LEFT, NULL); if (e && (e->b->flags & BF_DIRED) && dir < 0 && eb_at_bol(s->b, s->offset)) { s->qe_state->active_window = e; @@ -4900,7 +4900,6 @@ EditState *find_file_window(const char *filename) void switch_to_buffer(EditState *s, EditBuffer *b) { - QEmacsState *qs = s->qe_state; EditBuffer *b1; EditState *e; ModeSavedData *saved_data; @@ -4916,10 +4915,7 @@ void switch_to_buffer(EditState *s, EditBuffer *b) b1 = s->b; if (b1) { /* save mode data if no other window uses the buffer */ - for (e = qs->first_window; e != NULL; e = e->next_window) { - if (e != s && e->b == b1) - break; - } + e = eb_find_window(b1, s); if (e) { /* no need to save mode data */ /* CG: bogus! e and s might have different modes */ @@ -4940,6 +4936,9 @@ void switch_to_buffer(EditState *s, EditBuffer *b) edit_set_mode(s, NULL); if (b1->flags & BF_TRANSIENT) { eb_free(&b1); + } else { + /* save buffer for predict_switch_to_buffer */ + s->last_buffer = s->b; } } @@ -4947,12 +4946,8 @@ void switch_to_buffer(EditState *s, EditBuffer *b) s->b = b; if (b) { - /* try to restore saved data from another window or from the - buffer saved data */ - for (e = qs->first_window; e != NULL; e = e->next_window) { - if (e != s && e->b == b) - break; - } + /* Try to get window mode and data from another window */ + e = eb_find_window(b, s); if (e) { mode = e->mode; saved_data = generic_mode_save_data(e); @@ -5016,6 +5011,7 @@ EditState *edit_new(EditBuffer *b, s = qe_mallocz(EditState); if (!s) return NULL; + s->qe_state = qs; s->screen = qs->screen; s->x1 = x1; @@ -5024,30 +5020,15 @@ EditState *edit_new(EditBuffer *b, s->y2 = y1 + height; s->flags = flags; compute_client_area(s); + /* link window in window list */ - s->next_window = qs->first_window; - /* CG: should append window to end of list, esp. for popups */ - qs->first_window = s; - if (!qs->active_window) - qs->active_window = s; + edit_attach(s, qs->first_window); + /* restore saved window settings, set mode */ switch_to_buffer(s, b); return s; } -/* find a window with a given buffer if any. */ -EditState *edit_find(EditBuffer *b) -{ - QEmacsState *qs = &qe_state; - EditState *e; - - for (e = qs->first_window; e != NULL; e = e->next_window) { - if (e->b == b) - break; - } - return e; -} - /* detach the window from the window tree. */ void edit_detach(EditState *s) { @@ -5065,11 +5046,24 @@ void edit_detach(EditState *s) qs->active_window = qs->first_window; } -/* attach the window to the window list. */ -void edit_attach(EditState *s, EditState **ep) +/* move a window before another one */ +void edit_attach(EditState *s, EditState *e) { - s->next_window = *ep; - *ep = s; + QEmacsState *qs = s->qe_state; + EditState *active_window = qs->active_window; + EditState **ep; + + if (s != e) { + edit_detach(s); + + for (ep = &qs->first_window; *ep; ep = &(*ep)->next_window) { + if (*ep == e) + break; + } + s->next_window = e; + *ep = s; + qs->active_window = active_window ? active_window : s; + } } /* close the edit window. If it is active, find another active @@ -5079,26 +5073,10 @@ void edit_close(EditState **sp) { if (*sp) { EditState *s = *sp; - QEmacsState *qs = s->qe_state; - EditState **ps; /* save current state for later window reattachment */ switch_to_buffer(s, NULL); - - /* detach from window list */ - ps = &qs->first_window; - while (*ps != NULL) { - if (*ps == s) { - *ps = s->next_window; - break; - } - ps = &(*ps)->next_window; - } - - /* if active window, select another active window */ - if (qs->active_window == s) - qs->active_window = qs->first_window; - + edit_detach(s); qe_free(&s->mode_data); qe_free(&s->prompt); qe_free(&s->line_shadow); @@ -5671,15 +5649,15 @@ void do_less_exit(EditState *s) } /* show a popup on a readonly buffer */ -void show_popup(EditBuffer *b) +EditState *show_popup(EditBuffer *b) { - EditState *s; QEmacsState *qs = &qe_state; + EditState *s = qs->active_window; int w, h, w1, h1; /* Prevent recursion */ - if (qs->active_window && qs->active_window->b == b) - return; + if (s && s->b == b) + return s; /* XXX: generic function to open popup ? */ w1 = qs->screen->width; @@ -5694,6 +5672,7 @@ void show_popup(EditBuffer *b) popup_saved_active = qs->active_window; qs->active_window = s; do_refresh(s); + return s; } static void less_init(void) @@ -5728,13 +5707,13 @@ EditState *insert_window_left(EditBuffer *b, int width, int flags) } e_new = edit_new(b, 0, 0, width, qs->height - qs->status_height, - flags | WF_RSEPARATOR); - do_refresh(qs->first_window); + flags | WF_POPLEFT | WF_RSEPARATOR); + do_refresh(e_new); return e_new; } /* return a window on the side of window 's' */ -EditState *find_window(EditState *s, int key) +EditState *find_window(EditState *s, int key, EditState *def) { QEmacsState *qs = s->qe_state; EditState *e; @@ -5760,41 +5739,35 @@ EditState *find_window(EditState *s, int key) return e; } } - return NULL; + return def; } void do_find_window(EditState *s, int key) { - QEmacsState *qs = s->qe_state; - EditState *e; - - e = find_window(s, key); - if (e) - qs->active_window = e; + s->qe_state->active_window = find_window(s, key, s); } #endif -/* give a good guess to the user for the next buffer */ +/* Give a good guess to the user for the next buffer */ static EditBuffer *predict_switch_to_buffer(EditState *s) { QEmacsState *qs = s->qe_state; - EditState *e; EditBuffer *b; + /* try and switch to the last buffer attached to the window */ + b = check_buffer(&s->last_buffer); + if (b) + return b; + + /* else try and switch to a buffer not shown in any window */ for (b = qs->first_buffer; b != NULL; b = b->next) { if (!(b->flags & BF_SYSTEM)) { - for (e = qs->first_window; e != NULL; e = e->next_window) { - if (e->b == b) - break; - } - if (!e) - goto found; + if (!eb_find_window(b, NULL)) + return b; } } - /* select current buffer if none found */ - b = s->b; - found: - return b; + /* otherwise select current buffer. */ + return s->b; } void do_switch_to_buffer(EditState *s, const char *bufname) @@ -5857,7 +5830,10 @@ void kill_buffer_noconfirm(EditBuffer *b) EditState *e; EditBuffer *b1; - // FIXME: used to delete windows containing the buffer ??? + /* Emacs makes any window showing the killed buffer switch to + * another buffer. + * An alternative is to delete windows showing the buffer. + */ /* find a new buffer to switch to */ for (b1 = qs->first_buffer; b1 != NULL; b1 = b1->next) { @@ -6045,15 +6021,20 @@ void do_set_next_mode(EditState *s, int dir) modes[found]->name, scores[found]); } -/* Should take bits from enumeration instead of booleans */ -static void do_load1(EditState *s, const char *filename1, - int kill_buffer, int load_resource, int bflags) +/* Load a file and attach buffer to window `s`. + * Return -1 if loading failed. + * Return 0 if file or resource was already loaded, + * Return 1 if file or resource was newly loaded, + * Return 2 if buffer was created for a new file. + * Should take bits from enumeration instead of booleans. + */ +int qe_load_file(EditState *s, const char *filename1, + int kill_buffer, int load_resource, int bflags) { u8 buf[4097]; char filename[MAX_FILENAME_SIZE]; - int st_mode, buf_size; + int st_mode, buf_size, mode_score; ModeDef *selected_mode; - int mode_score; EditBuffer *b; EditBufferDataType *bdt; FILE *f; @@ -6061,46 +6042,47 @@ static void do_load1(EditState *s, const char *filename1, EOLType eol_type = EOL_UNIX; QECharset *charset = &charset_utf8; +#ifndef CONFIG_TINY + /* avoid messing with the dired pane */ + if ((s->flags & WF_POPLEFT) && s->x1 == 0) { + EditState *e = find_window(s, KEY_RIGHT, NULL); + if (e) { + if (s->qe_state->active_window == s) + s->qe_state->active_window = e; + s = e; + } + } +#endif + if (load_resource) { if (find_resource_file(filename, sizeof(filename), filename1)) { /* XXX: issue error message? */ - return; + return -1; } } else { /* compute full name */ canonicalize_absolute_path(filename, sizeof(filename), filename1); } - ///* If file already shown in window, switch to that */ - //s1 = find_file_window(filename); - //if (s1 != NULL) { - // qs->active_window = s1; - // return; - //} - - ///* Split window if window large enough and not empty */ - //if (other_window && s->height > 10 && s->b->total_size > 0) { - // do_split_window(s, 0, 0); - // s = qs->active_window; - //} - - if (kill_buffer && s->b) { - /* CG: this behaviour is not correct */ - /* CG: should have a direct primitive */ - do_kill_buffer(s, s->b->name); - } - /* If file already loaded in existing buffer, switch to that */ b = eb_find_file(filename); if (b != NULL) { switch_to_buffer(s, b); - return; + return 0; + } + + /* We are going to try and load a new file: potentially delete the + * current buffer if requested. + */ + if (kill_buffer && s->b && !s->b->modified) { + s->b->flags |= BF_TRANSIENT; } /* Create new buffer with unique name from filename */ b = eb_new("", BF_SAVELOG | bflags); eb_set_filename(b, filename); + /* XXX: should actually initialize SAVED_DATA area in new buffer */ s->offset = 0; /* XXX: Should test for full width and WRAP_TRUNCATE if not */ s->wrap = WRAP_LINE; /* default mode may override this */ @@ -6128,7 +6110,7 @@ static void do_load1(EditState *s, const char *filename1, if (b->data_type == &raw_data_type) put_status(s, "(New file)"); do_load_qerc(s, s->b->filename); - return; + return 2; } else { b->st_mode = st_mode = st.st_mode; buf_size = 0; @@ -6179,7 +6161,7 @@ static void do_load1(EditState *s, const char *filename1, /* XXX: invalid place */ edit_invalidate(s); - return; + return 1; } fail: @@ -6187,6 +6169,7 @@ static void do_load1(EditState *s, const char *filename1, put_status(s, "Could not open '%s': %s", filename, strerror(errno)); + return -1; } #if 0 @@ -6224,25 +6207,28 @@ static void load_completion_cb(void *opaque, int err) void do_find_file(EditState *s, const char *filename, int bflags) { - do_load1(s, filename, 0, 0, bflags); + qe_load_file(s, filename, 0, 0, bflags); } void do_find_file_other_window(EditState *s, const char *filename, int bflags) { - QEmacsState *qs = s->qe_state; - - do_split_window(s, 0); - do_load1(qs->active_window, filename, 0, 0, bflags); + /* Split window if window large enough and not empty */ + /* XXX: should check s->height units */ + if (s->height > 10 && s->b->total_size > 0) { + do_split_window(s, 0); + s = s->qe_state->active_window; + } + qe_load_file(s, filename, 0, 0, bflags); } void do_find_alternate_file(EditState *s, const char *filename, int bflags) { - do_load1(s, filename, 1, 0, bflags); + qe_load_file(s, filename, 1, 0, bflags); } void do_load_file_from_path(EditState *s, const char *filename, int bflags) { - do_load1(s, filename, 0, 1, bflags); + qe_load_file(s, filename, 0, 1, bflags); } void do_insert_file(EditState *s, const char *filename) @@ -6608,9 +6594,8 @@ void do_previous_window(EditState *s) void do_delete_window(EditState *s, int force) { QEmacsState *qs = s->qe_state; - EditState *e; - int count, x1, y1, x2, y2; - int ex1, ey1, ex2, ey2; + EditState *e, *e1 = NULL; + int count, pass, x1, y1, x2, y2; count = 0; for (e = qs->first_window; e != NULL; e = e->next_window) { @@ -6622,47 +6607,53 @@ void do_delete_window(EditState *s, int force) return; if (!(s->flags & WF_POPUP)) { - /* try to merge the window with one adjacent window. If none - found, just leave a hole */ + /* Try to merge the window with adjacent windows. + * If this cannot be done, just leave a hole and force full + * redisplay. + */ x1 = s->x1; x2 = s->x2; y1 = s->y1; y2 = s->y2; - for (e = qs->first_window; e != NULL; e = e->next_window) { - if (e->minibuf || e == s) - continue; - ex1 = e->x1; - ex2 = e->x2; - ey1 = e->y1; - ey2 = e->y2; + for (pass = 0; pass < 2; pass++) { + for (e = qs->first_window; e != NULL; e = e->next_window) { + if (e->minibuf || e == s || (e->flags & WF_POPUP)) + continue; - if (x1 == ex2 && y1 == ey1 && y2 == ey2) { - /* left border */ - e->x2 = x2; - break; - } else - if (x2 == ex1 && y1 == ey1 && y2 == ey2) { - /* right border */ - e->x1 = x1; - break; - } else - if (y1 == ey2 && x1 == ex1 && x2 == ex2) { - /* top border */ - e->y2 = y2; - break; - } else - if (y2 == ey1 && x1 == ex1 && x2 == ex2) { - /* bottom border */ - e->y1 = y1; - break; + if (x1 == e->x2 && y1 == e->y1 && y2 >= e->y2) { + /* partial vertical split along the left border */ + e->x2 = x2; + y1 = e->y2; + } else + if (x2 == e->x1 && y1 == e->y1 && y2 >= e->y2) { + /* partial vertical split along the right border */ + e->x1 = x1; + y1 = e->y2; + } else + if (y1 == e->y2 && x1 == e->x1 && x2 >= e->x2) { + /* partial horizontal split along the top border */ + e->y2 = y2; + x1 = e->x2; + } else + if (y2 == e->y1 && x1 == e->x1 && x2 >= e->x2) { + /* partial horizontal split along bottom border */ + e->y1 = y1; + x1 = e->x2; + } else { + continue; + } + compute_client_area(e1 = e); } + if (x1 == x2 || y1 == y2) + break; } - if (e) - compute_client_area(e); + if (x1 != x2 && y1 != y2) + qs->complete_refresh = 1; } if (qs->active_window == s) - qs->active_window = e ? e : qs->first_window; + qs->active_window = e1 ? e1 : qs->first_window; + edit_close(&s); if (qs->first_window) do_refresh(qs->first_window); @@ -6673,6 +6664,9 @@ void do_delete_other_windows(EditState *s) QEmacsState *qs = s->qe_state; EditState *e, *e1; + if (s->minibuf || (s->flags & WF_POPUP)) + return; + for (e = qs->first_window; e != NULL; e = e1) { e1 = e->next_window; if (!e->minibuf && e != s) @@ -6718,8 +6712,7 @@ void do_split_window(EditState *s, int horiz) s->y2 = y; } /* insert in the window list after current window */ - edit_detach(e); - edit_attach(e, &s->next_window); + edit_attach(e, s->next_window); if (qs->flag_split_window_change_focus) qs->active_window = e; diff --git a/qe.h b/qe.h index 958bc4f..c2e935f 100644 --- a/qe.h +++ b/qe.h @@ -859,6 +859,8 @@ typedef struct EditBufferDataType { #define BF_STYLE1 0x1000 /* buffer has 1 byte styles */ #define BF_STYLE2 0x2000 /* buffer has 2 byte styles */ #define BF_STYLE4 0x3000 /* buffer has 4 byte styles */ +#define BF_IS_STYLE 0x4000 /* buffer is a styles buffer */ +#define BF_IS_LOG 0x8000 /* buffer is a log buffer */ struct EditBuffer { OWNED Page *page_table; @@ -927,9 +929,9 @@ struct EditBuffer { /* CG: should instead keep a pointer to last window using this * buffer, even if no longer on screen */ - struct ModeDef *default_mode; - struct ModeDef *saved_mode; - OWNED struct ModeSavedData *saved_data; + ModeDef *default_mode; + ModeDef *saved_mode; + OWNED ModeSavedData *saved_data; /* default mode stuff when buffer is detached from window */ int offset; @@ -1171,6 +1173,8 @@ struct EditState { EditBuffer *b; + EditBuffer *last_buffer; /* for predict_switch_to_buffer */ + /* mode specific info */ ModeDef *mode; void *mode_data; /* mode private data */ @@ -1205,6 +1209,7 @@ struct EditState { #define WF_POPUP 0x0001 /* popup window (with borders) */ #define WF_MODELINE 0x0002 /* mode line must be displayed */ #define WF_RSEPARATOR 0x0004 /* right window separator */ +#define WF_POPLEFT 0x0008 /* left side window */ OWNED char *prompt; /* optional window prompt, utf8, owned by the window */ //const char *mode_line; @@ -1751,15 +1756,19 @@ static inline int is_user_input_pending(void) { } #endif +/* file loading */ +int qe_load_file(EditState *s, const char *filename1, + int kill_buffer, int load_resource, int bflags); + /* config file support */ void do_load_config_file(EditState *e, const char *file); void do_load_qerc(EditState *e, const char *file); /* popup / low level window handling */ -void show_popup(EditBuffer *b); +EditState *show_popup(EditBuffer *b); int check_read_only(EditState *s); EditState *insert_window_left(EditBuffer *b, int width, int flags); -EditState *find_window(EditState *s, int key); +EditState *find_window(EditState *s, int key, EditState *def); void do_find_window(EditState *s, int key); /* window handling */ @@ -1767,8 +1776,8 @@ void edit_close(EditState **sp); EditState *edit_new(EditBuffer *b, int x1, int y1, int width, int height, int flags); void edit_detach(EditState *s); +EditBuffer *check_buffer(EditBuffer **sp); EditState *check_window(EditState **sp); -EditState *edit_find(EditBuffer *b); void do_refresh(EditState *s); // should take direction argument void do_other_window(EditState *s); @@ -1939,7 +1948,7 @@ void do_call_macro(EditState *s); void do_execute_macro_keys(EditState *s, const char *keys); void do_define_kbd_macro(EditState *s, const char *name, const char *keys, const char *key_bind); -void edit_attach(EditState *s, EditState **ep); +void edit_attach(EditState *s, EditState *e); void do_completion(EditState *s); void do_completion_space(EditState *s); void do_electric_filename(EditState *s, int key); diff --git a/shell.c b/shell.c index 145f466..db1a65c 100644 --- a/shell.c +++ b/shell.c @@ -52,10 +52,8 @@ enum TTYState { TTY_STATE_STRING, }; -static int shell_signature; - typedef struct ShellState { - void *signature; + ModeDef *signature; /* buffer state */ int pty_fd; int pid; /* -1 if not launched */ @@ -659,7 +657,7 @@ static ShellState *shell_get_state(EditState *e, int status) { ShellState *s = e->b->priv_data; - if (s && s->signature == &shell_signature) + if (s && s->signature == &shell_mode) return s; if (status) @@ -687,7 +685,7 @@ static void shell_key(void *opaque, int key) const char *p; int len; - if (!s || s->signature != &shell_signature) + if (!s || s->signature != &shell_mode) return; if (key == KEY_CTRL('o')) { @@ -1244,7 +1242,7 @@ static void shell_read_cb(void *opaque) unsigned char buf[16 * 1024]; int len, i; - if (!s || s->signature != &shell_signature) + if (!s || s->signature != &shell_mode) return; qs = s->qe_state; @@ -1279,7 +1277,7 @@ static void shell_close(EditBuffer *b) ShellState *s = b->priv_data; int status; - if (!s || s->signature != &shell_signature) + if (!s || s->signature != &shell_mode) return; eb_free_callback(b, eb_offset_callback, &s->cur_offset); @@ -1317,7 +1315,7 @@ static void shell_pid_cb(void *opaque, int status) EditState *e; char buf[1024]; - if (!s || s->signature != &shell_signature) + if (!s || s->signature != &shell_mode) return; b = s->b; @@ -1395,7 +1393,7 @@ EditBuffer *new_shell_buffer(EditBuffer *b0, const char *bufname, b = b0; if (b) { s = b->priv_data; - if (s && s->signature != &shell_signature) + if (s && s->signature != &shell_mode) return NULL; if (shell_flags & SF_COLOR) eb_create_style_buffer(b, BF_STYLE2); @@ -1426,7 +1424,7 @@ EditBuffer *new_shell_buffer(EditBuffer *b0, const char *bufname, eb_free(&b); return NULL; } - s->signature = &shell_signature; + s->signature = &shell_mode; b->priv_data = s; b->close = shell_close; /* Track cursor with edge effect */ @@ -1466,7 +1464,7 @@ static EditBuffer *try_show_buffer(EditState *s, const char *bufname) b = eb_find(bufname); if (b) { - e = edit_find(b); + e = eb_find_window(b, NULL); if (e) qs->active_window = e; else @@ -1480,26 +1478,33 @@ static void do_shell(EditState *s, int force) ShellState *shs; EditBuffer *b = NULL; + if (s->flags & WF_POPLEFT) { + /* avoid messing with the dired pane */ + s = find_window(s, KEY_RIGHT, s); + s->qe_state->active_window = s; + } + /* CG: Should prompt for buffer name if arg: * find a syntax for optional string argument w/ prompt */ /* find shell buffer if any */ if (!force || force == NO_ARG) { /* XXX: if current buffer is a shell buffer without a process, - * restart shell process. + * restart shell process in it. */ b = s->b; shs = b->priv_data; if (strstart(b->name, "*shell*", NULL) - && shs && shs->signature == &shell_signature) { + && shs && shs->signature == &shell_mode) { if (shs->pid >= 0) return; } else { + /* XXX: should find the last used shell buffer */ b = try_show_buffer(s, "*shell*"); if (b) { shs = b->priv_data; if (shs) { - if (shs->signature != &shell_signature) { + if (shs->signature != &shell_mode) { b = NULL; } else if (shs->pid >= 0) @@ -1960,7 +1965,7 @@ static int shell_mode_probe(ModeDef *mode, ModeProbeData *p) { if (p->b && p->b->priv_data) { ShellState *s = p->b->priv_data; - if (s->signature == &shell_signature) { + if (s->signature == &shell_mode) { if (s->shell_flags & SF_INTERACTIVE) return 100; }