Extmarks can contain URLs which can then be drawn in any supporting UI.
In the TUI, for example, URLs are "drawn" by emitting the OSC 8 control
sequence to the TTY. On terminals which support the OSC 8 sequence this
will create clickable hyperlinks.
URLs are treated as inline highlights in the decoration subsystem, so
are included in the `DecorSignHighlight` structure. However, unlike
other inline highlights they use allocated memory which must be freed,
so they set the `ext` flag in `DecorInline` so that their lifetimes are
managed along with other allocated memory like virtual text.
The decoration subsystem then adds the URLs as a new highlight
attribute. The highlight subsystem maintains a set of unique URLs to
avoid duplicating allocations for the same string. To attach a URL to an
existing highlight attribute we call `hl_add_url` which finds the URL in
the set (allocating and adding it if it does not exist) and sets the
`url` highlight attribute to the index of the URL in the set (using an
index helps keep the size of the `HlAttrs` struct small).
This has the potential to lead to an increase in highlight attributes
if a URL is used over a range that contains many different highlight
attributes, because now each existing attribute must be combined with
the URL. In practice, however, URLs typically span a range containing a
single highlight (e.g. link text in Markdown), so this is likely just a
pathological edge case.
When a new highlight attribute is defined with a URL it is copied to all
attached UIs with the `hl_attr_define` UI event. The TUI manages its own
set of URLs (just like the highlight subsystem) to minimize allocations.
The TUI keeps track of which URL is "active" for the cell it is
printing. If no URL is active and a cell containing a URL is printed,
the opening OSC 8 sequence is emitted and that URL becomes the actively
tracked URL. If the cursor is moved while in the middle of a URL span,
we emit the terminating OSC sequence to prevent the hyperlink from
spanning multiple lines.
This does not support nested hyperlinks, but that is a rare (and,
frankly, bizarre) use case. If a valid use case for nested hyperlinks
ever presents itself we can address that issue then.
'foldtext' can be set to an empty string to disable and render the
line with:
- extmark highlight
- syntax highlighting
- search highlighting
- no line wrapping
- spelling
- conceal
- inline virtual text
- respects `fillchars:fold`
Currently normal virtual text is not displayed
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
perf: make screen size and position calculations more efficient
N/A patches for version.c:
vim-patch:9.1.0037: Calling get_breakindent_win() repeatedly when computing virtcol
vim-patch:9.1.0038: Unnecessary loop in getvcol()
When computing on-screen size or position, the size 'breakindent' and 'showbreak' is now cached,
and checks for whether a faster character size function can be used are performed only once at the start.
Multibyte characters are not decodes multiple times anymore, and character decoding functions are more efficient.
Additionally, the amount of trailing spaces for pasted blockwise text is now calculated correctly for multibyte characters.
Internal lisp formatting now doesn't erroneously use inline virtual text from a different line.
- Problem: One cannot easily write something like, for example:
`version_current >= {0, 10, 0}`; writing like
`not vim.version.lt(version_current, {0, 10, 0})` is verbose.
- Solution: add {`le`,`ge`} in addition to {`lt`,`gt`}.
- Also improve typing on the operator methods: allow `string` as well.
- Update the example in `vim.version.range()` docs: `ge` in place of
`gt` better matches the semantics of `range:has`.
Problem: Sharing queries with upstream and Helix is difficult due to
different capture names.
Solution: Define and document a new set of standard captures that
matches tree-sitter "standard captures" (where defined) and is closer to
Helix' Atom-style nested groups.
This is a breaking change for colorschemes that defined highlights based
on the old captures. On the other hand, the default colorscheme now
defines links for all standard captures (not just those used in bundled
queries), improving the out-of-the-box experience.
The motivation for this update is Issue #15365, where background=light
is not properly set for Nvim running from an Nvim :terminal. This can be
encountered when e.g., opening a terminal to make git commits, which
opens EDITOR=nvim in the nested terminal.
Under the implementation of this commit, the OSC response always
indicates a black or white foreground/background. While this may not
reflect the actual foreground/background color, it permits 'background'
to be retained for a nested Nvim instance running in the terminal
emulator. The behaviour matches Vim.
Problem: Current values of `StatusLine` and `StatusLineNC` are currently
designed to be visually distinctive while being not intrusive.
However, the compromise was more shifted towards "not intrusive".
After the feedback, statusline highlight groups should be designed to:
- Make current window clearly noticeable. Meaning `StatusLine` and
`StatusLineNC` should obviously differ.
- Make non-current windows clearly separable. Meaning `StatusLineNC`
and `Normal`/`NormalNC` should obviously differ.
Solution:
- Update `StatusLineNC` to have more visible background.
- Update `StatusLine` to be inverted variant of `StatusLineNC`.
- Update `WinBar` and `WinBarNC` to not link to `StatusLine` and
`StatusLineNC` because it makes two goals harder to achieve.
- Update `TabLine` to link to `StatusLineNC` instead of `StatusLine`
to not be very visually intrusive.
This commit implements a new TermRequest autocommand event and has Neovim
emit this event when children of terminal buffers emit an OSC or DCS sequence
libvterm does not handle.
The TermRequest autocommand event has additional data in the
v:termrequest variable.
Co-authored-by: Gregory Anders <greg@gpanders.com>
Problem:
Currently `deepcopy` hashes every single tables it copies so it can be
reused. For tables of mostly unique items that are non recursive, this
hashing is unnecessarily expensive
Solution:
Port the `noref` argument from Vimscripts `deepcopy()`.
The below benchmark demonstrates the results for two extreme cases of
tables of different sizes. One table that uses the same table lots of
times and one with all unique tables.
| test | `noref=false` (ms) | `noref=true` (ms) |
| -------------------- | ------------------ | ----------------- |
| unique tables (50) | 6.59 | 2.62 |
| shared tables (50) | 3.24 | 6.40 |
| unique tables (2000) | 23381.48 | 2884.53 |
| shared tables (2000) | 3505.54 | 14038.80 |
The results are basically the inverse of each other where `noref` is
much more performance on tables with unique fields, and `not noref` is
more performant on tables that reuse fields.
feat(diagnostic): add `vim.diagnostic.count()`
Problem: Getting diagnostic count based on the output of
`vim.diagnostic.get()` might become costly as number of diagnostic
entries grows. This is because it returns a copy of diagnostic cache
entries (so as to not allow users to change them in place).
Getting information about diagnostic count is frequently used in
statusline, so it is important to be as fast as reasonbly possible.
Solution: Add `vim.diagnostic.count()` which computes severity
counts without making copies.
Problem: Unable to predict which byte-offset to place virtual text to
make it repeat visually in the wrapped part of a line.
Solution: Add a flag to nvim_buf_set_extmark() that causes virtual
text to repeat in wrapped lines.
Problem:
Bundled color schemes use `:hi clear` and only define Vim's highlight
groups. This results into Nvim-specific highlight groups using
definitions from Nvim's default color scheme, which are not always
linked to a Vim's highlight group.
Solution:
Restore links to Vim's highlight groups which were present before Nvim's
default color scheme update.
Diagnostic signs should now be configured with vim.diagnostic.config(),
but "legacy" sign definitions should go through the standard deprecation
process to minimize the impact from breaking changes.
Problem: Updating default color scheme produced some feedback.
Solution: Address the feedback.
Outline of the changes:
- Colors `Grey1` and `Grey2` are made a little bit more extreme (dark -
darker, light - lighter) to increase overall contrast.
- `gui` colors are treated as base with `cterm` colors falling back to
using 0-15 colors which come from terminal emulator.
- Update highlight group definition to not include attribute definition
if it is intended to staty uncolored.
- Tweak some specific highlight groups.
- Add a list of Neovim specific highlight groups which are now defined
differently in a breaking way.
- Minor tweaks in several other places related to default color scheme.
Problem: We have `P_(BOOL|NUM|STRING)` macros to represent an option's type, which is redundant because `OptValType` can already do that. The current implementation of option type flags is also too limited to allow adding multitype options in the future.
Solution: Remove `P_(BOOL|NUM|STRING)` and replace it with a new `type_flags` attribute in `vimoption_T`. Also do some groundwork for adding multitype options in the future.
Side-effects: Attempting to set an invalid keycode option (e.g. `set t_foo=123`) no longer gives an error.
Problem:
Unlike termopen(), nvim_open_term() PTYs do not carriage-return the
cursor on newline ("\n") input.
nvim --clean
:let chan_id = nvim_open_term(1, {})
:call chansend(chan_id, ["here", "are", "some", "lines"])
Actual behavior:
here
are
some
lines
Expected behaviour:
here
are
some
lines
Solution:
Add `force_crlf` option, and enable it by default.
* fix garbled item for new treesitter injection format
* add missing item for new `vim.lpeg` and `vim.re`
* use taglinks where possible
* remove redundant "Added" and "Removed" from items
Enable 'termguicolors' automatically when Nvim can detect that truecolor
is supported by the host terminal.
If $COLORTERM is set to "truecolor" or "24bit", or the terminal's
terminfo entry contains capabilities for Tc, RGB, or setrgbf and
setrgbb, then we assume that the terminal supports truecolor. Otherwise,
the terminal is queried (using both XTGETTCAP and SGR + DECRQSS). If the
terminal's response to these queries (if any) indicates that it supports
truecolor, then 'termguicolors' is enabled.
Problem: Default color scheme is suboptimal.
Solution: Start using new color scheme. Introduce new `vim` color scheme
for opt-in backward compatibility.
------
Main design ideas
- Be "Neovim branded".
- Be minimal for 256 colors with a bit more shades for true colors.
- Be accessible through high enough contrast ratios.
- Be suitable for dark and light backgrounds via exchange of dark and
light palettes.
------
Palettes
- Have dark and light variants. Implemented through exporeted
`NvimDark*` and `NvimLight*` hex colors.
- Palettes have 4 shades of grey for UI elements and 6 colors (red,
yellow, green, cyan, blue, magenta).
- Actual values are computed procedurally in Oklch color space based on
a handful of hyperparameters.
- Each color has a 256 colors variant with perceptually closest color.
------
Highlight groups
Use:
- Grey shades for general UI according to their design.
- Bold text for keywords (`Statement` highlight group). This is an
important choice to increase accessibility for people with color
deficiencies, as it doesn't rely on actual color.
- Green for strings, `DiffAdd` (as background), `DiagnosticOk`, and some
minor text UI elements.
- Cyan as main syntax color, i.e. for function usage (`Function`
highlight group), `DiffText`, `DiagnosticInfo`, and some minor text UI
elements.
- Red to generally mean high user attention, i.e. errors; in particular
for `ErrorMsg`, `DiffDelete`, `DiagnosticError`.
- Yellow very sparingly only with true colors to mean mild user
attention, i.e. warnings. That is, `DiagnosticWarn` and `WarningMsg`.
- Blue very sparingly only with true colors as `DiagnosticHint` and some
additional important syntax group (like `Identifier`).
- Magenta very carefully (if at all).
------
Notes
- To make tests work without relatively larege updates, each one is
prepended with an equivalent of the call `:colorscheme vim`.
Plus some tests which spawn new Neovim instances also now use 'vim'
color scheme.
In some cases tests are updated to fit new default color scheme.
Problem: The legacy signlist data structures and associated functions are
redundant since the introduction of extmark signs.
Solution: Store signs defined through the legacy commands in a hashmap, placed
signs in the extmark tree. Replace signlist associated functions.
Usage of the legacy sign commands should yield no change in behavior with the
exception of:
- "orphaned signs" are now always removed when the line it is placed on is
deleted. This used to depend on the value of 'signcolumn'.
- It is no longer possible to place multiple signs with the same identifier
in a single group on multiple lines. This will now move the sign instead.
Moreover, both signs placed through the legacy sign commands and through
|nvim_buf_set_extmark()|:
- Will show up in both |sign-place| and |nvim_buf_get_extmarks()|.
- Are displayed by increasing sign identifier, left to right.
Extmark signs used to be ordered decreasingly as opposed to legacy signs.
Problem: buffer text with composing chars are converted from UTF-8
to an array of up to seven UTF-32 values and then converted back
to UTF-8 strings.
Solution: Convert buffer text directly to UTF-8 based schar_T values.
The limit of the text size is now in schar_T bytes, which is currently
31+1 but easily could be raised as it no longer multiplies the size
of the entire screen grid when not used, the full size is only required
for temporary scratch buffers.
Also does some general cleanup to win_line text handling, which was
unnecessarily complicated due to multibyte rendering being an "opt-in"
feature long ago. Nowadays, a char is just a char, regardless if it consists
of one ASCII byte or multiple bytes.
Use the XTGETTCAP sequence to determine if the host terminal supports
the OSC 52 sequence and, if it does, enable the OSC 52 clipboard
provider by default.
This is only done automatically when all of the following are true:
1. Nvim is running in the TUI
2. 'clipboard' is not set to unnamed or unnamedplus
3. g:clipboard is unset
4. Nvim is running in an SSH connection ($SSH_TTY is set)
5. Nvim is not running inside tmux ($TMUX is unset)
The 'termsync' option enables a mode (provided the underlying terminal
supports it) where all screen updates during a redraw cycle are buffered
and drawn together when the redraw is complete. This eliminates tearing
or flickering in cases where Nvim redraws slower than the terminal
redraws the screen.
refactor!: `vim.lsp.inlay_hint()` -> `vim.lsp.inlay_hint.enable()`
Problem:
The LSP specification allows inlay hints to include tooltips, clickable
label parts, and code actions; but Neovim provides no API to query for
these.
Solution:
Add minimal viable extension point from which plugins can query for
inlay hints in a range, in order to build functionality on top of.
Possible Next Steps
---
- Add `virt_text_idx` field to `vim.fn.getmousepos()` return value, for
usage in mappings of `<LeftMouse>`, `<C-LeftMouse>`, etc