From ed4c549ea2436b820860c3453d348c84d441de9b Mon Sep 17 00:00:00 2001 From: Shadman Date: Fri, 30 Jan 2026 23:22:48 +0600 Subject: [PATCH] fix(prompt): also store column info in ': mark #36194 Problem: Currently, : mark is set in start of prompt-line. But more relevant location is where the user text starts. Solution: Store and update column info on ': just like the line info --- src/nvim/edit.c | 18 +++++++++++------- src/nvim/eval.c | 5 ++--- src/nvim/mark.c | 4 ++++ src/nvim/normal.c | 2 +- test/functional/legacy/prompt_buffer_spec.lua | 13 +++++++------ 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 0b178a5646..79ce12bdea 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1591,31 +1591,35 @@ char *prompt_text(void) static void init_prompt(int cmdchar_todo) { char *prompt = prompt_text(); + int prompt_len = (int)strlen(prompt); if (curwin->w_cursor.lnum < curbuf->b_prompt_start.mark.lnum) { curwin->w_cursor.lnum = curbuf->b_prompt_start.mark.lnum; } char *text = get_cursor_line_ptr(); if ((curbuf->b_prompt_start.mark.lnum == curwin->w_cursor.lnum - && strncmp(text, prompt, strlen(prompt)) != 0) + && (curbuf->b_prompt_start.mark.col < prompt_len + || strncmp(text + curbuf->b_prompt_start.mark.col - prompt_len, prompt, + (size_t)prompt_len) != 0)) || curbuf->b_prompt_start.mark.lnum > curwin->w_cursor.lnum) { // prompt is missing, insert it or append a line with it if (*text == NUL) { ml_replace(curbuf->b_ml.ml_line_count, prompt, true); } else { ml_append(curbuf->b_ml.ml_line_count, prompt, 0, false); - curbuf->b_prompt_start.mark.lnum += 1; + curbuf->b_prompt_start.mark.lnum = curbuf->b_ml.ml_line_count; } + curbuf->b_prompt_start.mark.col = prompt_len; curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; coladvance(curwin, MAXCOL); - inserted_bytes(curbuf->b_ml.ml_line_count, 0, 0, (colnr_T)strlen(prompt)); + inserted_bytes(curbuf->b_ml.ml_line_count, 0, 0, (colnr_T)prompt_len); } // Insert always starts after the prompt, allow editing text after it. if (Insstart_orig.lnum != curbuf->b_prompt_start.mark.lnum - || Insstart_orig.col != (colnr_T)strlen(prompt)) { + || Insstart_orig.col != curbuf->b_prompt_start.mark.col) { Insstart.lnum = curbuf->b_prompt_start.mark.lnum; - Insstart.col = (colnr_T)strlen(prompt); + Insstart.col = curbuf->b_prompt_start.mark.col; Insstart_orig = Insstart; Insstart_textlen = Insstart.col; Insstart_blank_vcol = MAXCOL; @@ -1626,7 +1630,7 @@ static void init_prompt(int cmdchar_todo) coladvance(curwin, MAXCOL); } if (curbuf->b_prompt_start.mark.lnum == curwin->w_cursor.lnum) { - curwin->w_cursor.col = MAX(curwin->w_cursor.col, (colnr_T)strlen(prompt)); + curwin->w_cursor.col = MAX(curwin->w_cursor.col, curbuf->b_prompt_start.mark.col); } // Make sure the cursor is in a valid position. check_cursor(curwin); @@ -1638,7 +1642,7 @@ bool prompt_curpos_editable(void) { return curwin->w_cursor.lnum > curbuf->b_prompt_start.mark.lnum || (curwin->w_cursor.lnum == curbuf->b_prompt_start.mark.lnum - && curwin->w_cursor.col >= (int)strlen(prompt_text())); + && curwin->w_cursor.col >= curbuf->b_prompt_start.mark.col); } // Undo the previous edit_putchar(). diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 04ae4bc422..f3640e6299 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6633,9 +6633,8 @@ char *prompt_get_input(buf_T *buf) linenr_T lnum_last = buf->b_ml.ml_line_count; char *text = ml_get_buf(buf, lnum_start); - char *prompt = prompt_text(); - if (strlen(text) >= strlen(prompt)) { - text += strlen(prompt); + if ((int)strlen(text) >= buf->b_prompt_start.mark.col) { + text += buf->b_prompt_start.mark.col; } char *full_text = xstrdup(text); diff --git a/src/nvim/mark.c b/src/nvim/mark.c index fabcfc37f9..31eac728f9 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1448,6 +1448,10 @@ void mark_col_adjust(linenr_T lnum, colnr_T mincol, linenr_T lnum_amount, colnr_ // last change position COL_ADJUST(&(curbuf->b_last_change.mark)); + if (bt_prompt(curbuf)) { + COL_ADJUST(&(curbuf->b_prompt_start.mark)); + } + // list of change positions for (int i = 0; i < curbuf->b_changelistlen; i++) { COL_ADJUST(&(curbuf->b_changelist[i].mark)); diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 667848bd47..eb36b6f60b 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -6485,7 +6485,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) if (bt_prompt(curbuf) && !prompt_curpos_editable()) { if (curwin->w_cursor.lnum == curbuf->b_prompt_start.mark.lnum) { - curwin->w_cursor.col = (int)strlen(prompt_text()); + curwin->w_cursor.col = curbuf->b_prompt_start.mark.col; // Since we've shifted the cursor to the first editable char. We want to // paste before that. cap->cmdchar = 'P'; diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index 0eee719dea..8174ded803 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -642,6 +642,7 @@ describe('prompt buffer', function() api.nvim_set_option_value('buftype', 'prompt', { buf = 0 }) exec_lua(function() local buf = vim.api.nvim_get_current_buf() + vim.fn.prompt_setprompt(buf, 'cmd > ') vim.fn.prompt_setcallback(buf, function(str) local last_line = vim.api.nvim_buf_line_count(buf) vim.api.nvim_buf_set_lines(buf, last_line - 1, last_line - 1, true, vim.split(str, '\n')) @@ -649,12 +650,12 @@ describe('prompt buffer', function() end) feed('asdf') - eq({ 1, 1 }, api.nvim_buf_get_mark(0, ':')) + eq({ 1, 6 }, api.nvim_buf_get_mark(0, ':')) feed('') - eq({ 3, 1 }, api.nvim_buf_get_mark(0, ':')) + eq({ 3, 6 }, api.nvim_buf_get_mark(0, ':')) -- Multiline prompt. feed('line1line2line3') - eq({ 11, 1 }, api.nvim_buf_get_mark(0, ':')) + eq({ 11, 6 }, api.nvim_buf_get_mark(0, ':')) -- ': mark is only available in prompt buffer. api.nvim_set_option_value('buftype', '', { buf = 0 }) @@ -663,9 +664,9 @@ describe('prompt buffer', function() -- mark can be moved api.nvim_set_option_value('buftype', 'prompt', { buf = 0 }) local last_line = api.nvim_buf_line_count(0) - eq({ last_line, 1 }, api.nvim_buf_get_mark(0, ':')) - eq(true, api.nvim_buf_set_mark(0, ':', 1, 1, {})) - eq({ 1, 1 }, api.nvim_buf_get_mark(0, ':')) + eq({ last_line, 6 }, api.nvim_buf_get_mark(0, ':')) + eq(true, api.nvim_buf_set_mark(0, ':', 1, 5, {})) + eq({ 1, 5 }, api.nvim_buf_get_mark(0, ':')) end) describe('prompt_getinput', function()