Improve indentation commands

* add `find_indent` and `make_indent` ancillary functions
* add `untabulate` on `S-TAB` to remove one indentation level
* rename `do_tab` as `do_tabulate` for consistency
* `tabulate` indents the region one level if visible
* add `indent-rigidly` commands: indent block interactively
This commit is contained in:
oguillaumin 2024-08-13 21:37:29 +02:00 • committed by Charlie Gordon
commit 1d3cabeaa2
6 changed files with 169 additions and 14 deletions

View file

@ -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")`

View file

@ -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",

View file

@ -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);
}
}

View file

@ -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);
}
}

81
qe.c
View file

@ -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",

5
qe.h
View file

@ -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,