aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/mouse.c
Commit message (Collapse)AuthorAge
* feat(multicursor): zq operator; cursor-local marks #42148Justin M. Keyes2026-09-29
| | | | | | | | | | | | | | | | | | Problem: - `[count]Q` and `{Visual}Q` are implemented as ad hoc utils, because `Q` is not an "operator". - `Q` always "toggles", it is not "idempotent". - Various *cursor-relative* marks (`'.`, `'[`) are not saved/restored per-cursor, so they don't work during cascade. - Insert cascade clobbers the primary's `'^` and changelist. Solution: - Introduce the `zq{motion}` operator, which places cursors at every reachable `{motion}`. - `{Visual}Q` is now an alias to `{Visual}zqj`. - Introduce `1Q` and `2Q` for idempotent cursor placement. - Drop `[count]Q`, it's redundant with `zqgn`. - Classify cursor-relative marks as `type=motion` instead of `type=jump`. Save/restore per-cursor during cascade.
* perf(mbyte): single decoder loop for both cluster byte length and cell widthbfredl2026-09-25
| | | | | | | | | | | | | | | This applies to the callsites which already used utf_ptr2CharInfo and then utfc_next. There is more work to be done, but this is a lagom bisectable unit. A lot of code is still wounded by the historical distinction between "low" characters (c < 128) and "high" characters, with the UTF-8 specific rules behind compiler flags and virtual function calls. As a result, there are both ptr2cells() and utf_ptr2cells(). My work aims at slowly reintegrating the realms. As such, we consider ptr2cells() the "correct" abstraction as is matches what actually is printed in a displayed message and buffer text without extra bells and whistles, except for tabs.
* vim-patch:9.1.1429: dragging outside the tabpanel changes tabpagenrJan Edmund Lazo2026-09-06
| | | | | | | | | | | | Problem: dragging outside the tabpanel changes tabpagenr (char101) Solution: set in_tab_line and in_tabpanel variables (Hirohito Higashi) fixes: vim/vim#17385 closes: vim/vim#17431 https://github.com/vim/vim/commit/a1522f7c0daeddf91cdb7313bdcccd3b3774e39e Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
* feat(multicursor): MC HAMMER #41587Justin M. Keyes2026-09-01
| | | | | | | | | | | | | | | | | | | | | Other (squashed) commits: fix(tui): emit ui_send output atomically with the frame Problem: tui_ui_send() writes directly to the TTY, bypassing the output buffer. Sequences sent via nvim_ui_send() (e.g. kitty multiple-cursors, or visual-dot-repeat) always arrive in a separate TTY write from the frame they were computed for. This manifests as "tearing", or e.g. in the case of multicursor the terminal renders text with stale cursor overlays. Solution: - tui_ui_send(): while a frame is being assembled (pending invalid regions or buffered output), buffer instead of writing directly. - Out-of-frame sends (tty queries, clear-on-disable) still write immediately. - mcursor.lua: emit the terminal-cursor update at the end of the redraw cycle (`on_end`, when screen positions are final) instead of vim.schedule().
* refactor(input): exec stuffed keys eagerlyJustin M. Keyes2026-08-29
| | | | | | | | | | | | | | | | | | | Problem: The Vim "stuff" concept breaks the ability to reason about the call stack and thus the boundaries of a `CmdAtom`: a stuffed translation ("x" => "dl") defers to the main loop. This "continuation" must be modeled in `CmdAtom`, by checking global flags at undefined times, during undefined circumstances. Solution: - After a stuffed "translation", eagerly execute the stuff buffer (`exec_stuffed()`). - Delete the CmdAtom "continuation" junk. Note: - op_colon runs its cmdline "nested", but that's fine because operators already nest interactive sessions there (op_change runs edit()), and the cmdline is frameless so the operator's frame can own/capture it.
* refactor(cmdatom): do "redo prep" in one place #41348Justin M. Keyes2026-08-17
| | | | | | | | | | | | | | Problem: Redo prep is scattered/duplicated. - `do_pending_operator()` has 3 prep blocks whose conditions must be in sync with `atom_capture_op()`. - insert.c, spell_suggest() hand-roll `redo_new()` + `redo_append_xx()` sequences. - prep_redo() has 2 roles, decided by `keys != NULL`. Solution: - `atom_capture_op()` is the "operator" entry point: capture, then prep. - Extract `prep_redo_visual()`, `atom_capturable()`.
* feat(input)!: CmdAtom event #41297Justin M. Keyes2026-08-14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: There is no unified notion of a "user action". Vim processes input by one-char-at-a-time, and mostly throws away any hints it might gather about the user's action, with one exception: it stores the last _edit_ action (the "redo buffer", encoded as unstructured `["x][v][count]body` bytes). Plugins can only observe individual keys (vim.on_key) and high-level effects (TextChanged, CursorMoved). Solution: - Users can subscribe to `CmdAtom` events to handle any user action. - Event is deferred; handlers cannot cancel or interfere with user actions. - Capture `CmdSpec` from the normal/insert/visual subsystems. - typeahead/readahead stay unstructured (`buffheader_T`): they are key streams, not commands. - the redo/record buffers become `StringBuilder`: fewer allocations/copies. - Repurpose the input/redo engine to accept `CmdSpec` objects. "atom": one repeatable unit of user input, as a resolved (post-mapping) keysequence plus structured fields. Only user actions, not `:normal`, API calls, or non-"t" `feedkeys`. BREAKING: dot-repeat of an Insert session, replays the entire session including cursor-moves (:help ins-repeat). BREAKING: dot-repeat of a Visual operation, replays the selection instead of operating on a fixed-size region.
* feat(options): schema, "dict" options, messagesJustin M. Keyes2026-07-24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Options parsing is still painful for dict-style options. Solution: schema-maxxing => better `opt:get()` (will be the basis for `vim.o()`), unified (and more-detailed) err msgs. - Drop bespoke structure-builder in `_core/options.lua`. - Define `schema` for all non-primitive options (except 'guicursor' and statusline-style options); generate reified keysets `OptKeyDict`). - Generate 'fillchars' => `fcs_tab`, 'listchars' => `lcs_tab`. - `nvim_set_option_value`: - Return the improved structures. Also from `vim.opt.x:get()`. - Eliminate api <=> lua roundtrip, centralize option structure handling. - Improve/unify errors. - Bump ERR_BUFLEN 80 → 256 so the "one of" list isn't truncated. - Eliminate old 'diffopt' order-dependence (`iwhiteall` before `iwhite`) Error samples: Typed-key path (opt_strings_check → diffopt/mousescroll/breakindentopt): E474: Unknown item 'foo' E474: 'context' requires a number E474: 'ver' number is out of range E474: 'algorithm' must be one of: myers, minimal, patience, histogram E474: 'filler' does not take a value Related: - #31084 - #34661 - #31820 - #14739 - #20107 - fix #18875 - :get() returns `{ sbr = true, shift = '3' }` (reified-keyset) instead of `{'sbr', 'shift:3'}` - Setting via table now works too. `object_as_optval_for` `is_map` now recognizes struct options. - fix #30296 - instead of `E474: Invalid argument`, errors now look like: ``` E474: Invalid value 'x', expected one of: single, double: ambiwidth=x E474: Unknown item 'foo': diffopt=foo E474: 'context' requires a number: diffopt=context:x ``` simplify `win_float_parse_option` from #26799.
* refactor(window): extract w_kind for window role #40830glepnir2026-07-20
| | | | | | | | Problem: w_float_is_info conflates a window's role with its floating layout, which are orthogonal properties. Solution: Replace w_float_is_info with a w_kind enum for the window's role.
* refactor(globals): group Visual-mode globals in VisualState #40777Justin M. Keyes2026-07-16
|
* refactor(core): group insert-mode globals in `InsState` #40712Justin M. Keyes2026-07-13
| | | | | | | | | Problem: Insert-mode globals are scattered. Solution: Group them into one struct. Besides improving readability and discoverability, this greatly helps with save/restore of an insert-mode session.
* refactor(insert): rename edit.c => insert.c #40705Justin M. Keyes2026-07-12
| | | | | | | | | | Problem: - `edit.c` is an unnecessarily misleading and less-discoverable name than `insert.c`. - Numerous insert-mode related things are named with a `ins_` prefix. - There is already a `insexpand.c` module... Solution: Rename `edit.c` => `insert.c`.
* refactor(input): rename getchar.c => input.c #40698Justin M. Keyes2026-07-12
| | | | | | | | | | | | Problem: `getchar.c` is a quirky name and doesn't align with our existing `os/input.c` and `tui/input.c` modules, which encompass the same topic at different layers. Solution: Rename `getchar.c` => `input.c` for discoverability. Introduce `dialog.c` for functionality related to showing confirm prompts, dialogs, etc.
* feat(cmdwin): implement cmdwin as a normal buf+winJustin M. Keyes2026-06-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: cmdwin (the `:q` cmdline buffer) has various limitations which require special-casing all over the codebase. Besides complicating the code, it also breaks async plugins if they try to create buffers/windows after some work is done, if the user happens to open cmdwin at the wrong the moment: Lua callback: …/guh.nvim/lua/guh/util.lua:531: E11: Invalid in command-line window; <CR> executes, CTRL-C quits stack traceback: [C]: in function 'nvim_buf_delete' …/guh.nvim/lua/guh/util.lua:531: in function <…/guh.nvim/lua/guh/util.lua:526> Solution: Just say no to "inception". Reimplement cmdwin as a normal buffer+window. All of the cmdwin contortions (in both core, and innocent plugins) exist literally only to support "inception": recursive cmdwin-in-cmdline-things, like `<c-r>=`, `/`, search-during-substitute, `:input()`, etc. So we just won't support that (though I have a potential plan for that later, which I call "modal parking lot"). The benefit is that plugins, and core, no longer have to care about cmdwin. BONUS: - mouse-drag on vertical separators works (it only worked for horizontal/statusline before) - inccommand-in-cmdwin now works correctly, for free (thus don't need #40077). POTENTIAL FOLLOWUPS - Drop `CHECK_CMDWIN` ("E11: Invalid in command-line window"), allow chaos. - Unify `BUFLOCK_OK` / `LOCK_OK` ? DESIGN: - Eliminate lots of C globals, `EX_CMDWIN`, etc. - `text_locked()` no longer reports true for cmdwin. - cmdwin = a normal window with 'winfixbuf', 'bufhidden=wipe', 'buftype=nofile'. Invariants come from those options rather than special cases throughout the codebase. - `nv_record` for q:/q//q? calls Lua `nlua_call_vimfn("vim._core.cmdwin", …)`. No `K_CMDWIN` / cmdline-reader detour. - `cedit_key` (`c_CTRL-F`) schedules a deferred event that calls `vim._core.cmdwin.open(type, content, pos)` and returns `Ctrl_C` so the in-flight cmdline cancels. Reader state is not serialized; instead the captured `(type, line, col)` is replayed via `nvim_feedkeys(type..line.."<CR>", "nt", …)` after user confirms. - On confirm/cancel: `<CR>` / `<C-C>` calls into Lua which closes the window and re-feeds the cmdline. BREAKING CHANGES: - Expression-register cmdline (`<C-R>=` from insert-mode) no longer supports cmdwin. Same applies to `input()` / `inputlist()` (already covered by `text_locked`). - Usage of cmdwin in macros/mappings will probably break (assuming they ever worked).
* feat(column): per row click handlers for 'statuscolumn' (#40265)luukvbaal2026-06-20
| | | | | | | | | | | | | | Problem: - Current 'statuscolumn' click label caveat is restrictive. - v:virtnum is not unique to a line if it has both above and below virtual lines. - 'statuscolumn' click handler may expect v:virt/lnum to be set. Solution: - Store per-row click definitions for the statuscolumn in a (nested line/virt number) map. - Implement strategy that gives each 'statuscolumn' row a unique v:virtnum. - Set v:virt/lnum when determining which line is clicked.
* fix(mouse): click on "below" virtual lines #40217luukvbaal2026-06-13
| | | | | | Problem: Clicking on a "below" virtual line interacts with the line it is attached to for decor/drawing purposes, rather than the line the extmark is placed at. Solution: Account for "below" virtual lines when computing mouse line number.
* vim-patch:9.2.0596: cmdline completion popup cannot be scrolled with the ↵zeertzjq2026-06-08
| | | | | | | | | | | | | | | | | | | mouse (#40142) Problem: In command-line completion with a popup menu ('wildoptions' contains "pum"), the info popup shown next to the menu could not be scrolled, unlike the Insert mode completion info popup which scrolls with the mouse wheel. Solution: When the mouse pointer is on top of the info popup, scroll it with the mouse wheel in command-line mode as well, without closing the completion popup menu. closes: vim/vim#20146 closes: vim/vim#20418 https://github.com/vim/vim/commit/96dbab257a881ee4a552e1acf62e7d4168dc444a Co-authored-by: Hirohito Higashi <h.east.727@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(mouse): mouse=n should not adjust visual selectionNick Krichevsky2026-05-19
| | | | | | | | | | | | | | | | | | | Problem: When mouse=n is set - Dragging the mouse enters visual mode, and then stops listening for mouse events. - Double/Triple/Quad clicking performs selections. - Clicking in visual mode moves the cursor (though not through the TUI). Solution: Explicitly gate mouse actions that affect visual mode with a check for MOUSE_VISUAL. This matches the behavior described in :help mouse. > If enabled for "v" (Visual mode) then double-click selects word-wise, > triple-click makes it line-wise, and quadruple-click makes it > rectangular block-wise.
* vim-patch:9.2.0289: 'linebreak' may lead to wrong Visual block highlighting ↵zeertzjq2026-04-04
| | | | | | | | | | | | | (#38749) Problem: 'linebreak' may lead to wrong Visual block highlighting when end char occupies multiple cells (after 7.4.467). Solution: Exclude 'linebreak' from the ending column instead of setting 'virtualedit' temporarily (zeertzjq). fixes: vim/vim#19898 closes: vim/vim#19900 https://github.com/vim/vim/commit/23be1889d1a1212445ca8bb9cd378484d3755f79
* vim-patch:8.1.2077: the ops.c file is too bigJan Edmund Lazo2025-09-26
| | | | | | | | | | Problem: The ops.c file is too big. Solution: Move code for dealing with registers to a new file. (Yegappan Lakshmanan, closes vim/vim#4982) https://github.com/vim/vim/commit/4aea03eb875613e3eae2125b84f02b7cd898b2f8 Co-authored-by: Bram Moolenaar <Bram@vim.org>
* feat(ui): support grid=0 in nvim_input_mouse #32535fredizzimo2025-09-13
| | | | | | | | | | | | | | | | | Problem: Multigrid UIs have to find out which window to send the input by using the Nvim focus rules, which are not fully documented. Furthermore,`getmousepos()` has several problems when multigrid is enabled, with the main one being that screenrow and screencol are window relative instead of screen relative, due to the fact that the UI don't send any absolute coordinates. Solution: Allow passing 0 as grid to `nvim_input_mouse`, with absolute coordinates, which lets nvim determine the actual window to send the mouse input to. This works as long as nvim is in charge of the window positioning. If the UI repositions or resizes the windows, it can still pass the grid it determines like before.
* vim-patch:8.1.1920: cannot always close a popup when filter consumes all eventsJan Edmund Lazo2025-09-09
| | | | | | | | | | Problem: Cannot close a popup by the X when a filter consumes all events. Solution: Check for a click on the close button before invoking filters. (closes vim/vim#4858) https://github.com/vim/vim/commit/f63962378dc32c7253e4825b4b0f414a81c1dd3e Co-authored-by: Bram Moolenaar <Bram@vim.org>
* vim-patch:8.1.1751: when redrawing popups plines_win() may be called oftenJan Edmund Lazo2025-09-09
| | | | | | | | | Problem: When redrawing popups plines_win() may be called often. Solution: Pass a cache to mouse_comp_pos(). https://github.com/vim/vim/commit/9d5ffceb3fea247a88d4d3936e97b7f488aab6ff Co-authored-by: Bram Moolenaar <Bram@vim.org>
* refactor(build): remove INCLUDE_GENERATED_DECLARATIONS guardsbfredl2025-08-14
| | | | | | | | | These are not needed after #35129 but making uncrustify still play nice with them was a bit tricky. Unfortunately `uncrustify --update-config-with-doc` breaks strings with backslashes. This issue has been reported upstream, and in the meanwhile auto-update on every single run has been disabled.
* refactor(ui): separate types for allocated grids and viewportsbfredl2025-04-28
|
* fix(mouse): do not fetch clipboard twice when pasting with middle button #33494Dmitry Torokhov2025-04-16
| | | | | | | | | | | | | | | | | | Problem: When doing paste operation mouse code tries to figure out it it is dealing with a multi-line register by calling yank_register_mline(), which fetches register data and checks its type. Later the code calls either do_put() or insert_reg() which fetch register data again. This is unnoticeable when working with internal neovim registers, but starts hurting when dealing with clipboards, especially remote one (forwarded X or socket tunnel or similar). Solution: Change yank_register_mline() to also return pointer to the register structure prepared for pasting, and insert_reg() to accept such register pointer and use it if it is supplied. do_put() already has support for accepting a register structure to be used for pasting. Fixes #33493
* fix(marks): clamp conceal_lines corrected line number #33464luukvbaal2025-04-14
| | | | | | Problem: Line number corrected for conceal_lines may be set beyond eob when the last buffer line is concealed, causing ml_get errors. Solution: Avoid setting line number beyond eob.
* fix(mouse): mouseclick after conceal_lines is miscalculated #33451luukvbaal2025-04-13
| | | | | | | Problem: Computed buffer line for mouse position does not take into account concealed lines on the reached row. Solution: Adjust for concealed lines at the end of the loop computing the buffer position.
* fix(mouse): crash with click on win-separator in statusline (#33091)Shadman2025-03-28
| | | | | | | Problem: Clicking on window separator in statusline crashes Nvim due to out of bound memory access Solution: Check if the click location is within clicking range before applying it.
* fix(mouse): 'statuscolumn' fold and popopmenu handlingLuuk van Baal2025-01-23
| | | | | | | | | Problem: A right-click on the 'statuscolumn' does not open the popupmenu, even if a cell without a clickdef is clicked. Clicking the %C fold item does not open/close the fold. Solution: Open the popupmenu when there is no clickdef like right-clicking the sign/numbercolumn does. Fill "linebuf_vcol" when drawing the 'statuscolumn' to handle foldcolumn item clicks.
* feat(float): allow enabling mouse for non-focusable window (#30844)zeertzjq2024-10-20
| | | | Problem: Cannot allow mouse interaction for non-focusable float window. Solution: Add a "mouse" field to float window config.
* fix(mouse): indicate X1 and X2 button clicks on statusline (#30655)zeertzjq2024-10-04
|
* refactor: collapse statements in single assignmentsLewis Russell2024-07-30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Variables are often assigned multiple places in common patterns. Solution: Replace these common patterns with different patterns that reduce the number of assignments. Use `MAX` and `MIN`: ```c if (x < y) { x = y; } // --> x = MAX(x, y); ``` ```c if (x > y) { x = y; } // --> x = MIN(x, y); ``` Use ternary: ```c int a; if (cond) { a = b; } els { a = c; } // --> int a = cond ? b : c; ```
* fix(mouse): don't treat click on hsep as click on statusline (#29565)zeertzjq2024-07-05
| | | This allows showing popup menu when right-clicking on hsep or cmdline.
* fix(mouse): early return when clicking in padded 'statuscolumn' (#29394)luukvbaal2024-06-19
| | | | | | Problem: Hit assert when clicking inside a padded 'statuscolumn' that is padded beyond the length of the allocated click_defs. Solution: Still consider this a "in_statuscol" click, but return early when about to execute the click func.
* vim-patch:9.1.0406: Divide by zero with getmousepos() and 'smoothscroll' ↵zeertzjq2024-05-11
| | | | | | | | | | | (#28701) Problem: Divide by zero with getmousepos() and 'smoothscroll'. Solution: Don't compute skip_lines when width1 is zero. (zeertzjq) closes: vim/vim#14747 https://github.com/vim/vim/commit/031a745608d615d56f9d79bb0f76e2a74b2eaf14
* fix(lua): vim.fn.has('nvim-0.10') in fast context, used by vim.deprecatebfredl2024-04-25
|
* vim-patch:9.1.0215: Half-page scrolling does not support smooth-scrollingLuuk van Baal2024-03-28
| | | | | | | | | | | | | Problem: Page-wise scrolling with Ctrl-D/Ctrl-U implements it's own logic to change the topline and cursor. More logic than necessary for scrolling with Ctrl-F/Ctrl-B was removed in patch 9.1.0211. Solution: Re-use the logic from Ctrl-E/Ctrl-Y/Ctrl-F/Ctrl-B while staying backward compatible as much as possible. Restore some of the logic that determined how many lines will be scrolled (Luuk van Baal) https://github.com/vim/vim/commit/5a2e3ec9ac72b6e644fea4ebba7e632498296e2f
* vim-patch:9.1.0184: Cursor pos wrong when clicking with conceal and wrap ↵zeertzjq2024-03-17
| | | | | | | | | | | | | | | | (#27890) Problem: Cursor position wrong when clicking with conceal and wrap. Solution: Use the virtual column of the last char for ScreenCols[] in boguscols. Remove use of MAXCOL in ScreenCols[]. Rename third argument of wlv_screen_line() to "clear_end" as that's clearer what it does (zeertzjq). related: 14192 closes: vim/vim#14200 https://github.com/vim/vim/commit/d0c1b7723f7e73763597af2f97a53d94ab7ed020 Rename win_put_linebuf() to wlv_put_linebuf().
* fix(api/buffer): fix handling of viewport of non-current bufferbfredl2024-03-13
| | | | | | | | | | | A lot of functions in move.c only worked for curwin, alternatively took a `wp` arg but still only work if that happens to be curwin. Refactor those that are needed for update_topline(wp) to work for any window. fixes #27723 fixes #27720
* feat(tabline): middle mouse button now closes tab (#27522)Nacho Nieva2024-02-19
|
* refactor: rename w_float_config to w_config #27419Will Hopkins2024-02-10
| | | Follows up on rename of `FloatConfig` to `WinConfig` in #27397.
* vim-patch:9.1.0077: Unnecessary call to redraw_for_cursorline() in ↵zeertzjq2024-02-06
| | | | | | | | | | | | | | nv_mousescroll() (#27359) Problem: The call to redraw_for_cursorline() in nv_mousescroll() is unnecessary because redraw_for_cursorline() only sets redraw type to UPD_VALID, and all code paths in do_mousescroll() already set redraw type to at least UPD_VALID. Solution: Remove call to redraw_for_cursorline() in nv_mousescroll(). (zeertzjq) closes: vim/vim#13979 https://github.com/vim/vim/commit/3f1b5312e0fa0089f255bf9c0c3b27590552119e
* vim-patch:9.1.0047: issues with temp curwin/buf while cmdwin is openSean Dewar2024-01-28
| | | | | | | | | | | | | | | | | Problem: Things that temporarily change/restore curwin/buf (e.g: win_execute, some autocmds) may break assumptions that curwin/buf is the cmdwin when "cmdwin_type != 0", causing issues. Solution: Expose the cmdwin's real win/buf and check that instead. Also try to ensure these variables are NULL if "cmdwin_type == 0", allowing them to be used directly in most cases without checking cmdwin_type. (Sean Dewar) Reset and save `cmdwin_old_curwin` in a similar fashion. Apply suitable changes for API functions and add Lua tests. https://github.com/vim/vim/commit/988f74311c26ea9917e84fbae608de226dba7e5f
* refactor: IWYU (#27186)zeertzjq2024-01-25
|
* refactor: use "csarg" for CharsizeArg variables (#27123)zeertzjq2024-01-22
|
* perf: reuse fast character size calculation algorithm from getvcol()VanaIgr2024-01-22
|
* refactor(IWYU): fix headersdundargoc2024-01-11
| | | | | | Remove `export` pramgas from defs headers as it causes IWYU to believe that the definitions from the defs headers comes from main header, which is not what we really want.
* fix(terminal): check if mouse on statusline/tabline/winbar/vsep (#26892)zeertzjq2024-01-05
|
* refactor: follo