diff --git a/changelog.md b/changelog.md index d8b2057..8a1ade1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,17 @@ # Changelog +### Features +* Better results when syntax errors are present. + +### Bug Fixes +* Solved a case where there were duplicate completion candidates +* Special workaround for Eglot to be able to complete multisyms. + To be honest, this isn't even Eglot's fault; the LSP specification leaves it ambiguous + [Eglot's issue](https://github.com/joaotavora/eglot/issues/402) + [LSP's issue](https://github.com/microsoft/language-server-protocol/issues/648) + [fennel-mode can't fix it on their end](https://git.sr.ht/~technomancy/fennel-mode/commit/188ee04e86792cd4bce75d52b9603cc833b63b48) + + ## 0.1.2 ### Features diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index f7cb0eb..a3d8e8f 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -176,8 +176,9 @@ Every time the client sends a message, it gets handled by a function in the corr def (formatter.completion-item-format label def) _ {: label :kind kinds.Field}))))) {: metadata : fields} - (icollect [label info (pairs fields)] - (formatter.completion-item-format label info)) + (let [_metadata metadata] + (icollect [label info (pairs fields)] + (formatter.completion-item-format label info))) _ nil))) (λ requests.textDocument/completion [self send {: position :textDocument {: uri}}] @@ -191,9 +192,10 @@ Every time the client sends a message, it gets handled by a function in the corr (let [input-range (if ?symbol (message.multisym->range self file ?symbol -1) {:start position :end position}) ?completions (scope-completion self file byte ?symbol parents)] (if ?completions - (each [_ completion (ipairs ?completions)] - (set completion.textEdit {:newText completion.label :range input-range}))) - ?completions) + (let [?completions (utils.uniq-by ?completions #$.label)] + (each [_ completion (ipairs ?completions)] + (set completion.textEdit {:newText completion.label :range input-range})) + ?completions))) ;; completion from field [_a _b &as split] diff --git a/src/fennel-ls/utils.fnl b/src/fennel-ls/utils.fnl index 98d6a33..1de89d3 100644 --- a/src/fennel-ls/utils.fnl +++ b/src/fennel-ls/utils.fnl @@ -170,15 +170,15 @@ WARNING: this is only used in the test code, not in the real language server" (λ type= [val typ] (= (type val) typ)) -(λ uniq-by [list eq?] +(λ uniq-by [list key-fn] "I know the big O of this is bad, but we'll come back to it if it's a performance problem" - (let [result []] + (let [result [] + seen {}] (each [_ new-item (ipairs list)] - (if (not (accumulate [any? nil - _ seen-item (ipairs result) - &until any?] - (eq? seen-item new-item))) - (table.insert result new-item))) + (let [key (key-fn new-item)] + (when (not (. seen key)) + (tset seen key true) + (table.insert result new-item)))) result)) (λ split-spaces [str] diff --git a/test/completion.fnl b/test/completion.fnl index b975604..29545ba 100644 --- a/test/completion.fnl +++ b/test/completion.fnl @@ -54,18 +54,20 @@ "from: " (view file-contents) "\n" (view (. completions i) {:escape-newlines? true}))))) - (each [_ e (ipairs expected)] - (let [i (find completions e)] - (faith.is i (.. "Didn't get completion: " (view e) "\n" - "from: " (view file-contents) "\n" - (if (= (type e) :table) - (let [candidate (find completions {:label e.label})] - (if candidate - (.. "Candidate that didn't match:\n" - (view (. completions candidate) - {:escape-newlines? true})) - "")) - ""))))))) + (if (= (type expected) :table) + (each [_ e (ipairs expected)] + (let [i (find completions e)] + (faith.is i (.. "Didn't get completion: " (view e) "\n" + "from: " (view file-contents) "\n" + (if (= (type e) :table) + (let [candidate (find completions {:label e.label})] + (if candidate + (.. "Candidate that didn't match:\n" + (view (. completions candidate) + {:escape-newlines? true})) + "")) + ""))))) + (expected completions)))) (fn test-global [] ;; TODO shouldn't this kind be Function? @@ -103,6 +105,13 @@ bar 20 _ fo|" [:foo :bar] []) (check "(local x {:field 100})\n(if x.fi" [:field] []) + (check "(let [x 10] (let [x 10] x" + (fn [completions] + (faith.= 1 (accumulate [number-of-x 0 _ completion (ipairs completions)] + (if (= completion.label :x) + (+ number-of-x 1) + number-of-x)))) + []) nil) (fn test-builtin []