From: NeilBrown Date: Thu, 8 Jun 2023 05:54:34 +0000 (+1000) Subject: emacs: add CX-< and CX-> to scroll left or right. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=fef0b282dba06fc0b02bb5aeca6268f380be8408;p=edlib.git emacs: add CX-< and CX-> to scroll left or right. The first CX-< switch from wrapping to no-wrapping. Then it shifts 8 units at a time, unless a number is given. Signed-off-by: NeilBrown --- diff --git a/DOC/TODO.md b/DOC/TODO.md index 94ae699f..44c1f573 100644 --- a/DOC/TODO.md +++ b/DOC/TODO.md @@ -9,7 +9,7 @@ the file. ### Trivial -= [ ] :Cx-< and :Cx-> to shift view left and right and disable wrap +- [X] :Cx-< and :Cx-> to shift view left and right and disable wrap - [ ] Unify edlib_timing and pane_too_long ?? - [X] If an email part doesn't end with newline, last character is swallowed. - [X] What is rule for doc:content? Does the mark move and get passed @@ -251,6 +251,9 @@ Module features - [ ] sort the command names for command-completion? Currently lines are inserted into buffer. I need to store in an array first, then qsort() +- [ ] Do I want a 'truncated' marker at start/end of line when not + wrapping, and does the '\' go away properly when I start shifting. +- [ ] change shift left/right to work in characters rather than pixels - [ ] filename completion should ignore uninteresting files like ".o" Maybe use .gitignore, or have config module understand that. - [ ] maybe alt-, does c-x` if that is the recent search? diff --git a/mode-emacs.c b/mode-emacs.c index dd018f00..a2462e2b 100644 --- a/mode-emacs.c +++ b/mode-emacs.c @@ -39,6 +39,7 @@ enum { N2_undo, /* Last command was 'undo' too */ N2_close_others,/* Last command was close-other, just a 1 can repeat */ N2_runmacro, /* Last command was CX-e, just an 'e' can repeat */ + N2_shift, /* Laset command was CX-< or CX-> */ }; static inline int N2(const struct cmd_info *ci safe) { @@ -2631,6 +2632,54 @@ DEF_CMD(emacs_readonly) return 1; } +DEF_CMD(emacs_shift) +{ + int rpt = ci->num; + int shift; + + shift = pane_attr_get_int(ci->focus, "shift-left", -1); + if (strcmp(ci->key, "K:CX->") == 0 || strcmp(ci->key, "K->") == 0) + rpt = -rpt; + if (rpt == NO_NUMERIC) { + if (shift < 0) + shift = 0; + else + shift += 8; + } else if (rpt == -NO_NUMERIC) { + if (shift >= 8) + shift -= 8; + else if (shift > 0) + shift = 0; + else + shift = -1; + } else if (rpt >= 0) { + if (shift < 0) + shift = 0; + shift += rpt; + } else { + if (shift > 0 && shift + rpt < 0) + shift = 0; + else + shift += rpt; + } + if (shift < 0) + attr_set_str(&ci->focus->attrs, "shift-left", ""); + else + attr_set_int(&ci->focus->attrs, "shift-left", shift); + call("view:changed", ci->focus); + call("Mode:set-num2", ci->focus, N2_shift); + call("Message:modal", ci->focus, 0, NULL, "Type < or > to shift again"); + return 1; +} + +DEF_CMD(emacs_shift_again) +{ + if (N2(ci) != N2_shift) + return emacs_insert_func(ci); + else + return emacs_shift_func(ci); +} + DEF_CMD(emacs_curs_pos) { struct mark *c; @@ -3159,6 +3208,11 @@ static void emacs_init(void) key_add(m, "K:CX-=", &emacs_curs_pos); key_add(m, "K:A-=", &emacs_word_count); + key_add(m, "K:CX-<", &emacs_shift); + key_add(m, "K:CX->", &emacs_shift); + key_add(m, "K-<", &emacs_shift_again); + key_add(m, "K->", &emacs_shift_again); + key_add(m, "K:C-S", &emacs_start_search); key_add(m, "K:C-R", &emacs_start_search); key_add(m, "K:A-%", &emacs_start_search); diff --git a/render-lines.c b/render-lines.c index 2c1ecb7e..4f581a5a 100644 --- a/render-lines.c +++ b/render-lines.c @@ -110,7 +110,8 @@ struct rl_data { short i_moved; /* I moved cursor, so don't clear * target */ - int do_wrap; + short do_wrap; + short shift_locked; short shift_left; short shift_left_last_refresh; struct mark *header; @@ -544,7 +545,8 @@ static void find_lines(struct mark *pm safe, struct pane *p safe, * call_render_line() will have created 'end' if it didn't exist. */ - rl->shift_left = 0; + if (!rl->shift_locked) + rl->shift_left = 0; /* ->cy is top of cursor, we want to measure from bottom */ if (start->mdata) { @@ -554,7 +556,7 @@ static void find_lines(struct mark *pm safe, struct pane *p safe, curs_width = pane_attr_get_int( start->mdata, "curs_width", 1); - while (!rl->do_wrap && curs_width > 0 && + while (!rl->do_wrap && !rl->shift_locked && curs_width > 0 && hp->cx + curs_width >= p->w) { int shift = 8 * curs_width; if (shift > hp->cx) @@ -869,7 +871,7 @@ DEF_CMD(render_lines_get_attr) if (ci->str && strcmp(ci->str, "shift_left") == 0) { char ret[10]; - if (rl->do_wrap) + if (rl->do_wrap && !rl->shift_locked) return comm_call(ci->comm2, "cb", ci->focus, 0, NULL, "-1"); snprintf(ret, sizeof(ret), "%d", rl->shift_left); @@ -918,7 +920,7 @@ static int revalidate_start(struct rl_data *rl safe, /* This loop is fragile and sometimes spins. So ensure we * never loop more than 1000 times. */ - if (pm && !rl->do_wrap && shifts++ < 1000) { + if (pm && !rl->do_wrap && !rl->shift_locked && shifts++ < 1000) { int prefix_len; int curs_width; /* Need to check if side-shift is needed on cursor line */ @@ -1095,6 +1097,7 @@ DEF_CMD(render_lines_revise) bool refresh_all = False; char *hdr; char *a; + int shift; a = pane_attr_get(focus, "render-wrap"); if (rl->do_wrap != (!a || strcmp(a, "yes") ==0)) { @@ -1102,6 +1105,25 @@ DEF_CMD(render_lines_revise) refresh_all = True; } + shift = pane_attr_get_int(focus, "shift-left", -1); + if (shift >= 0) { + if (rl->shift_left != shift) + refresh_all = True; + + rl->shift_left = shift; + rl->shift_locked = 1; + } else { + if (rl->shift_locked) + refresh_all = True; + rl->shift_locked = 0; + } + if (refresh_all) { + struct mark *v; + for (v = vmark_first(focus, rl->typenum, p); + (v && v->mdata) ; v = vmark_next(v)) + pane_damaged(v->mdata, DAMAGED_REFRESH); + } + rl->margin = pane_attr_get_int(focus, "render-vmargin", 0); if (rl->margin >= p->h/2) rl->margin = p->h/2;