commit ed4c549ea2436b820860c3453d348c84d441de9b
parent 36db6ff2c128864840e2820491a2172d6b1b7e62
Author: Shadman <shadmansaleh3@gmail.com>
Date: Fri, 30 Jan 2026 23:22:48 +0600
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
Diffstat:
5 files changed, 25 insertions(+), 17 deletions(-)
diff --git 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
@@ -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
@@ -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
@@ -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
@@ -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('<cr>')
- eq({ 3, 1 }, api.nvim_buf_get_mark(0, ':'))
+ eq({ 3, 6 }, api.nvim_buf_get_mark(0, ':'))
-- Multiline prompt.
feed('<s-cr>line1<s-cr>line2<s-cr>line3<cr>')
- 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()