diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c index eba6b5c791..0583c62102 100644 --- a/src/nvim/eval/buffer.c +++ b/src/nvim/eval/buffer.c @@ -291,6 +291,8 @@ void f_prompt_appendbuf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) linenr_T lnum = MAX(0, buf->b_prompt_start.mark.lnum - 1); typval_T *lines = &argvars[1]; + bool did_concat = false; + if (!buf->b_prompt_append_new_line) { // Since we are not creating a new line we need to append input to current line const char *text = (lnum > 0) ? (const char *)ml_get_buf(buf, lnum) : ""; @@ -303,6 +305,7 @@ void f_prompt_appendbuf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_clear(&li->li_tv); li->li_tv.v_type = VAR_STRING; li->li_tv.vval.v_string = new_str; + did_concat = true; } } else if (lines->v_type == VAR_STRING) { const char *str = tv_get_string(lines); @@ -314,7 +317,20 @@ void f_prompt_appendbuf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (did_emsg == did_emsg_before) { - set_buffer_lines(buf, lnum, buf->b_prompt_append_new_line, lines, rettv); + if (did_concat && tv_list_len(lines->vval.v_list) > 1) { + // Multi-element list with concat: first element (already concatenated) + // replaces the line at lnum, remaining elements are inserted after. + list_T *l = lines->vval.v_list; + listitem_T *li = tv_list_first(l); + set_buffer_lines(buf, lnum, false, &li->li_tv, rettv); + + if (rettv->vval.v_number == 0) { + tv_list_item_remove(l, li); + set_buffer_lines(buf, lnum, true, lines, rettv); + } + } else { + set_buffer_lines(buf, lnum, buf->b_prompt_append_new_line, lines, rettv); + } } if (rettv->vval.v_number == 0) { diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index db80762fb3..995e01fba6 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -1073,4 +1073,56 @@ describe('prompt buffer', function() fn('prompt_setprompt', unloaded_buf, 'hello unloaded! > ') eq('hello unloaded! > ', fn('prompt_getprompt', unloaded_buf)) end) + + it('prompt_appendbuf with multi-element list and singleline prompt', function() + command('new') + local buf = api.nvim_get_current_buf() + api.nvim_set_option_value('buftype', 'prompt', { buf = buf }) + fn('prompt_setprompt', buf, 'cmd: ') + + -- Single element list: appends before prompt + fn('prompt_appendbuf', buf, { 'line1' }) + eq({ 'line1', 'cmd: ' }, api.nvim_buf_get_lines(buf, 0, -1, false)) + + -- Multi-element list: first element appended, rest inserted as new lines before prompt + fn('prompt_appendbuf', buf, { '-append', 'line2' }) + eq({ 'line1-append', 'line2', 'cmd: ' }, api.nvim_buf_get_lines(buf, 0, -1, false)) + + -- Multi-element list after multi-element list + fn('prompt_appendbuf', buf, { '', 'line3', 'line4', 'line5', 'line6' }) + eq( + { 'line1-append', 'line2', 'line3', 'line4', 'line5', 'line6', 'cmd: ' }, + api.nvim_buf_get_lines(buf, 0, -1, false) + ) + end) + + it('prompt_appendbuf with multi-element list and multiline prompt', function() + command('new') + local buf = api.nvim_get_current_buf() + api.nvim_set_option_value('buftype', 'prompt', { buf = buf }) + fn('prompt_setprompt', buf, 'cmd: ') + source('startinsert') + + -- User types multiline input in the prompt + feed('input1input2') + eq({ 'cmd: input1', 'input2' }, api.nvim_buf_get_lines(buf, 0, -1, false)) + + -- Single element list: appends before prompt + fn('prompt_appendbuf', buf, { 'line1' }) + eq({ 'line1', 'cmd: input1', 'input2' }, api.nvim_buf_get_lines(buf, 0, -1, false)) + + -- Multi-element list: first element appended, rest inserted as new lines before prompt + fn('prompt_appendbuf', buf, { '-append', 'line2' }) + eq( + { 'line1-append', 'line2', 'cmd: input1', 'input2' }, + api.nvim_buf_get_lines(buf, 0, -1, false) + ) + + -- Multi-element list after multi-element list + fn('prompt_appendbuf', buf, { '', 'line3', 'line4', 'line5', 'line6' }) + eq( + { 'line1-append', 'line2', 'line3', 'line4', 'line5', 'line6', 'cmd: input1', 'input2' }, + api.nvim_buf_get_lines(buf, 0, -1, false) + ) + end) end)