commit 2367f3d8e66b6f794850cc85b6bb85c6d789b286
parent 684fc8f84ae762ca2e2191543afe1a5b400a79f5
Author: David Lawrence Ramsey <pooka109@gmail.com>
Date: Mon, 10 Jul 2017 15:48:50 -0500
text: make do_unindent() an exact copy of do_indent()
This is the first step toward splitting them into two dedicated
functions, instead of letting do_indent() handle both cases.
Diffstat:
3 files changed, 165 insertions(+), 8 deletions(-)
diff --git a/src/global.c b/src/global.c
@@ -931,7 +931,7 @@ void shortcut_init(void)
#ifndef NANO_TINY
add_to_funcs(do_indent_void, MMAIN,
N_("Indent Text"), IFSCHELP(nano_indent_msg), TOGETHER, NOVIEW);
- add_to_funcs(do_unindent, MMAIN,
+ add_to_funcs(do_unindent_void, MMAIN,
N_("Unindent Text"), IFSCHELP(nano_unindent_msg), BLANKAFTER, NOVIEW);
#endif
#ifdef ENABLE_WORDCOMPLETION
@@ -1106,7 +1106,7 @@ void shortcut_init(void)
add_to_sclist(MMAIN, "M-6", 0, do_copy_text, 0);
add_to_sclist(MMAIN, "M-^", 0, do_copy_text, 0);
add_to_sclist(MMAIN, "M-}", 0, do_indent_void, 0);
- add_to_sclist(MMAIN, "M-{", 0, do_unindent, 0);
+ add_to_sclist(MMAIN, "M-{", 0, do_unindent_void, 0);
add_to_sclist(MMAIN, "M-U", 0, do_undo, 0);
add_to_sclist(MMAIN, "M-E", 0, do_redo, 0);
#endif
@@ -1490,7 +1490,7 @@ sc *strtosc(const char *input)
else if (!strcasecmp(input, "indent"))
s->scfunc = do_indent_void;
else if (!strcasecmp(input, "unindent"))
- s->scfunc = do_unindent;
+ s->scfunc = do_unindent_void;
else if (!strcasecmp(input, "scrollup"))
s->scfunc = do_scroll_up;
else if (!strcasecmp(input, "scrolldown"))
diff --git a/src/proto.h b/src/proto.h
@@ -525,7 +525,8 @@ void do_tab(void);
#ifndef NANO_TINY
void do_indent(ssize_t cols);
void do_indent_void(void);
-void do_unindent(void);
+void do_unindent(ssize_t cols);
+void do_unindent_void(void);
#endif
bool white_string(const char *s);
#ifdef ENABLE_COMMENT
diff --git a/src/text.c b/src/text.c
@@ -440,11 +440,167 @@ void do_indent_void(void)
do_indent(tabsize);
}
-/* Unindent the current line, or all lines covered by the mark if the
- * mark is on, tabsize columns. */
-void do_unindent(void)
+/* Indent or unindent the current line (or, if the mark is on, all lines
+ * covered by the mark) len columns, depending on whether len is
+ * positive or negative. If the TABS_TO_SPACES flag is set, indent or
+ * unindent by len spaces. Otherwise, indent or unindent by (len /
+ * tabsize) tabs and (len % tabsize) spaces. */
+void do_unindent(ssize_t cols)
+{
+ bool indent_changed = FALSE;
+ /* Whether any indenting or unindenting was done. */
+ bool unindent = FALSE;
+ /* Whether we're unindenting text. */
+ char *line_indent = NULL;
+ /* The text added to each line in order to indent it. */
+ size_t line_indent_len = 0;
+ /* The length of the text added to each line in order to indent
+ * it. */
+ filestruct *top, *bot, *f;
+ size_t top_x, bot_x;
+
+ assert(openfile->current != NULL && openfile->current->data != NULL);
+
+ /* If cols is zero, get out. */
+ if (cols == 0)
+ return;
+
+ /* If cols is negative, make it positive and set unindent to TRUE. */
+ if (cols < 0) {
+ cols = -cols;
+ unindent = TRUE;
+ /* Otherwise, we're indenting, in which case the file will always be
+ * modified, so set indent_changed to TRUE. */
+ } else
+ indent_changed = TRUE;
+
+ /* If the mark is on, use all lines covered by the mark. */
+ if (openfile->mark_set)
+ mark_order((const filestruct **)&top, &top_x,
+ (const filestruct **)&bot, &bot_x, NULL);
+ /* Otherwise, use the current line. */
+ else {
+ top = openfile->current;
+ bot = top;
+ }
+
+ if (!unindent) {
+ /* Set up the text we'll be using as indentation. */
+ line_indent = charalloc(cols + 1);
+
+ if (ISSET(TABS_TO_SPACES)) {
+ /* Set the indentation to cols spaces. */
+ charset(line_indent, ' ', cols);
+ line_indent_len = cols;
+ } else {
+ /* Set the indentation to (cols / tabsize) tabs and (cols %
+ * tabsize) spaces. */
+ size_t num_tabs = cols / tabsize;
+ size_t num_spaces = cols % tabsize;
+
+ charset(line_indent, '\t', num_tabs);
+ charset(line_indent + num_tabs, ' ', num_spaces);
+
+ line_indent_len = num_tabs + num_spaces;
+ }
+
+ line_indent[line_indent_len] = '\0';
+ }
+
+ /* Go through each line of the text. */
+ for (f = top; f != bot->next; f = f->next) {
+ size_t line_len = strlen(f->data);
+ size_t indent_len = indent_length(f->data);
+
+ if (!unindent) {
+ /* If we're indenting, add the characters in line_indent to
+ * the beginning of the non-whitespace text of this line. */
+ f->data = charealloc(f->data, line_len + line_indent_len + 1);
+ charmove(&f->data[indent_len + line_indent_len],
+ &f->data[indent_len], line_len - indent_len + 1);
+ strncpy(f->data + indent_len, line_indent, line_indent_len);
+ openfile->totsize += line_indent_len;
+
+ /* Keep track of the change in the current line. */
+ if (openfile->mark_set && f == openfile->mark_begin &&
+ openfile->mark_begin_x >= indent_len)
+ openfile->mark_begin_x += line_indent_len;
+
+ if (f == openfile->current && openfile->current_x >= indent_len) {
+ openfile->current_x += line_indent_len;
+ openfile->placewewant = xplustabs();
+ }
+
+ /* If the NO_NEWLINES flag isn't set, and this is the
+ * magicline, add a new magicline. */
+ if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
+ new_magicline();
+ } else {
+ size_t indent_col = strnlenpt(f->data, indent_len);
+ /* The length in columns of the indentation on this line. */
+
+ if (cols <= indent_col) {
+ size_t indent_new = actual_x(f->data, indent_col - cols);
+ /* The length of the indentation remaining on
+ * this line after we unindent. */
+ size_t indent_shift = indent_len - indent_new;
+ /* The change in the indentation on this line
+ * after we unindent. */
+
+ /* If we're unindenting, and there's at least cols
+ * columns' worth of indentation at the beginning of the
+ * non-whitespace text of this line, remove it. */
+ charmove(&f->data[indent_new], &f->data[indent_len],
+ line_len - indent_shift - indent_new + 1);
+ null_at(&f->data, line_len - indent_shift + 1);
+ openfile->totsize -= indent_shift;
+
+ /* Keep track of the change in the current line. */
+ if (openfile->mark_set && f == openfile->mark_begin &&
+ openfile->mark_begin_x > indent_new) {
+ if (openfile->mark_begin_x <= indent_len)
+ openfile->mark_begin_x = indent_new;
+ else
+ openfile->mark_begin_x -= indent_shift;
+ }
+
+ if (f == openfile->current &&
+ openfile->current_x > indent_new) {
+ if (openfile->current_x <= indent_len)
+ openfile->current_x = indent_new;
+ else
+ openfile->current_x -= indent_shift;
+ openfile->placewewant = xplustabs();
+ }
+
+ /* We've unindented, so the indentation changed. */
+ indent_changed = TRUE;
+ }
+ }
+ }
+
+ if (!unindent)
+ /* Clean up. */
+ free(line_indent);
+
+ if (indent_changed) {
+ /* Throw away the undo stack, to prevent making mistakes when
+ * the user tries to undo something in the reindented text. */
+ discard_until(NULL, openfile);
+
+ /* Mark the file as modified. */
+ set_modified();
+
+ /* Update the screen. */
+ refresh_needed = TRUE;
+ }
+}
+
+/* Unindent the current line, or all lines covered by the mark if the mark
+ * is on, tabsize columns. */
+void do_unindent_void(void)
{
- do_indent(-tabsize);
+ do_unindent(-tabsize);
}
#endif /* !NANO_TINY */