Skip to content

Commit 76bdb82

Browse files
glepnirchrisbra
authored andcommitted
patch 9.1.1086: completion doesn't work with multi lines
Problem: completion doesn't work with multi lines (Łukasz Jan Niemier) Solution: handle linebreaks in completion code as expected (glepnir) fixes: vim#2505 closes: vim#15373 Signed-off-by: glepnir <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent 746fe54 commit 76bdb82

15 files changed

+286
-19
lines changed

runtime/doc/version9.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41638,6 +41638,7 @@ Changed~
4163841638
- new digraph "APPROACHES THE LIMIT" using ".="
4163941639
- Add the optional {opts} |Dict| argument to |getchar()| to control: cursor
4164041640
behaviour, return type and whether or not to simplify the returned key
41641+
- handle multi-line completion as expected
4164141642

4164241643
*added-9.2*
4164341644
Added ~

runtime/filetype.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
" Vim support file to detect file types
22
"
33
" Maintainer: The Vim Project <https://github.com/vim/vim>
4-
" Last Change: 2025 Jan 21
4+
" Last Change: 2025 Feb 08
55
" Former Maintainer: Bram Moolenaar <[email protected]>
66

77
" Listen very carefully, I will say this only once

src/drawline.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,7 +1877,8 @@ win_line(
18771877
}
18781878
#endif
18791879

1880-
if ((State & MODE_INSERT) && in_curline && ins_compl_win_active(wp))
1880+
if ((State & MODE_INSERT) && ins_compl_win_active(wp)
1881+
&& (in_curline || ins_compl_lnum_in_range(lnum)))
18811882
area_highlighting = TRUE;
18821883

