Compare commits

...

5 Commits

Author SHA1 Message Date
marvim
81b7b06934 docs: update version.c 2025-09-03 03:16:46 +00:00
Luna Razzaghipour
f9ce939bf5 perf: scheduler priority clamping on macOS #35488
Problem:
All of Nvim’s threads are clamped to the Default QoS class. This means
that Nvim is forced to compete for CPU time with compilers and other
batch work, and is even prioritized beneath user-initiated work in GUI
apps like e.g. file imports. This significantly harms responsiveness.

Solution:
Tell the kernel that the Nvim process takes part in rendering a UI.

Implementation:
Remove the process-wide QoS clamp. This doesn’t directly do anything to
the main thread, but rather has the side-effect of letting the main
thread run at its actual QoS (User Interactive QoS).
2025-09-02 18:34:46 -07:00
zeertzjq
1ae09bf545 vim-patch:4c39d0c: runtime(doc): quote partial urls with a backtick (#35606)
closes: vim/vim#18194

4c39d0cc9b

Co-authored-by: Yochem van Rosmalen <git@yochem.nl>
2025-09-03 09:07:01 +08:00
Evgeni Chasnovski
431004dda2 fix: screenchar()/screenstring() with hidden floating windows #35560 2025-09-02 11:21:19 -07:00
Shadman
79bfeecdb4 feat(editor)!: insert-mode ctrl-r should work like paste #35477
Problem:
insert-mode ctrl-r input is treated like raw user input, which is almost
never useful. This means any newlines in the input are affected by
autoindent, etc., which is:
- slow
- usually breaks the formatting of the input

Solution:
- ctrl-r should be treated like a paste, not user-input.
- does not affect `<c-r>=`, so `<c-r>=@x` can still be used to get the
  old behavior.

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2025-09-01 21:05:16 -07:00
17 changed files with 196 additions and 97 deletions

View File

@@ -142,13 +142,16 @@ CTRL-R {register} *c_CTRL-R* *c_<C-R>*
typing CTRL-R and the second character '"' will be displayed
to indicate that you are expected to enter the name of a
register.
The text is inserted as if you typed it, but mappings and
abbreviations are not used. Command-line completion through
'wildchar' is not triggered though. And characters that end
the command line are inserted literally (<Esc>, <CR>, <NL>,
<C-C>). A <BS> or CTRL-W could still end the command line
though, and remaining characters will then be interpreted in
another mode, which might not be what you intended.
When used with named or clipboard registers (A-Z,a-z,0-9,+)
text is inserted literally like pasting with "p". For other
registers, the text is inserted as if you typed it, but
mappings and abbreviations are not used. Command-line
completion through 'wildchar' is not triggered though. And
characters that end the command line are inserted literally
(<Esc>, <CR>, <NL>, <C-C>). A <BS> or CTRL-W could still end
the command line though, and remaining characters will then be
interpreted in another mode, which might not be what you
intended.
Special registers:
'"' the unnamed register, containing the text of
the last delete or yank
@@ -176,7 +179,9 @@ CTRL-R {register} *c_CTRL-R* *c_<C-R>*
sure the expression evaluates to an empty
string. E.g.: >
<C-R><C-R>=setcmdpos(2)[-1]<CR>
< See |registers| about registers.
< You can use this to insert a register as
typed with CTRL-R =@reg.
See |registers| about registers.
Implementation detail: When using the |expression| register
and invoking setcmdpos(), this sets the position before
inserting the resulting string. Use CTRL-R CTRL-R to set the

View File

@@ -101,14 +101,17 @@ CTRL-N Find next keyword (see |i_CTRL-N|).
CTRL-P Find previous keyword (see |i_CTRL-P|).
CTRL-R {register} *i_CTRL-R*
Insert the contents of a register. Between typing CTRL-R and
Insert the contents of a register. Between typing CTRL-R and
the second character, '"' will be displayed to indicate that
you are expected to enter the name of a register.
The text is inserted as if you typed it, but mappings and
abbreviations are not used. If you have options like
'textwidth', 'formatoptions', or 'autoindent' set, this will
influence what will be inserted. This is different from what
happens with the "p" command and pasting with the mouse.
you are expected to enter the name of a register. When used
with When used with named or clipboard registers
(A-Z,a-z,0-9,+) text is inserted literally like pasting with
"p". For other registers, the text is inserted as if you typed
it, but mappings and abbreviations are not used. If you have
options like 'textwidth', 'formatoptions', or 'autoindent'
set, this will influence what will be inserted. This is
different from what happens with the "p" command and pasting
with the mouse.
Special registers:
'"' the unnamed register, containing the text of
the last delete or yank
@@ -131,6 +134,8 @@ CTRL-R {register} *i_CTRL-R*
special keys. E.g., you can use this to move
the cursor up:
CTRL-R ="\<Up>"
you can use this to insert a register as
typed with CTRL-R =@reg.
Use CTRL-R CTRL-R to insert text literally.
When the result is a |List| the items are used
as lines. They can have line breaks inside

View File

@@ -68,7 +68,8 @@ DIAGNOSTICS
EDITOR
todo
|i_CTRL-R| inserts named registers (A-Z,a-z,0-9) literally like pasting instead of
as typed. To get the old behavior you can use `<C-R>=@x`.
EVENTS

View File

@@ -649,11 +649,11 @@ ask you where to write the file (there must be a writable directory in
'runtimepath' for this).
The plugin has a default place where to look for spell files, on the Vim ftp
server. The protocol used is SSL (https://) for security. If you want to use
another location or another protocol, set the g:spellfile_URL variable to the
directory that holds the spell files. You can use http:// or ftp://, but you
are taking a security risk then. The |netrw| plugin is used for getting the
file, look there for the specific syntax of the URL. Example: >
server. The protocol used is TLS (`https://`) for security. If you want to
use another location or another protocol, set the g:spellfile_URL variable to
the directory that holds the spell files. You can use `http://` or `ftp://`,
but you are taking a security risk then. The |netrw| plugin is used for
getting the file, look there for the specific syntax of the URL. Example: >
let g:spellfile_URL = 'https://ftp.nluug.nl/vim/runtime/spell'
You may need to escape special characters.

View File

@@ -136,10 +136,10 @@ might want to try the manual way of downloading the file.
Accessing files over the internet works with the netrw plugin. Currently URLs
with these formats are recognized:
ftp:// uses ftp
rcp:// uses rcp
scp:// uses scp
http:// uses wget (reading only)
`ftp://` uses ftp
`rcp://` uses rcp
`scp://` uses scp
`http://` uses wget (reading only)
Vim doesn't do the communication itself, it relies on the mentioned programs
to be available on your computer. On most Unix systems "ftp" and "rcp" will
@@ -147,7 +147,7 @@ be present. "scp" and "wget" might need to be installed.
Vim detects these URLs for each command that starts editing a new file, also
with ":edit" and ":split", for example. Write commands also work, except for
http://.
`http://`.
For more information, also about passwords, see |netrw|.

View File

@@ -316,6 +316,8 @@ Commands:
Editor:
- |prompt-buffer| supports multiline input/paste, undo/redo, and o/O normal
commands.
- |i_CTRL-R| inserts named registers (A-Z,a-z,0-9) literally like pasting instead of
as typed. To get the old behavior you can use `<C-R>=@x`.
Events (autocommands):
- Fixed inconsistent behavior in execution of nested autocommands #23368

View File

@@ -2854,6 +2854,8 @@ static void ins_reg(void)
vim_beep(kOptBoFlagRegister);
need_redraw = true; // remove the '"'
} else {
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
if (literally == Ctrl_O || literally == Ctrl_P) {
// Append the command to the redo buffer.
AppendCharToRedobuff(Ctrl_R);
@@ -2862,7 +2864,11 @@ static void ins_reg(void)
do_put(regname, NULL, BACKWARD, 1,
(literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
} else if (insert_reg(regname, NULL, literally) == FAIL) {
} else if (reg->y_size > 1 && is_literal_register(regname)) {
AppendCharToRedobuff(Ctrl_R);
AppendCharToRedobuff(regname);
do_put(regname, NULL, BACKWARD, 1, PUT_CURSEND);
} else if (insert_reg(regname, NULL, !!literally) == FAIL) {
vim_beep(kOptBoFlagRegister);
need_redraw = true; // remove the '"'
} else if (stop_insert_mode) {

View File

@@ -188,6 +188,7 @@ static bool event_teardown(void)
/// Needed for unit tests.
void early_init(mparm_T *paramp)
{
os_hint_priority();
estack_init();
cmdline_init();
eval_init(); // init global variables

View File

@@ -152,7 +152,7 @@ static inline int op_reg_index(const int regname)
static inline bool is_literal_register(const int regname)
FUNC_ATTR_CONST
{
return regname == '*' || regname == '+';
return regname == '*' || regname == '+' || ASCII_ISALNUM(regname);
}
EXTERN LuaRef repeat_luaref INIT( = LUA_NOREF); ///< LuaRef for "."

View File

@@ -39,6 +39,10 @@
# include "nvim/fileio.h"
#endif
#ifdef __APPLE__
# include <mach/task.h>
#endif
#ifdef HAVE__NSGETENVIRON
# include <crt_externs.h>
#endif
@@ -367,6 +371,18 @@ int64_t os_get_pid(void)
#endif
}
/// Signals to the OS that Nvim is an application for "interactive work"
/// which should be prioritized similar to a GUI app.
void os_hint_priority(void)
{
#ifdef __APPLE__
// By default, processes have the TASK_UNSPECIFIED "role", which means all of its threads are
// clamped to Default QoS. Setting the role to TASK_DEFAULT_APPLICATION removes this clamp.
integer_t policy = TASK_DEFAULT_APPLICATION;
task_policy_set(mach_task_self(), TASK_CATEGORY_POLICY, &policy, 1);
#endif
}
/// Gets the hostname of the current machine.
///
/// @param hostname Buffer to store the hostname.

View File

@@ -335,7 +335,8 @@ ScreenGrid *ui_comp_get_grid_at_coord(int row, int col)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
ScreenGrid *grid = &wp->w_grid_alloc;
if (row >= grid->comp_row && row < grid->comp_row + grid->rows
&& col >= grid->comp_col && col < grid->comp_col + grid->cols) {
&& col >= grid->comp_col && col < grid->comp_col + grid->cols
&& !wp->w_config.hide) {
return grid;
}
}

View File

@@ -61,7 +61,7 @@ static const int included_patches[] = {
2423,
2422,
2421,
// 2420,
2420,
2419,
// 2418,
2417,
@@ -147,7 +147,7 @@ static const int included_patches[] = {
2337,
2336,
2335,
// 2334,
2334,
2333,
2332,
2331,
@@ -174,14 +174,14 @@ static const int included_patches[] = {
2310,
2309,
2308,
// 2307,
2307,
2306,
2305,
2304,
2303,
2302,
2301,
// 2300,
2300,
2299,
2298,
2297,
@@ -193,9 +193,9 @@ static const int included_patches[] = {
2291,
2290,
2289,
// 2288,
// 2287,
// 2286,
2288,
2287,
2286,
2285,
2284,
2283,
@@ -204,7 +204,7 @@ static const int included_patches[] = {
2280,
// 2279,
2278,
// 2277,
2277,
2276,
2275,
2274,
@@ -241,7 +241,7 @@ static const int included_patches[] = {
2243,
2242,
// 2241,
// 2240,
2240,
2239,
2238,
2237,
@@ -268,10 +268,10 @@ static const int included_patches[] = {
2216,
2215,
2214,
// 2213,
2213,
2212,
2211,
// 2210,
2210,
2209,
// 2208,
2207,
@@ -317,7 +317,7 @@ static const int included_patches[] = {
2167,
2166,
2165,
// 2164,
2164,
2163,
2162,
2161,
@@ -367,12 +367,12 @@ static const int included_patches[] = {
2117,
2116,
2115,
// 2114,
2114,
2113,
2112,
2111,
// 2110,
// 2109,
2110,
2109,
2108,
2107,
2106,
@@ -449,7 +449,7 @@ static const int included_patches[] = {
2035,
2034,
2033,
// 2032,
2032,
2031,
2030,
2029,
@@ -472,7 +472,7 @@ static const int included_patches[] = {
2012,
2011,
2010,
// 2009,
2009,
2008,
2007,
2006,
@@ -483,8 +483,8 @@ static const int included_patches[] = {
2001,
2000,
// 1999,
// 1998,
// 1997,
1998,
1997,
// 1996,
1995,
1994,
@@ -518,11 +518,11 @@ static const int included_patches[] = {
1966,
1965,
// 1964,
// 1963,
1963,
1962,
1961,
1960,
// 1959,
1959,
1958,
// 1957,
1956,
@@ -536,7 +536,7 @@ static const int included_patches[] = {
1948,
1947,
1946,
// 1945,
1945,
// 1944,
// 1943,
1942,
@@ -545,14 +545,14 @@ static const int included_patches[] = {
// 1939,
1938,
1937,
// 1936,
1936,
1935,
// 1934,
1934,
1933,
1932,
1931,
1930,
// 1929,
1929,
// 1928,
1927,
1926,
@@ -563,8 +563,8 @@ static const int included_patches[] = {
1921,
// 1920,
// 1919,
// 1918,
// 1917,
1918,
1917,
1916,
1915,
1914,
@@ -574,12 +574,12 @@ static const int included_patches[] = {
1910,
1909,
// 1908,
// 1907,
1907,
// 1906,
// 1905,
// 1904,
1903,
// 1902,
1902,
1901,
1900,
1899,
@@ -607,7 +607,7 @@ static const int included_patches[] = {
1877,
1876,
1875,
// 1874,
1874,
1873,
1872,
1871,
@@ -631,12 +631,12 @@ static const int included_patches[] = {
1853,
1852,
// 1851,
// 1850,
1850,
1849,
1848,
1847,
1846,
// 1845,
1845,
1844,
1843,
1842,
@@ -667,7 +667,7 @@ static const int included_patches[] = {
1817,
1816,
1815,
// 1814,
1814,
// 1813,
1812,
// 1811,
@@ -692,28 +692,28 @@ static const int included_patches[] = {
1792,
1791,
1790,
// 1789,
1789,
1788,
// 1787,
// 1786,
1786,
1785,
// 1784,
1783,
1782,
1781,
1780,
// 1779,
// 1778,
1779,
1778,
1777,
1776,
1775,
1774,
// 1773,
1773,
1772,
1771,
// 1770,
1769,
// 1768,
1768,
1767,
1766,
1765,
@@ -726,10 +726,10 @@ static const int included_patches[] = {
1758,
1757,
1756,
// 1755,
// 1754,
// 1753,
// 1752,
1755,
1754,
1753,
1752,
// 1751,
1750,
1749,
@@ -748,7 +748,7 @@ static const int included_patches[] = {
1736,
1735,
1734,
// 1733,
1733,
1732,
1731,
1730,
@@ -762,7 +762,7 @@ static const int included_patches[] = {
1722,
1721,
1720,
// 1719,
1719,
// 1718,
1717,
1716,
@@ -772,9 +772,9 @@ static const int included_patches[] = {
1712,
1711,
1710,
// 1709,
1709,
1708,
// 1707,
1707,
1706,
1705,
1704,
@@ -803,9 +803,9 @@ static const int included_patches[] = {
1681,
1680,
1679,
// 1678,
1678,
1677,
// 1676,
1676,
1675,
1674,
// 1673,
@@ -815,8 +815,8 @@ static const int included_patches[] = {
1669,
1668,
1667,
// 1666,
// 1665,
1666,
1665,
1664,
1663,
1662,
@@ -825,17 +825,17 @@ static const int included_patches[] = {
// 1659,
1658,
1657,
// 1656,
1656,
1655,
1654,
1653,
1652,
1651,
1650,
// 1649,
1649,
1648,
1647,
// 1646,
1646,
1645,
1644,
1643,
@@ -845,7 +845,7 @@ static const int included_patches[] = {
1639,
1638,
1637,
// 1636,
1636,
1635,
1634,
1633,
@@ -859,14 +859,14 @@ static const int included_patches[] = {
1625,
1624,
1623,
// 1622,
1622,
1621,
// 1620,
1620,
1619,
1618,
// 1617,
1617,
1616,
// 1615,
1615,
1614,
1613,
// 1612,
@@ -879,13 +879,13 @@ static const int included_patches[] = {
1605,
1604,
1603,
// 1602,
1602,
1601,
// 1600,
1599,
1598,
// 1597,
// 1596,
1596,
1595,
1594,
1593,
@@ -919,7 +919,7 @@ static const int included_patches[] = {
1565,
1564,
1563,
// 1562,
1562,
// 1561,
// 1560,
// 1559,
@@ -931,7 +931,7 @@ static const int included_patches[] = {
// 1553,
1552,
1551,
// 1550,
1550,
1549,
// 1548,
1547,
@@ -954,7 +954,7 @@ static const int included_patches[] = {
1530,
1529,
1528,
// 1527,
1527,
1526,
// 1525,
1524,
@@ -1398,7 +1398,7 @@ static const int included_patches[] = {
1086,
1085,
1084,
// 1083,
1083,
1082,
1081,
1080,

View File

@@ -83,6 +83,36 @@ describe('insert-mode', function()
{5:-- INSERT --} |
]])
end)
it('inserts named registers literally', function()
local screen = Screen.new(50, 6)
-- regular text without special charecter command
command('let @a = "test"')
feed('i<C-R>a<ESC>')
screen:expect([[
tes^t |
{1:~ }|*4
|
]])
-- text with backspace character gets written literally by default
command('let @a = "test\\<C-H>"')
feed('cc<C-R>a<ESC>')
screen:expect([[
test{18:^^H} |
{1:~ }|*4
|
]])
-- =@reg<CR> can be used to get effect of keypress
command('let @a = "test\\<C-H>"')
feed('cc<C-R>=@a<CR><ESC>')
screen:expect([[
te^s |
{1:~ }|*4
|
]])
end)
end)
describe('Ctrl-O', function()

View File

@@ -76,7 +76,39 @@ describe('screenchar() and family respect floating windows', function()
describe('with ext_multigrid', function()
with_ext_multigrid(true)
end)
describe('without ext_multigrid', function()
with_ext_multigrid(false)
end)
describe('hidden windows', function()
before_each(function()
clear()
Screen.new(40, 7, {})
api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'aaa' })
end)
local assert_screen_funcs = function()
eq('a', fn.screenstring(1, 1))
eq(97, fn.screenchar(1, 1))
eq({ 97 }, fn.screenchars(1, 1))
eq(fn.screenattr(2, 1), fn.screenattr(1, 1))
end
it('manual', function()
local bufnr = api.nvim_create_buf(false, true)
api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'bb' })
local win_opts = { relative = 'editor', row = 0, col = 0, height = 1, width = 2, hide = true }
api.nvim_open_win(bufnr, false, win_opts)
assert_screen_funcs()
end)
it('from ui2', function()
n.exec_lua('require("vim._extui").enable({ enable = true })')
command('echo "foo"')
assert_screen_funcs()
end)
end)
end)

View File

@@ -2090,7 +2090,7 @@ func Test_Cmdline()
let g:log = []
let @r = 'abc'
call feedkeys(":0\<C-R>r1\<C-R>\<C-O>r2\<C-R>\<C-R>r3\<Esc>", 'xt')
call feedkeys(":0\<C-R>=@r\<CR>1\<C-R>\<C-O>r2\<C-R>\<C-R>r3\<Esc>", 'xt')
call assert_equal([
\ '0',
\ '0a',

View File

@@ -905,7 +905,7 @@ func Test_cmdline_paste()
" Test for pasting register containing CTRL-H using CTRL-R and CTRL-R CTRL-R
let @a = "xy\<C-H>z"
call feedkeys(":\"\<C-R>a\<CR>", 'xt')
call feedkeys(":\"\<C-R>=@a\<CR>\<CR>", 'xt')
call assert_equal('"xz', @:)
call feedkeys(":\"\<C-R>\<C-R>a\<CR>", 'xt')
call assert_equal("\"xy\<C-H>z", @:)

View File

@@ -1523,7 +1523,7 @@ func Test_complete_reginsert()
exe "normal Goa\<C-P>\<C-R>=\"\\<C-P>\"\<CR>"
call assert_equal('a123', getline(5))
let @r = "\<C-P>\<C-P>"
exe "normal GCa\<C-P>\<C-R>r"
exe "normal GCa\<C-P>\<C-R>=@r\<CR>"
call assert_equal('a12', getline(5))
exe "normal GCa\<C-P>\<C-R>=\"x\"\<CR>"
call assert_equal('a1234x', getline(5))