diff --git a/TODO.md b/TODO.md index 2432287..b50c863 100644 --- a/TODO.md +++ b/TODO.md @@ -5,8 +5,6 @@ ## Current work * pass `indent` to `ColorizeFunc`. -* `S-TAB` -> untabify -* `TAB` and `S-TAB` with selected block -> indent, unindent block * `TAB` -> complete function name etc. * add parametric syntax definitions (nanorc files). * should implement a maximum macro length and abort macro learning mode if reached @@ -128,7 +126,6 @@ both in `strtokey` * fix `eb_prev_char` to handle non self-synchronizing charsets * auto/mixed eol mode * `set-eol-type` should take a string: auto/binary/dos/unix/mac/0/1/2... -* display `^L` as horizontal line and consider as linebreak character * handle zero width codepoints: cp="200B" na="ZERO WIDTH SPACE" alias="ZWSP" cp="200C" na="ZERO WIDTH NON-JOINER" alias="ZWNJ" @@ -156,6 +153,7 @@ both in `strtokey` * fix current position when changing buffer attached to window * fix default wrap setting mess * display: add screen dump command and format +* display `^L` as horizontal line and consider as linebreak character * colorize extra `^M` and `^Z` as preproc at end of line prior to calling the syntax highlighter (same as BOM) * colorizer bug on **/comp/projects/fractal/fractint/ORGFORM/NOEL-2.FRM** (triple `^M`) * display bug on **~/comp/projects/fractal/fractint/ORGFORM/BAILOUT.FRM** (double `^M`) @@ -211,6 +209,9 @@ insert_window_left() deletes some left-most windows * fix column computation based on display properties: (variable pitch, tabs, ^x and \uxxxx stuff -- emacs behaviour) ? +* tag left-view with electric navigation +* expand / collapse region + ## X11 display / graphics * handle X11 window manager close window event and exit cleanly @@ -278,7 +279,6 @@ insert_window_left() deletes some left-most windows * `what-cursor-position` with universal prefix: show popup with long description * `compare-windows` should resync from the end of line. * `elastic-tabs` - * `indent-rigidly` * `show-matching-delimiters` * blink-and-insert on `) } ] >` * `set-gosmacs-bindings` -> `set_emulation("gosmacs")` diff --git a/extras.c b/extras.c index 1537a28..41441b6 100644 --- a/extras.c +++ b/extras.c @@ -724,12 +724,75 @@ static void do_indent_region(EditState *s, int start, int end) (s->mode->indent_func)(s, eb_goto_pos(s->b, line1, 0)); } else { s->offset = eb_goto_pos(s->b, line1, 0); - do_tab(s, 1); + do_tabulate(s, 1); } } s->offset = eb_goto_eol(s->b, s->offset); } +void do_indent_rigidly(EditState *s, int start, int end, int argval) +{ + int col_num, line1, line2; + + if (argval == NO_ARG) { + // enter interactive mode + QEmacsState *qs = s->qe_state; + if (!qs->first_transient_key) { + s->region_style = QE_STYLE_REGION_HILITE; + put_status(s, "indent the region interactively with TAB, left, right, S-left, S-right"); + qe_register_transient_binding(qs, "indent-rigidly-left", "left"); + qe_register_transient_binding(qs, "indent-rigidly-right", "right"); + qe_register_transient_binding(qs, "indent-rigidly-left-to-tab-stop", "S-left, S-TAB"); + qe_register_transient_binding(qs, "indent-rigidly-right-to-tab-stop", "S-right, TAB"); + } + return; + } + + /* Swap point and mark so mark <= point */ + if (end < start) { + int tmp = start; + end = start; + start = tmp; + } + /* We do it with lines to avoid offset variations during indenting */ + eb_get_pos(s->b, &line1, &col_num, start); + eb_get_pos(s->b, &line2, &col_num, end); + + if (col_num == 0) + line2--; + + /* Iterate over all lines inside block */ + //s->b->mark = eb_goto_bol(s->b, start); + for (; line1 <= line2; line1++) { + int offset = eb_goto_pos(s->b, line1, 0); + int off1, off2; + int indent = find_indent(s, offset, 0, &off1); + int new_indent = max_int(0, indent + argval); + if (eb_nextc(s->b, off1, &off2) == '\n') + new_indent = 0; + make_indent(s, offset, off1, 0, new_indent); + } + //s->offset = eb_goto_eol(s->b, s->offset); +} + +static void do_indent_rigidly_to_tab_stop(EditState *s, int start, int end, int dir) { + int tw = s->b->tab_width > 0 ? s->b->tab_width : DEFAULT_TAB_WIDTH; + int indent = s->indent_size > 0 ? s->indent_size : tw; + + do_indent_rigidly(s, start, end, indent * dir); +} + +static void do_untabulate(EditState *s) { + if (s->region_style) { + do_indent_rigidly_to_tab_stop(s, s->b->mark, s->offset, -1); + } else { + // FIXME: should decrease indentation at s->offset + int start = eb_goto_bol(s->b, s->offset); + int end = eb_goto_eol(s->b, s->offset); + do_indent_rigidly_to_tab_stop(s, start, end, -1); + } +} + void do_show_date_and_time(EditState *s, int argval) { time_t t = argval; @@ -2612,6 +2675,24 @@ static const CmdDef extra_commands[] = { CMD2( "indent-buffer", "", "Indent each nonblank line in the buffer", do_indent_region, ESii, "*" "ze") + CMD2( "indent-rigidly", "C-x TAB", + "Indent the region interactively", + do_indent_rigidly, ESiii, "*" "md" "P") + CMD3( "indent-rigidly-left", "", + "Decrease the region indentation", + do_indent_rigidly, ESiii, "*" "md" "v", -1) + CMD3( "indent-rigidly-right", "", + "Increase the region indentation", + do_indent_rigidly, ESiii, "*" "md" "v", +1) + CMD3( "indent-rigidly-left-to-tab-stop", "", + "Decrease the region indentation by one tab", + do_indent_rigidly_to_tab_stop, ESiii, "*" "md" "v", -1) + CMD3( "indent-rigidly-right-to-tab-stop", "", + "Increase the region indentation by one tab", + do_indent_rigidly_to_tab_stop, ESiii, "*" "md" "v", +1) + CMD2( "untabulate", "S-TAB", + "Decrease indentation", + do_untabulate, ES, "*") CMD2( "show-date-and-time", "C-x t", "Show current date and time", diff --git a/lang/clang.c b/lang/clang.c index 7fb8e00..19f55be 100644 --- a/lang/clang.c +++ b/lang/clang.c @@ -1121,11 +1121,12 @@ done: static void do_c_indent(EditState *s) { - if (eb_is_in_indentation(s->b, s->offset) + if (!s->region_style + && eb_is_in_indentation(s->b, s->offset) && s->qe_state->last_cmd_func != (CmdFunc)do_c_indent) { c_indent_line(s, s->offset); } else { - do_tab(s, 1); + do_tabulate(s, 1); } } diff --git a/modes/shell.c b/modes/shell.c index c4a24b8..f2e1e6e 100644 --- a/modes/shell.c +++ b/modes/shell.c @@ -3157,6 +3157,7 @@ static void do_shell_tabulate(EditState *e) if (e->interactive) { shell_write_char(e, 9); } else { + //do_tabulate(s, 1); text_write_char(e, 9); } } diff --git a/qe.c b/qe.c index cac6f76..d895c3f 100644 --- a/qe.c +++ b/qe.c @@ -1042,7 +1042,7 @@ void do_backspace(EditState *s, int argval) if (argval == NO_ARG) { // XXX: this does not work for c-mode // XXX: should implement backward-delete-char-untabify instead - if (s->qe_state->last_cmd_func == (CmdFunc)do_tab + if (s->qe_state->last_cmd_func == (CmdFunc)do_tabulate && !s->indent_tabs_mode && !s->multi_cursor_active) { /* Delete tab or indentation? */ do_undo(s); @@ -1926,17 +1926,86 @@ void do_overwrite_mode(EditState *s, int argval) { put_status(s, "Overwrite mode is %s", s->overwrite ? "on" : "off"); } -void do_tab(EditState *s, int argval) +/* get the indentation width at a given offset */ +int find_indent(EditState *s, int offset, int pos, int *offsetp) { + int tw = s->b->tab_width > 0 ? s->b->tab_width : 8; + int offset1; + for (;; offset = offset1) { + char32_t c = eb_nextc(s->b, offset, &offset1); + if (c == '\t') + pos += tw - (pos % tw); + else if (c == ' ') + pos++; + else + break; + } + *offsetp = offset; + return pos; +} + +static void get_indent_chars(EditState *s, int pos, int target, + int *ptabs, int *pspaces) { + int tabs = 0, spaces = 0; + if (target > pos) { + if (s->indent_tabs_mode) { + int tw = s->b->tab_width > 0 ? s->b->tab_width : 8; + while (target >= pos + tw - pos % tw) { + tabs++; + pos += tw - pos % tw; + } + } + spaces = target - pos; + } + *ptabs = tabs; + *pspaces = spaces; +} + +/* replace characters in region with specified TABs and spaces */ +static int replace_indent(EditState *s, int offset, int end, int tabs, int spaces) { + int offset1; + while (offset < end) { + char32_t c = eb_nextc(s->b, offset, &offset1); + if (tabs && c == '\t') { + tabs--; + } else + if (spaces && c == ' ') { + spaces--; + } else { + break; + } + offset = offset1; + } + eb_delete_range(s->b, offset, end); + offset += eb_insert_char32_n(s->b, offset, '\t', tabs); + offset += eb_insert_char32_n(s->b, offset, ' ', spaces); + return offset; +} + +int make_indent(EditState *s, int offset, int end, int pos, int target) { + int tabs, spaces; + get_indent_chars(s, pos, target, &tabs, &spaces); + return replace_indent(s, offset, end, tabs, spaces); +} + +void do_tabulate(EditState *s, int argval) +{ + int tw = s->b->tab_width > 0 ? s->b->tab_width : DEFAULT_TAB_WIDTH; + int indent = s->indent_size > 0 ? s->indent_size : tw; + /* CG: should do smart complete, smart indent, insert tab */ +#ifndef CONFIG_TINY + if (s->region_style) { + do_indent_rigidly(s, s->b->mark, s->offset, indent); + return; + } +#endif if (s->indent_tabs_mode) { do_char(s, '\t', argval); } else { int offset = s->offset; int offset0 = eb_goto_bol(s->b, offset); int col = 0; - int tw = s->b->tab_width > 0 ? s->b->tab_width : DEFAULT_TAB_WIDTH; - int indent = s->indent_size > 0 ? s->indent_size : tw; while (offset0 < offset) { char32_t c = eb_nextc(s->b, offset0, &offset0); @@ -10330,10 +10399,10 @@ static const CmdDef basic_commands[] = { do_char, ESii, "*" "n{Insert char: }[charname]|charvalue|" "p") - /* do_tab will not change read only buffer */ + /* do_tabulate will not change read only buffer */ CMD2( "tabulate", "TAB", "Insert a TAB or spaces according to indent-tabs-mode", - do_tab, ESi, "p") + do_tabulate, ESi, "p") //CMD2( "space", "SPC", "Insert a space", do_space, ESi, "*" "P") CMD2( "quoted-insert", "C-q", "Read next input character and insert it", diff --git a/qe.h b/qe.h index cf074b0..cb454aa 100644 --- a/qe.h +++ b/qe.h @@ -1502,7 +1502,7 @@ void do_newline(EditState *s); void do_open_line(EditState *s); void do_backspace(EditState *s, int argval); void do_delete_char(EditState *s, int argval); -void do_tab(EditState *s, int argval); +void do_tabulate(EditState *s, int argval); EditBuffer *new_yank_buffer(QEmacsState *qs, EditBuffer *base); void do_append_next_kill(EditState *s); void do_kill(EditState *s, int p1, int p2, int dir, int keep); @@ -1585,6 +1585,8 @@ void do_toggle_truncate_lines(EditState *s); void do_word_wrap(EditState *s); void do_count_lines(EditState *s); void do_what_cursor_position(EditState *s); +int find_indent(EditState *s, int offset, int pos, int *offsetp); +int make_indent(EditState *s, int offset, int end, int pos, int target); void do_set_tab_width(EditState *s, int tab_width); void do_set_indent_width(EditState *s, int indent_width); void do_set_indent_tabs_mode(EditState *s, int val); @@ -1762,6 +1764,7 @@ void do_compare_windows(EditState *s, int argval); void do_compare_files(EditState *s, const char *filename, int bflags); void do_delete_horizontal_space(EditState *s); void do_show_date_and_time(EditState *s, int argval); +void do_indent_rigidly(EditState *s, int start, int end, int argval); enum { CMD_TRANSPOSE_CHARS = 1,