18831884
#ifdef FEAT_SYN_HL
@@ -2423,11 +2424,11 @@ win_line(
24232424
#endif
24242425

24252426
// Check if ComplMatchIns highlight is needed.
2426-
if ((State & MODE_INSERT) && in_curline
2427-
&& ins_compl_win_active(wp))
2427+
if ((State & MODE_INSERT) && ins_compl_win_active(wp)
2428+
&& (in_curline || ins_compl_lnum_in_range(lnum)))
24282429
{
24292430
int ins_match_attr =
2430-
ins_compl_col_range_attr((int)(ptr - line));
2431+
ins_compl_col_range_attr(lnum, (int)(ptr - line));
24312432
if (ins_match_attr > 0)
24322433
search_attr =
24332434
hl_combine_attr(search_attr, ins_match_attr);

src/insexpand.c

Lines changed: 124 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ static pos_T compl_startpos;
172172
// Length in bytes of the text being completed (this is deleted to be replaced
173173
// by the match.)
174174
static int compl_length = 0;
175+
static linenr_T compl_lnum = 0; // lnum where the completion start
175176
static colnr_T compl_col = 0; // column where the text starts
176177
// that is being completed
177178
static colnr_T compl_ins_end_col = 0;
@@ -226,6 +227,8 @@ static int ins_compl_pum_key(int c);
226227
static int ins_compl_key2count(int c);
227228
static void show_pum(int prev_w_wrow, int prev_w_leftcol);
228229
static unsigned quote_meta(char_u *dest, char_u *str, int len);
230+
static int ins_compl_has_multiple(void);
231+
static void ins_compl_expand_multiple(char_u *str);
229232

230233
#ifdef FEAT_SPELL
231234
static void spell_back_to_badword(void);
@@ -919,20 +922,54 @@ ins_compl_insert_bytes(char_u *p, int len)
919922
/*
920923
* Checks if the column is within the currently inserted completion text
921924
* column range. If it is, it returns a special highlight attribute.
922-
* -1 mean normal item.
925+
* -1 means normal item.
923926
*/
924927
int
925-
ins_compl_col_range_attr(int col)
928+
ins_compl_col_range_attr(linenr_T lnum, int col)
926929
{
927-
if ((get_cot_flags() & COT_FUZZY))
930+
int start_col;
931+
int attr;
932+
933+
if ((get_cot_flags() & COT_FUZZY)
934+
|| (attr = syn_name2attr((char_u *)"ComplMatchIns")) == 0)
928935
return -1;
929936

930-
if (col >= (compl_col + (int)ins_compl_leader_len()) && col < compl_ins_end_col)
931-
return syn_name2attr((char_u *)"ComplMatchIns");
937+
start_col = compl_col + (int)ins_compl_leader_len();
938+
if (!ins_compl_has_multiple())
939+
return (col >= start_col && col < compl_ins_end_col) ? attr : -1;
940+
941+
// Multiple lines
942+
if ((lnum == compl_lnum && col >= start_col && col < MAXCOL) ||
943+
(lnum > compl_lnum && lnum < curwin->w_cursor.lnum) ||
944+
(lnum == curwin->w_cursor.lnum && col <= compl_ins_end_col))
945+
return attr;
932946

933947
return -1;
934948
}
935949

950+
/*
951+
* Returns TRUE if the current completion string contains newline characters,
952+
* indicating it's a multi-line completion.
953+
*/
954+
static int
955+
ins_compl_has_multiple(void)
956+
{
957+
return vim_strchr(compl_shown_match->cp_str.string, '\n') != NULL;
958+
}
959+
960+
/*
961+
* Returns TRUE if the given line number falls within the range of a multi-line
962+
* completion, i.e. between the starting line (compl_lnum) and current cursor
963+
* line. Always returns FALSE for single-line completions.
964+
*/
965+
int
966+
ins_compl_lnum_in_range(linenr_T lnum)
967+
{
968+
if (!ins_compl_has_multiple())
969+
return FALSE;
970+
return lnum >= compl_lnum && lnum <= curwin->w_cursor.lnum;
971+
}
972+
936973
/*
937974
* Reduce the longest common string for match "match".
938975
*/
@@ -3123,6 +3160,7 @@ set_completion(colnr_T startcol, list_T *list)
31233160
if (startcol > curwin->w_cursor.col)
31243161
startcol = curwin->w_cursor.col;
31253162
compl_col = startcol;
3163+
compl_lnum = curwin->w_cursor.lnum;
31263164
compl_length = (int)curwin->w_cursor.col - (int)startcol;
31273165
// compl_pattern doesn't need to be set
31283166
compl_orig_text.string = vim_strnsave(ml_get_curline() + compl_col,
@@ -4342,13 +4380,39 @@ ins_compl_delete(void)
43424380
// In insert mode: Delete the typed part.
43434381
// In replace mode: Put the old characters back, if any.
43444382
int col = compl_col + (compl_status_adding() ? compl_length : 0);
4383+
char_u *remaining = NULL;
4384+
int orig_col;
43454385
int has_preinsert = ins_compl_preinsert_effect();
43464386
if (has_preinsert)
43474387
{
43484388
col += ins_compl_leader_len();
43494389
curwin->w_cursor.col = compl_ins_end_col;
43504390
}
43514391

4392+
if (curwin->w_cursor.lnum > compl_lnum)
4393+
{
4394+
if (curwin->w_cursor.col < ml_get_curline_len())
4395+
{
4396+
char_u *line = ml_get_curline();
4397+
remaining = vim_strnsave(line + curwin->w_cursor.col,
4398+
(size_t)STRLEN(line + curwin->w_cursor.col));
4399+
if (remaining == NULL)
4400+
return;
4401+
}
4402+
while (curwin->w_cursor.lnum > compl_lnum)
4403+
{
4404+
if (ml_delete(curwin->w_cursor.lnum) == FAIL)
4405+
{
4406+
if (remaining)
4407+
VIM_CLEAR(remaining);
4408+
return;
4409+
}
4410+
curwin->w_cursor.lnum--;
4411+
}
4412+
// move cursor to end of line
4413+
curwin->w_cursor.col = ml_get_curline_len();
4414+
}
4415+
43524416
if ((int)curwin->w_cursor.col > col)
43534417
{
43544418
if (stop_arrow() == FAIL)
@@ -4357,6 +4421,13 @@ ins_compl_delete(void)
43574421
compl_ins_end_col = curwin->w_cursor.col;
43584422
}
43594423

4424+
if (remaining != NULL)
4425+
{
4426+
orig_col = curwin->w_cursor.col;
4427+
ins_str(remaining);
4428+
curwin->w_cursor.col = orig_col;
4429+
vim_free(remaining);
4430+
}
43604431
// TODO: is this sufficient for redrawing? Redrawing everything causes
43614432
// flicker, thus we can't do that.
43624433
changed_cline_bef_curs();
@@ -4366,6 +4437,38 @@ ins_compl_delete(void)
43664437
#endif
43674438
}
43684439

4440+
/*
4441+
* Insert a completion string that contains newlines.
4442+
* The string is split and inserted line by line.
4443+
*/
4444+
static void
4445+
ins_compl_expand_multiple(char_u *str)
4446+
{
4447+
char_u *start = str;
4448+
char_u *curr = str;
4449+
4450+
while (*curr != NUL)
4451+
{
4452+
if (*curr == '\n')
4453+
{
4454+
// Insert the text chunk before newline
4455+
if (curr > start)
4456+
ins_char_bytes(start, (int)(curr - start));
4457+
4458+
// Handle newline
4459+
open_line(FORWARD, OPENLINE_KEEPTRAIL, FALSE, NULL);
4460+
start = curr + 1;
4461+
}
4462+
curr++;
4463+
}
4464+
4465+
// Handle remaining text after last newline (if any)
4466+
if (curr > start)
4467+
ins_char_bytes(start, (int)(curr - start));
4468+
4469+
compl_ins_end_col = curwin->w_cursor.col;
4470+
}
4471+
43694472
/*
43704473
* Insert the new text being completed.
43714474
* "in_compl_func" is TRUE when called from complete_check().
@@ -4375,19 +4478,25 @@ ins_compl_delete(void)
43754478
void
43764479
ins_compl_insert(int in_compl_func, int move_cursor)
43774480
{
4378-
int compl_len = get_compl_len();
4379-
int preinsert = ins_compl_has_preinsert();
4380-
char_u *cp_str = compl_shown_match->cp_str.string;
4381-
size_t cp_str_len = compl_shown_match->cp_str.length;
4382-
size_t leader_len = ins_compl_leader_len();
4481+
int compl_len = get_compl_len();
4482+
int preinsert = ins_compl_has_preinsert();
4483+
char_u *cp_str = compl_shown_match->cp_str.string;
4484+
size_t cp_str_len = compl_shown_match->cp_str.length;
4485+
size_t leader_len = ins_compl_leader_len();
4486+
char_u *has_multiple = vim_strchr(cp_str, '\n');
43834487

43844488
// Make sure we don't go over the end of the string, this can happen with
43854489
// illegal bytes.
43864490
if (compl_len < (int)cp_str_len)
43874491
{
4388-
ins_compl_insert_bytes(cp_str + compl_len, -1);
4389-
if (preinsert && move_cursor)
4390-
curwin->w_cursor.col -= (colnr_T)(cp_str_len - leader_len);
4492+
if (has_multiple)
4493+
ins_compl_expand_multiple(cp_str + compl_len);
4494+
else
4495+
{
4496+
ins_compl_insert_bytes(cp_str + compl_len, -1);
4497+
if (preinsert && move_cursor)
4498+
curwin->w_cursor.col -= (colnr_T)(cp_str_len - leader_len);
4499+
}
43914500
}
43924501
if (match_at_original_text(compl_shown_match) || preinsert)
43934502
compl_used_match = FALSE;
@@ -5373,6 +5482,7 @@ ins_compl_start(void)
53735482
line = ml_get(curwin->w_cursor.lnum);
53745483
curs_col = curwin->w_cursor.col;
53755484
compl_pending = 0;
5485+
compl_lnum = curwin->w_cursor.lnum;
53765486

53775487
if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
53785488
&& compl_cont_mode == ctrl_x_mode)
@@ -5423,6 +5533,7 @@ ins_compl_start(void)
54235533
curbuf->b_p_com = old;
54245534
compl_length = 0;
54255535
compl_col = curwin->w_cursor.col;
5536+
compl_lnum = curwin->w_cursor.lnum;
54265537
}
54275538
else if (ctrl_x_mode_normal() && in_fuzzy)
54285539
{

src/proto/insexpand.pro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ void ins_compl_delete(void);
6161
void ins_compl_insert(int in_compl_func, int move_cursor);
6262
void ins_compl_check_keys(int frequency, int in_compl_func);
6363
int ins_complete(int c, int enable_pum);
64-
int ins_compl_col_range_attr(int col);
64+
int ins_compl_col_range_attr(linenr_T lnum, int col);
6565
void free_insexpand_stuff(void);
6666
int ins_compl_preinsert_effect(void);
67+
int ins_compl_lnum_in_range(linenr_T lnum);
6768
/* vim: set ft=c : */
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
|f+0&#ffffff0|u|n|c| |(|)| @67
2+
@75
3+
|e|n|d> @71
4+
|f+0#0000001#e0e0e08|u|n|c|t|i|o|n| |(|)| @3| +0#4040ff13#ffffff0@59
5+
|f+0#0000001#ffd7ff255|o@1|b|a|r| @8| +0#4040ff13#ffffff0@59
6+
|你*0#0000001#ffd7ff255|好|^+&|@| @1|^|@|我*&|好| +&| +0#4040ff13#ffffff0@59
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|~| @73
11+
|~| @73
12+
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |3| +0#0000000&@34
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
|f+0&#ffffff0|o@1|b|a|r> @68
2+
|f+0#0000001#ffd7ff255|u|n|c|t|i|o|n| |(|)| @3| +0#4040ff13#ffffff0@59
3+
|f+0#0000001#e0e0e08|o@1|b|a|r| @8| +0#4040ff13#ffffff0@59
4+
|你*0#0000001#ffd7ff255|好|^+&|@| @1|^|@|我*&|好| +&| +0#4040ff13#ffffff0@59
5+
|~| @73
6+
|~| @73
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|~| @73
11+
|~| @73
12+
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |2| |o|f| |3| +0#0000000&@34
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
|h+0&#ffffff0|e|l@1|o| |f|u|n|c| |(|)| @61
2+
@75
3+
|e|n|d> |h|e|r|o| @66
4+
|~+0#4040ff13&| @3| +0#0000001#e0e0e08|f|u|n|c|t|i|o|n| |(|)| @3| +0#4040ff13#ffffff0@53
5+
|~| @3| +0#0000001#ffd7ff255|f|o@1|b|a|r| @8| +0#4040ff13#ffffff0@53
6+
|~| @3| +0#0000001#ffd7ff255|你*&|好|^+&|@| @1|^|@|我*&|好| +&| +0#4040ff13#ffffff0@53
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|~| @73
11+
|~| @73
12+
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |3| +0#0000000&@34
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
|h+0&#ffffff0|e|l@1|o| |f|o@1|b|a|r> |h|e|r|o| @57
2+
|~+0#4040ff13&| @3| +0#0000001#ffd7ff255|f|u|n|c|t|i|o|n| |(|)| @3| +0#4040ff13#ffffff0@53
3+
|~| @3| +0#0000001#e0e0e08|f|o@1|b|a|r| @8| +0#4040ff13#ffffff0@53
4+
|~| @3| +0#0000001#ffd7ff255|你*&|好|^+&|@| @1|^|@|我*&|好| +&| +0#4040ff13#ffffff0@53
5+
|~| @73
6+
|~| @73
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|~| @73
11+
|~| @73
12+
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |2| |o|f| |3| +0#0000000&@34
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
|h+0&#ffffff0|e|l@1|o| |你*&|好| +&@64
2+
@75
3+
|我*&|好> +&|h|e|r|o| @65
4+
|~+0#4040ff13&| @1| +0#0000001#ffd7ff255|f|u|n|c|t|i|o|n| |(|)| @3| +0#4040ff13#ffffff0@55
5+
|~| @1| +0#0000001#ffd7ff255|f|o@1|b|a|r| @8| +0#4040ff13#ffffff0@55
6+
|~| @1| +0#0000001#e0e0e08|你*&|好|^+&|@| @1|^|@|我*&|好| +&| +0#4040ff13#ffffff0@55
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|~| @73
11+
|~| @73
12+
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |3| |o|f| |3| +0#0000000&@34
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
|h+0&#ffffff0|e|l@1|o| > |h|e|r|o| @63
2+
|~+0#4040ff13&| @3| +0#0000001#ffd7ff255|f|u|n|c|t|i|o|n| |(|)| @3| +0#4040ff13#ffffff0@53
3+
|~| @3| +0#0000001#ffd7ff255|f|o@1|b|a|r| @8| +0#4040ff13#ffffff0@53
4+
|~| @3| +0#0000001#ffd7ff255|你*&|好|^+&|@| @1|^|@|我*&|好| +&| +0#4040ff13#ffffff0@53
5+
|~| @73
6+
|~| @73
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|~| @73
11+
|~| @73
12+
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |B+0#e000002&|a|c|k| |a|t| |o|r|i|g|i|n|a|l| +0#0000000&@30
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
|f+0#ff404010#ffffff0|u|n|c| |(|)| +0#0000000&@67
2+
| +0#ff404010&@7| +0#0000000&@66
3+
|e+0#ff404010&|n|d> +0#0000000&@71
4+
|f+0#0000001#e0e0e08|u|n|c|t|i|o|n| |(|)| @3| +0#4040ff13#ffffff0@59
5+
|f+0#0000001#ffd7ff255|o@1|b|a|r| @8| +0#4040ff13#ffffff0@59
6+
|你*0#0000001#ffd7ff255|好|^+&|@| @1|^|@|我*&|好| +&| +0#4040ff13#ffffff0@59
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|~| @73
11+
|~| @73
12+
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |3| +0#0000000&@34
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
|h+0&#ffffff0|e|l@1|o| |f+0#ff404010&|u|n|c| |(|)| +0#0000000&@61
2+
| +0#ff404010&@7| +0#0000000&@66
3+
|e+0#ff404010&|n|d> |h+0#0000000&|e|r|o| @66
4+
|~+0#4040ff13&| @3| +0#0000001#e0e0e08|f|u|n|c|t|i|o|n| |(|)| @3| +0#4040ff13#ffffff0@53
5+
|~| @3| +0#0000001#ffd7ff255|f|o@1|b|a|r| @8| +0#4040ff13#ffffff0@53
6+
|~| @3| +0#0000001#ffd7ff255|你*&|好|^+&|@| @1|^|@|我*&|好| +&| +0#4040ff13#ffffff0@53
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|~| @73
11+
|~| @73
12+
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |3| +0#0000000&@34

0 commit comments

Comments
 (0)