mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
Merge pull request #32935 from zeertzjq/vim-3495497
vim-patch: too many strlen() calls in edit.c
This commit is contained in:
@@ -1820,7 +1820,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
|
||||
saved_line[curwin->w_cursor.col] = NUL;
|
||||
// Remove trailing white space, unless OPENLINE_KEEPTRAIL used.
|
||||
if (trunc_line && !(flags & OPENLINE_KEEPTRAIL)) {
|
||||
truncate_spaces(saved_line);
|
||||
truncate_spaces(saved_line, (size_t)curwin->w_cursor.col);
|
||||
}
|
||||
ml_replace(curwin->w_cursor.lnum, saved_line, false);
|
||||
|
||||
|
116
src/nvim/edit.c
116
src/nvim/edit.c
@@ -120,7 +120,8 @@ static colnr_T Insstart_textlen; // length of line when insert started
|
||||
static colnr_T Insstart_blank_vcol; // vcol for first inserted blank
|
||||
static bool update_Insstart_orig = true; // set Insstart_orig to Insstart
|
||||
|
||||
static char *last_insert = NULL; // the text of the previous insert, K_SPECIAL is escaped
|
||||
/// the text of the previous insert, K_SPECIAL is escaped
|
||||
static String last_insert = STRING_INIT;
|
||||
static int last_insert_skip; // nr of chars in front of previous insert
|
||||
static int new_insert_skip; // nr of chars in front of current insert
|
||||
static int did_restart_edit; // "restart_edit" when calling edit()
|
||||
@@ -1816,12 +1817,12 @@ void change_indent(int type, int amount, int round, bool call_changed_bytes)
|
||||
/// Truncate the space at the end of a line. This is to be used only in an
|
||||
/// insert mode. It handles fixing the replace stack for MODE_REPLACE and
|
||||
/// MODE_VREPLACE modes.
|
||||
void truncate_spaces(char *line)
|
||||
void truncate_spaces(char *line, size_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
// find start of trailing white space
|
||||
for (i = (int)strlen(line) - 1; i >= 0 && ascii_iswhite(line[i]); i--) {
|
||||
for (i = (int)len - 1; i >= 0 && ascii_iswhite(line[i]); i--) {
|
||||
if (State & REPLACE_FLAG) {
|
||||
replace_join(0); // remove a NUL from the replace stack
|
||||
}
|
||||
@@ -2332,8 +2333,8 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove)
|
||||
String inserted = get_inserted();
|
||||
int added = inserted.data == NULL ? 0 : (int)inserted.size - new_insert_skip;
|
||||
if (did_restart_edit == 0 || added > 0) {
|
||||
xfree(last_insert);
|
||||
last_insert = inserted.data;
|
||||
xfree(last_insert.data);
|
||||
last_insert = inserted; // structure copy
|
||||
last_insert_skip = added < 0 ? 0 : new_insert_skip;
|
||||
} else {
|
||||
xfree(inserted.data);
|
||||
@@ -2440,23 +2441,24 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove)
|
||||
// Used for the replace command.
|
||||
void set_last_insert(int c)
|
||||
{
|
||||
xfree(last_insert);
|
||||
last_insert = xmalloc(MB_MAXBYTES * 3 + 5);
|
||||
char *s = last_insert;
|
||||
xfree(last_insert.data);
|
||||
last_insert.data = xmalloc(MB_MAXBYTES * 3 + 5);
|
||||
char *s = last_insert.data;
|
||||
// Use the CTRL-V only when entering a special char
|
||||
if (c < ' ' || c == DEL) {
|
||||
*s++ = Ctrl_V;
|
||||
}
|
||||
s = add_char2buf(c, s);
|
||||
*s++ = ESC;
|
||||
*s++ = NUL;
|
||||
*s = NUL;
|
||||
last_insert.size = (size_t)(s - last_insert.data);
|
||||
last_insert_skip = 0;
|
||||
}
|
||||
|
||||
#if defined(EXITFREE)
|
||||
void free_last_insert(void)
|
||||
{
|
||||
XFREE_CLEAR(last_insert);
|
||||
API_CLEAR_STRING(last_insert);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2692,11 +2694,10 @@ int cursor_down(int n, bool upd_topline)
|
||||
/// @param no_esc Don't add an ESC at the end
|
||||
int stuff_inserted(int c, int count, int no_esc)
|
||||
{
|
||||
char *esc_ptr;
|
||||
char last = NUL;
|
||||
|
||||
char *ptr = get_last_insert();
|
||||
if (ptr == NULL) {
|
||||
String *insert = get_last_insert(); // text to be inserted
|
||||
if (insert->data == NULL) {
|
||||
emsg(_(e_noinstext));
|
||||
return FAIL;
|
||||
}
|
||||
@@ -2705,37 +2706,44 @@ int stuff_inserted(int c, int count, int no_esc)
|
||||
if (c != NUL) {
|
||||
stuffcharReadbuff(c);
|
||||
}
|
||||
if ((esc_ptr = strrchr(ptr, ESC)) != NULL) {
|
||||
// remove the ESC.
|
||||
*esc_ptr = NUL;
|
||||
|
||||
if (insert->size > 0) {
|
||||
// look for the last ESC in 'insert'
|
||||
for (char *p = insert->data + insert->size - 1; p >= insert->data; p--) {
|
||||
if (*p == ESC) {
|
||||
insert->size = (size_t)(p - insert->data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// when the last char is either "0" or "^" it will be quoted if no ESC
|
||||
// comes after it OR if it will inserted more than once and "ptr"
|
||||
// starts with ^D. -- Acevedo
|
||||
char *last_ptr = (esc_ptr ? esc_ptr : ptr + strlen(ptr)) - 1;
|
||||
if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
|
||||
&& (no_esc || (*ptr == Ctrl_D && count > 1))) {
|
||||
last = *last_ptr;
|
||||
*last_ptr = NUL;
|
||||
if (insert->size > 0) {
|
||||
char *p = insert->data + insert->size - 1;
|
||||
// when the last char is either "0" or "^" it will be quoted if no ESC
|
||||
// comes after it OR if it will inserted more than once and "ptr"
|
||||
// starts with ^D. -- Acevedo
|
||||
if ((*p == '0' || *p == '^')
|
||||
&& (no_esc || (*insert->data == Ctrl_D && count > 1))) {
|
||||
last = *p;
|
||||
insert->size--;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
stuffReadbuff(ptr);
|
||||
stuffReadbuffLen(insert->data, (ptrdiff_t)insert->size);
|
||||
// A trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^".
|
||||
if (last) {
|
||||
stuffReadbuff(last == '0' ? "\026\060\064\070" : "\026^");
|
||||
switch (last) {
|
||||
case '0':
|
||||
stuffReadbuffLen(S_LEN("\026\060\064\070"));
|
||||
break;
|
||||
case '^':
|
||||
stuffReadbuffLen(S_LEN("\026^"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (--count > 0);
|
||||
|
||||
if (last) {
|
||||
*last_ptr = last;
|
||||
}
|
||||
|
||||
if (esc_ptr != NULL) {
|
||||
*esc_ptr = ESC; // put the ESC back
|
||||
}
|
||||
|
||||
// may want to stuff a trailing ESC, to get out of Insert mode
|
||||
if (!no_esc) {
|
||||
stuffcharReadbuff(ESC);
|
||||
@@ -2744,28 +2752,37 @@ int stuff_inserted(int c, int count, int no_esc)
|
||||
return OK;
|
||||
}
|
||||
|
||||
char *get_last_insert(void)
|
||||
String *get_last_insert(void)
|
||||
FUNC_ATTR_PURE
|
||||
{
|
||||
if (last_insert == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return last_insert + last_insert_skip;
|
||||
static String insert = STRING_INIT;
|
||||
|
||||
insert = last_insert.data == NULL ? NULL_STRING : (String){
|
||||
insert.data = last_insert.data + last_insert_skip,
|
||||
insert.size = last_insert.size - (size_t)last_insert_skip,
|
||||
};
|
||||
|
||||
return &insert;
|
||||
}
|
||||
|
||||
// Get last inserted string, and remove trailing <Esc>.
|
||||
// Returns pointer to allocated memory (must be freed) or NULL.
|
||||
char *get_last_insert_save(void)
|
||||
{
|
||||
if (last_insert == NULL) {
|
||||
String *insert = get_last_insert();
|
||||
|
||||
if (insert->data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
size_t len = strlen(last_insert + last_insert_skip);
|
||||
char *s = xmemdupz(last_insert + last_insert_skip, len);
|
||||
if (len > 0 && s[len - 1] == ESC) { // remove trailing ESC
|
||||
s[len - 1] = NUL;
|
||||
}
|
||||
|
||||
char *s = xmemdupz(insert->data, insert->size);
|
||||
if (insert->size > 0) {
|
||||
// remain trailing ESC
|
||||
insert->size--;
|
||||
if (s[insert->size] == ESC) {
|
||||
s[insert->size] = NUL;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -3507,7 +3524,7 @@ static bool ins_start_select(int c)
|
||||
if (mod_mask) {
|
||||
const char buf[] = { (char)K_SPECIAL, (char)KS_MODIFIER,
|
||||
(char)(uint8_t)mod_mask, NUL };
|
||||
stuffReadbuff(buf);
|
||||
stuffReadbuffLen(buf, 3);
|
||||
}
|
||||
stuffcharReadbuff(c);
|
||||
return true;
|
||||
@@ -4705,11 +4722,12 @@ static char *do_insert_char_pre(int c)
|
||||
if (!has_event(EVENT_INSERTCHARPRE)) {
|
||||
return NULL;
|
||||
}
|
||||
buf[utf_char2bytes(c, buf)] = NUL;
|
||||
size_t buflen = (size_t)utf_char2bytes(c, buf);
|
||||
buf[buflen] = NUL;
|
||||
|
||||
// Lock the text to avoid weird things from happening.
|
||||
textlock++;
|
||||
set_vim_var_string(VV_CHAR, buf, -1);
|
||||
set_vim_var_string(VV_CHAR, buf, (ptrdiff_t)buflen); // set v:char
|
||||
|
||||
char *res = NULL;
|
||||
if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) {
|
||||
|
@@ -3849,7 +3849,7 @@ void ex_display(exarg_T *eap)
|
||||
}
|
||||
|
||||
// display last inserted text
|
||||
if ((p = get_last_insert()) != NULL
|
||||
if ((p = get_last_insert()->data) != NULL
|
||||
&& (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
|
||||
&& !message_filtered(p)) {
|
||||
msg_puts("\n c \". ");
|
||||
|
@@ -328,4 +328,31 @@ func Test_put_list()
|
||||
put! =l
|
||||
call assert_equal(['a', 'b', 'c', ''], getline(1, '$'))
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
" Test pasting the '.' register
|
||||
func Test_put_inserted()
|
||||
new
|
||||
|
||||
for s in ['', '…', '0', '^', '+0', '+^', '…0', '…^']
|
||||
call setline(1, 'foobar')
|
||||
exe $"normal! A{s}\<Esc>"
|
||||
call assert_equal($'foobar{s}', getline(1))
|
||||
normal! ".p
|
||||
call assert_equal($'foobar{s}{s}', getline(1))
|
||||
normal! ".2p
|
||||
call assert_equal($'foobar{s}{s}{s}{s}', getline(1))
|
||||
endfor
|
||||
|
||||
for s in ['0', '^', '+0', '+^', '…0', '…^']
|
||||
call setline(1, "\t\t\t\t\tfoobar")
|
||||
exe $"normal! A\<C-D>{s}\<Esc>"
|
||||
call assert_equal($"\t\t\t\tfoobar{s}", getline(1))
|
||||
normal! ".p
|
||||
call assert_equal($"\t\t\tfoobar{s}{s}", getline(1))
|
||||
normal! ".2p
|
||||
call assert_equal($"\tfoobar{s}{s}{s}{s}", getline(1))
|
||||
endfor
|
||||
|
||||
bwipe!
|
||||
endfunc
|
||||
|
Reference in New Issue
Block a user