ex_getln: Fixes for some problems with getexmodeline()

Problems with line-input editing commands in Ex mode
('nvim -e' or 'Q' in normal mode):

CTRL_U: Only after the next keystroke the complete
        line change is shown if the indentation was
        not 0.

        :     asdfCTRL_U

CTRL_T: Memory reallocation with ga_grows() before a
        memmove(), but pointers into the memory are
        not updated.

        :set sw=40
        :CTRL_T
        ...

        Should complain about a memory error.

CTRL_D: Trying to reduce an indentation of 0.

        :set sw=1
        :CTRL_D

        Segfault

Helped-by: Scott Prager <splinterofchaos@gmail.com>
This commit is contained in:
oni-link
2015-03-31 20:17:45 +02:00
committed by Justin M. Keyes
parent e692930af2
commit 2493b6fefc

View File

@@ -1781,24 +1781,29 @@ getexmodeline (
msg_col = startcol;
msg_clr_eos();
line_ga.ga_len = 0;
continue;
goto redraw;
}
int num_spaces;
if (c1 == Ctrl_T) {
int sw = get_sw_value(curbuf);
p = (char_u *)line_ga.ga_data;
p[line_ga.ga_len] = NUL;
indent = get_indent_str(p, 8, FALSE);
indent += sw - indent % sw;
num_spaces = sw - indent % sw;
indent += num_spaces;
add_indent:
while (get_indent_str(p, 8, FALSE) < indent) {
if (num_spaces > 0) {
ga_grow(&line_ga, num_spaces + 1);
p = (char_u *)line_ga.ga_data;
char_u *s = skipwhite(p);
ga_grow(&line_ga, 1);
memmove(s + 1, s, line_ga.ga_len - (s - p) + 1);
*s = ' ';
++line_ga.ga_len;
// Insert spaces after leading whitespaces.
memmove(s + num_spaces, s, line_ga.ga_len - (s - p) + 1);
memset(s, ' ', num_spaces);
line_ga.ga_len += num_spaces;
}
redraw:
/* redraw the line */
@@ -1835,15 +1840,25 @@ redraw:
} else {
p[line_ga.ga_len] = NUL;
indent = get_indent_str(p, 8, FALSE);
if (indent == 0) {
continue;
}
--indent;
indent -= indent % get_sw_value(curbuf);
}
while (get_indent_str(p, 8, FALSE) > indent) {
char_u *s = skipwhite(p);
memmove(s - 1, s, line_ga.ga_len - (s - p) + 1);
--line_ga.ga_len;
// reduce the line's indentation
char_u *from = skipwhite(p);
char_u *to = from;
int old_indent;
while ((old_indent = get_indent_str(p, 8, FALSE)) > indent) {
*--to = NUL;
}
memmove(to, from, line_ga.ga_len - (from - p) + 1);
line_ga.ga_len -= from - to;
// Removed to much indentation, fix it before redrawing.
num_spaces = indent - old_indent;
goto add_indent;
}