Repository navigation
Conversation
atusy
force-pushed
the
feat/lsp-external-completion
branch
3 times, most recently
from
October 20, 2026 15:32
0f38ee8 to
62078f9
Compare
atusy
marked this pull request as ready for review
October 20, 2026 15:37
lsp.lua mixed three concerns: generating candidates, shaping them for the builtin completion UI, and the in-process transport. Moving the first into lsp/candidates.lua lets later changes touch the transport or the item shape without scrolling past the dictionary lookup. No behavior change. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…aping The completion list mixed what every LSP client needs (items, ranges, sort order, data) with what only Neovim's builtin menu needs (completeopt, insertOnSelect label tricks, snippet escaping). Building the neutral list in lsp/list.lua makes that boundary explicit, so a different client can consume the same list without inheriting builtin workarounds. No behavior change for the builtin menu. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…dule init.lua carried per-UI branches for detecting a visible menu and for the confirm key. Collecting them in completion.lua leaves one place to extend when another completion UI needs the same treatment, instead of growing init.lua's complete_info and native_confirm_key. No behavior change. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
pum.vim and nvim-cmp were the only non-builtin UIs skkelua could drive, and only through hard-coded detection. A UI that owns its own menu now reports the selected LSP item and the keys that confirm it, so <C-y> and <CR> follow its selection instead of the builtin pum's. The selected item lets a selected [辞書登録] item be recognized and keep the pre-edit for every UI. The text a candidate inserts is read from the item's data, so the UI does not have to say what it inserted. An explicit adapter wins over automatic detection. vim_status() asks the adapter on every keypress, so a stale menu object must not break all of skkelua's input: a failing adapter counts as "no selection" and warns once, and a confirm() that is not a string is ignored. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Learning a confirmed candidate and opening the registration prompt were wired to the builtin menu's CompleteDone, so every other LSP client had no way to trigger them. The server now advertises skkelua.accept, and each item carries it as its command. Clients run an item's command only when it is confirmed, so cancelling (<Esc>, <C-e>) needs no special handling here, and the builtin menu relies on the same path instead of its own autocmd. The registration prompt opens straight from the command, one tick sooner than the extra schedule it used to wait for. Tests drive the real builtin menu to pin that confirming learns exactly once, cancelling learns nothing, and [辞書登録] opens the prompt once. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
lsp.start(bufnr) attaches a buffer to one client that is kept across SKK enable/disable, does not enable the builtin menu, and returns the UI-independent list. A UI can therefore ask the same server for candidates without a Lua API of its own. The in-process server now answers every request it receives (an error for unsupported methods, a failure reply when building the list throws) and returns true and a request id from request(), which clients use to tell whether a request was sent and to cancel it; the builtin menu ignores the return value, which is why only external clients depended on it. The requested document is looked up in the current buffer first, since requests arrive on every keystroke. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Cancelling the registration prompt restores the pre-edit without typing, so no UI's autotrigger runs. skkelua still re-requests builtin completion, and fires skkelua-pre-edit-restored so any other UI can re-request its own, without every adapter having to carry a callback for it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The shared client, the accept command and the adapter hook are only useful to someone who knows the contract: which request positions are honored, that confirmation (not cancellation) must run the item's command, and what state, confirm and trigger are expected to do. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
atusy
force-pushed
the
feat/lsp-external-completion
branch
from
October 20, 2026 16:36
62078f9 to
e66deb4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Lets completion UIs other than Neovim's builtin menu use skkelua's candidates, through the in-process LSP server rather than a parallel Lua API. This is a rework of #1 following the maintainer's direction that SKK conversion logic should live in the LSP server as much as possible; #1 is left open for reference and can be closed once this one is accepted.
CompletionListare internal tolsp/(lsp/candidates.lua,lsp/list.lua); there is no publicget().command = skkelua.accept; the server declares it inexecuteCommandProviderand handlesworkspace/executeCommand. Clients run an item's command only when it is confirmed, so cancelling (<C-e>,<Esc>) needs no special casing. This replaces theCompleteDoneautocmd, and there is noaccept()fallback in Lua.require("skkelua.lsp").start(bufnr)attaches a buffer to one shared client (kept across SKK enable/disable, builtin UI not enabled) that returns the UI-independent list.require("skkelua.completion").set_adapter({selected, confirm})is the only UI-specific hook left. The server cannot know which item a menu has selected or how to confirm it, so the UI reports them:selected()returns the selected LSPCompletionItem(or nil), andconfirm()returns the keys that confirm it. pum.vim and nvim-cmp are still auto-detected through the same seam; an explicit adapter wins.User skkelua-pre-edit-restoredfires when the pre-edit is restored without typing (e.g. cancelling the registration prompt). Autotrigger does not run then, so a UI re-requests completion from this event; builtin completion is still re-requested by skkelua.Try it with laser.nvim
Minimal config (laser.nvim completing with skkelua's candidates)
Save as
minimal.luaand runNVIM_APPNAME=skkelua-minimal nvim -u minimal.lua(needs Neovim withvim.pack). In insert mode,<C-j>enables SKK andKanjilists the candidates;<C-n>/<C-p>select,<C-y>confirms and teaches skkelua,<C-e>closes.Notes for review
insertOnSelectshaping anddeferOkuriauto-select were compared againstorigin/masteritem by item. The one deliberate difference is that learning now happens one scheduled tick later than the old synchronousCompleteDonehandler;<C-y>/<CR>on a dictionary item are still finalized by skkelua itself and learn synchronously.commandon confirm for learning and[辞書登録]to work; the help says so, including for the auto-detected pum.vim/nvim-cmp (nvim-cmp does).completeTypeinvim_status()is now"external"for pum.vim/nvim-cmp (was"pum.vim"/"cmp"), andcompleteInfo.selectedis0/-1for them.Testing
nvim --clean --headless -l tests/run.luapasses. New coverage includes a real builtin menu (vim.lsp.completion) selecting and confirming/cancelling items, a realClient:exec_cmdround trip, shared-client reuse/separation in both attach orders, error replies for unsupported requests, pum.vim/nvim-cmp selection, and theskkelua-pre-edit-restoredevent.🤖 Generated with Claude Code