Skip to content

bug: picker crashes with "index out of range" when LSP symbol line ends with emoji #2704

@snapwich

Description

@snapwich

Did you check docs and existing issues?

  • I have read all the snacks.nvim docs
  • I have updated the plugin to the latest version before submitting this issue
  • I have searched the existing issues of snacks.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.12.0-dev

Operating system/version

Ubuntu 24.04 (WSL2)

Describe the bug

When using the LSP Symbols picker on a markdown file, navigating past a symbol whose heading ends with an emoji crashes with E5108: index out of range.

For example, editing docs/dashboard.md line 18 to ## Usage 🚀. Opening LSP Symbols on this file (ss) and moving the cursor past that heading in the picker triggers:

E5108: Lua: vim/_editor.lua:0: index out of range
stack traceback:
[C]: in function 'error'
vim/_editor.lua: in function 'str_byteindex'
...snacks.nvim/lua/snacks/picker/util/init.lua:402: in function 'resolve'
...snacks.nvim/lua/snacks/picker/util/init.lua:406: in function 'resolve_loc'
...snacks.nvim/lua/snacks/picker/core/picker.lua:553: in function 'resolve'
...snacks.nvim/lua/snacks/picker/core/picker.lua:586: in function 'current'
...snacks.nvim/lua/snacks/picker/core/actions.lua:50: in function 'fn'
...snacks.nvim/lua/snacks/win.lua:362: in function <...snacks.nvim/lua/snacks/win.lua:357>

This may be related to #2389, which was fixed in 46917d0 by correcting the vim.str_byteindex capability check. I've confirmed that fix is present in my
checkout. However, I think the crash is still occurring because the resolve helper in resolve_loc (util/init.lua:402) calls M.str_byteindex without handling
out-of-range indices:

Claude's analysis

local col = line and M.str_byteindex(line, pos.character, item.loc.encoding) or pos.character

When the LSP server returns a pos.character that exceeds the character count of the line in the given encoding (which happens with emojie.g., 🚀 is 4 UTF-8
 bytes but 2 UTF-16 code units), vim.str_byteindex throws.

Analysis of M.str_byteindex:
- The new Neovim API (vim.str_byteindex(s, encoding, index, strict_indexing)) supports a strict_indexing parameterpassing false would clamp out-of-range
indices instead of erroring. But the call site never passes this parameter.
- The old Neovim API has no strict_indexing support and always throws on out-of-range.

A potential fix would be to pass strict_indexing = false at the call site (line 402) and add pcall protection in the old-API branches of M.str_byteindex with
a fallback to #s (byte length = end of line).


### Steps To Reproduce

1. Open docs/dashboard.md:18 in this repo and edit emoji to be end of line (or open any markdown file with a heading ending in an emoji)
2. Open LSP Symbols picker (:lua Snacks.picker.lsp_symbols())
3. Navigate past the ## Usage 🚀 heading entry in the picker list


### Expected Behavior

The picker should navigate past the symbol without crashing.

### Repro

```lua

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingstaleThis issue or PR has been inactive for a whilewontfixThis issue will not be fixed or implemented

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions