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
This commit is contained in:
Shadman
2026-01-30 23:22:48 +06:00
committed by GitHub
parent 36db6ff2c1
commit ed4c549ea2
5 changed files with 25 additions and 17 deletions

View File

@@ -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().

View File

@@ -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);

View File

@@ -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));

View File

@@ -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';

View File

@@ -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()