From 1c3d7fbe214d49731b9f0e19e7c890573e966b9a Mon Sep 17 00:00:00 2001 From: XeroOl Date: Wed, 16 Jul 2025 02:05:31 -0500 Subject: [PATCH] make the completion tests run faster performance is starting to bother me, but I've made completions faster (in tests). --- src/fennel-ls/completion.fnl | 33 ++----- src/fennel-ls/docs.fnl | 15 +++- src/fennel-ls/formatter.fnl | 11 +-- test/capabilities.fnl | 12 +-- test/completion.fnl | 166 +++++++++++++++++++---------------- test/utils/init.fnl | 2 +- 6 files changed, 122 insertions(+), 117 deletions(-) diff --git a/src/fennel-ls/completion.fnl b/src/fennel-ls/completion.fnl index 3dfa62e..26006c5 100644 --- a/src/fennel-ls/completion.fnl +++ b/src/fennel-ls/completion.fnl @@ -38,18 +38,6 @@ is set to true and we report that we support completionItem/resolve." (local compiler (require :fennel-ls.compiler)) (local {:metadata METADATA} (require :fennel.compiler)) -(local hardcoded-completions - {:nil {:metadata {:fnl/docstring "Represents the absence of a useful value." - :fls/itemKind "Keyword"}} - :true {:metadata {:fnl/docstring "A boolean value representing truth." - :fls/itemKind "Keyword"}} - :false {:metadata {:fnl/docstring "A boolean value representing falsehood." - :fls/itemKind "Keyword"}} - :.nan {:metadata {:fnl/docstring "NaN" - :fls/itemKind "Constant"}} - :.inf {:metadata {:fnl/docstring "inf" - :fls/itemKind "Constant"}}}) - (λ textDocument/completion [server _send {: position :textDocument {: uri}}] ;; get the file (let [file (files.get-by-uri server uri) @@ -80,7 +68,7 @@ is set to true and we report that we support completionItem/resolve." "add the completion. also recursively adds the fields' completions" (when (not (. seen definition)) (set (. seen definition) true) - (add-completion! name definition "Value") + (add-completion! name definition) (each [field def ?string-method (navigate.iter-fields server definition)] (if (or (= :self (tostring (?. def :metadata :fnl/arglist 1))) ?string-method @@ -97,11 +85,7 @@ is set to true and we report that we support completionItem/resolve." (set (. seen definition) false))) (fn expression-completions [] - (each [name documentation (pairs hardcoded-completions)] - (add-completion! name documentation)) - (local seen-manglings {}) - (each [_ global* (ipairs file.allowed-globals)] (when (not (. seen-manglings global*)) (set (. seen-manglings global*) true) @@ -156,14 +140,13 @@ is set to true and we report that we support completionItem/resolve." (fn completionItem/resolve [server _send completion-item] (let [result - (or (. hardcoded-completions completion-item.name) - (let [{: uri : byte} completion-item.data - file (files.get-by-uri server uri) - (_symbol parents) (analyzer.find-symbol file.ast byte) - scope (or (accumulate [?find nil _ parent (ipairs parents) &until ?find] - (. file.scopes parent)) - file.scope)] - (analyzer.search-name-and-scope server file completion-item.label scope)))] + (let [{: uri : byte} completion-item.data + file (files.get-by-uri server uri) + (_symbol parents) (analyzer.find-symbol file.ast byte) + scope (or (accumulate [?find nil _ parent (ipairs parents) &until ?find] + (. file.scopes parent)) + file.scope)] + (analyzer.search-name-and-scope server file completion-item.label scope))] (when result (set completion-item.documentation (format.hover-format server completion-item.label result))) completion-item)) diff --git a/src/fennel-ls/docs.fnl b/src/fennel-ls/docs.fnl index 6baee54..8239f7d 100644 --- a/src/fennel-ls/docs.fnl +++ b/src/fennel-ls/docs.fnl @@ -97,9 +97,22 @@ Handles grabbing the documentation from sources other than fennel code; (or (get-library-global server global-name) (. (get-lua-version server.configuration.lua-version) global-name))) +(local hardcoded-special-items + {:nil {:metadata {:fnl/docstring "Represents the absence of a useful value." + :fls/itemKind "Keyword"}} + :true {:metadata {:fnl/docstring "A boolean value representing truth." + :fls/itemKind "Keyword"}} + :false {:metadata {:fnl/docstring "A boolean value representing falsehood." + :fls/itemKind "Keyword"}} + :.nan {:metadata {:fnl/docstring "NaN" + :fls/itemKind "Constant"}} + :.inf {:metadata {:fnl/docstring "inf" + :fls/itemKind "Constant"}}}) + (fn get-builtin [_server builtin-name] (or (. specials builtin-name) - (. macros* builtin-name))) + (. macros* builtin-name) + (. hardcoded-special-items builtin-name))) (λ validate-lua-version [lua-version invalid] (case (. lua-versions lua-version) diff --git a/src/fennel-ls/formatter.fnl b/src/fennel-ls/formatter.fnl index 76a1fdb..926e730 100644 --- a/src/fennel-ls/formatter.fnl +++ b/src/fennel-ls/formatter.fnl @@ -193,14 +193,11 @@ fntype is one of fn or λ or lambda" {:label name :documentation (when (not server.can-do-good-completions?) (hover-format server name definition)) :textEdit (when (not server.can-do-good-completions?) {:newText name : range}) - :kind (or (if (not= ?kind :Value) (?. kinds ?kind)) + :kind (or (?. kinds ?kind) + (if (name:find ".:") kinds.Method) (case (navigate.getmetadata server definition) - metadata - (or (?. kinds metadata.fls/itemKind) - (when metadata.fnl/arglist - (if (name:find ":") kinds.Method kinds.Function)))) - (?. kinds ?kind) - kinds.Text)}) + metadata (?. kinds metadata.fls/itemKind)) + kinds.Value)}) {: signature-help-format : hover-format diff --git a/test/capabilities.fnl b/test/capabilities.fnl index daf01ec..20d0b6a 100644 --- a/test/capabilities.fnl +++ b/test/capabilities.fnl @@ -8,7 +8,7 @@ : encoding :locations [{:range {: start : end}}] : initialize-response} (create-client "(let [==𐐀𐐀== 100] 𐐀𐐀|)" - {:position-encodings [:utf-16] + {:capabilities {:general {:positionEncodings [:utf-16]}} :markup-encoding :utf-16}) [response] (client:definition uri cursor)] (faith.= :utf-16 encoding) @@ -23,8 +23,8 @@ : encoding :locations [{:range {: start : end}}] : initialize-response} (create-client "(let [==𐐀𐐀== 100] 𐐀𐐀|)" - {:position-encodings [:utf-8] - :markup-encoding :utf-8}) + {:capabilities {:general {:positionEncodings [:utf-8]}} + :markup-encoding :utf-8}) [response] (client:definition uri cursor)] (faith.= :utf-8 encoding) (faith.= :utf-8 (. initialize-response 1 :result :capabilities :positionEncoding)) @@ -33,13 +33,13 @@ (faith.= end response.result.range.end)) ;; utf-16 is the fallback - (let [{: initialize-response} (create-client "" {:position-encodings NIL})] + (let [{: initialize-response} (create-client "" {:capabilities {:general {}}})] (faith.= :utf-16 (. initialize-response 1 :result :capabilities :positionEncoding))) - (let [{: initialize-response} (create-client "" {:position-encodings [:some-unknown-encoding]})] + (let [{: initialize-response} (create-client "" {:capabilities {:general {:positionEncodings [:some-unknown-encoding]}}})] (faith.= :utf-16 (. initialize-response 1 :result :capabilities :positionEncoding))) - (let [{: initialize-response} (create-client "" {:position-encodings [:utf-8 :utf-16]})] + (let [{: initialize-response} (create-client "" {:capabilities {:general {:positionEncodings [:utf-8 :utf-16]}}})] (faith.= :utf-8 (. initialize-response 1 :result :capabilities :positionEncoding))) nil) diff --git a/test/completion.fnl b/test/completion.fnl index b0a6c49..d45ae91 100644 --- a/test/completion.fnl +++ b/test/completion.fnl @@ -9,62 +9,77 @@ :Snippet 15 :Color 16 :File 17 :Reference 18 :Folder 19 :EnumMember 20 :Constant 21 :Struct 22 :Event 23 :Operator 24 :TypeParameter 25}) -(fn find [completions e] - (accumulate [result nil - i c (ipairs completions) - &until result] - (if (or (and (= (type e) :string) - (= c.label e)) - (and (= (type e) :table) - (or (= e.label nil) - (and (= (type e.label) :string) (= e.label c.label)) - (and (= (type e.label) :function) (e.label c.label))) - (or (= e.kind nil) - (and (= (type e.kind) :number) (= e.kind c.kind)) - (and (= (type e.kind) :function) (e.kind c.kind))) - (or (= e.filterText nil) - (and (= (type e.filterText) :string) (= e.filterText c.filterText)) - (and (= (type e.filterText) :function) (e.filterText c.filterText))) - (or (= e.insertText nil) - (and (= (type e.insertText) :string) (= e.insertText c.insertText)) - (and (= (type e.insertText) :function) (e.insertText c.insertText))) - (or (= e.documentation nil) - (and (= (type e.documentation) :string) (= e.documentation c.documentation)) - (and (= (type e.documentation) :function) (e.documentation c.documentation)) - (and (= e.documentation true) (not= nil c.documentation))) - (or (= e.textEdit nil) - (and (= (type e.textEdit) :table) - (= e.textEdit.range.start.line c.textEdit.range.start.line) - (= e.textEdit.range.start.character c.textEdit.range.start.character) - (= e.textEdit.range.end.line c.textEdit.range.end.line) - (= e.textEdit.range.end.character c.textEdit.range.end.character) - (= e.textEdit.newText c.textEdit.newText)) - (and (= (type e.textEdit) :function) (e.textEdit c.textEdit))))) - i))) +(fn find [client params e] + (let [completions (or params.items params)] + (accumulate [result nil + i c (ipairs completions) + &until result] + (let [c (if params.itemDefaults + (collect [k v (pairs params.itemDefaults) &into (collect [k v (pairs c)] k v)] k v) + c)] + (if (or (and (= (type e) :string) + (= c.label e)) + (and (= (type e) :table) + (or (= e.label nil) + (and (= (type e.label) :string) (= e.label c.label)) + (and (= (type e.label) :function) (e.label c.label))) + (or (= e.kind nil) + (and (= (type e.kind) :number) (= e.kind c.kind)) + (and (= (type e.kind) :function) (e.kind c.kind))) + (or (= e.filterText nil) + (and (= (type e.filterText) :string) (= e.filterText c.filterText)) + (and (= (type e.filterText) :function) (e.filterText c.filterText))) + (or (= e.insertText nil) + (and (= (type e.insertText) :string) (= e.insertText c.insertText)) + (and (= (type e.insertText) :function) (e.insertText c.insertText))) + (or (= e.documentation nil) + (let [c (if params.items (-> (client:completion-item-resolve c) + (. 1 :result)) + c)] + (or + (and (= (type e.documentation) :string) (= e.documentation c.documentation)) + (and (= (type e.documentation) :function) (e.documentation c.documentation)) + (and (= e.documentation true) (not= nil c.documentation))))) + (or (= e.textEdit nil) + (let [c-textEdit (or c.textEdit {:range c.editRange :newText (or c.insertText c.label)})] + (and (= (type e.textEdit) :table) + (= e.textEdit.range.start.line c-textEdit.range.start.line) + (= e.textEdit.range.start.character c-textEdit.range.start.character) + (= e.textEdit.range.end.line c-textEdit.range.end.line) + (= e.textEdit.range.end.character c-textEdit.range.end.character) + (= e.textEdit.newText c-textEdit.newText))) + (and (= (type e.textEdit) :function) (e.textEdit c.textEdit))))) + i))))) -(fn check [file-contents expected unexpected ?client-opts] - (let [{: client : uri : cursor : text} (create-client file-contents ?client-opts) +(fn check [file-contents expected unexpected ?bad-completions?] + (let [{: client : uri : cursor : text} (create-client file-contents (if (not ?bad-completions?) + {:capabilities + {:textDocument + {:completion + {:completionList + {:itemDefaults + [:editRange :data]}}}}})) [{:result ?result}] (client:completion uri (or cursor (position-past-end-of-text text))) completions (or ?result [])] (each [_ e (ipairs unexpected)] - (let [i (find completions e)] + (let [i (find client completions e)] (faith.= nil i (.. "Got unexpected completion: " (view e) "\n" "from: " (view file-contents) "\n" - (view (. completions i) {:escape-newlines? true}))))) + (view (. (or completions.items completions) i) {:escape-newlines? true}))))) (if (= (type expected) :table) (each [_ e (ipairs expected)] - (let [i (find completions e)] + (let [i (find client 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})] + (let [candidate (find client completions {:label e.label})] (if candidate (.. "Candidate that didn't match:\n" - (view (. completions candidate) + (view (. (or completions.items completions) candidate) {:escape-newlines? true})) "")) ""))))) @@ -111,7 +126,7 @@ (check "(local x {:field 100})\n(if x.fi" [:x.field] []) (check "(let [x 10] (let [x 10] x" (fn [completions] - (faith.= 1 (accumulate [number-of-x 0 _ completion (ipairs completions)] + (faith.= 1 (accumulate [number-of-x 0 _ completion (ipairs completions.items)] (if (= completion.label :x) (+ number-of-x 1) number-of-x)))) @@ -185,37 +200,10 @@ nil) (fn test-docs [] - (check "(fn xyzzy [x y z] \"docstring\" nil)\n(xyzz" - [{:label :xyzzy :kind kinds.Function :documentation true}] - []) - ;; things that aren't present in lua5.4 but are in other versions, I guess?? (local things-that-are-allowed-to-have-missing-docs {:lua 1 :set-forcibly! 1}) ;:unpack 1 :setfenv 1 :getfenv 1 :module 1 :newproxy 1 :gcinfo 1 :loadstring 1 :bit 1 :jit 1 :bit32 1}) - (check "(" - [;; builtin specials - {:label :local - :kind kinds.Operator - :documentation true - :textEdit {:range {:start {:line 0 :character 1} - :end {:line 0 :character 1}} - :newText :local}} - ;; builtin macros - {:label :-?> - :kind kinds.Keyword - :documentation true} - ;; builtin globals - {:label :table - :kind kinds.Module - :documentation true} - {:label :_G - :kind kinds.Variable - :documentation true}] - [{:documentation #(= nil $) :label #(not (. things-that-are-allowed-to-have-missing-docs $))} - {:kind #(= nil $) :label #(not (. things-that-are-allowed-to-have-missing-docs $))} - {:label #(= nil $)}]) - (check "(let [x (fn x [a b c] \"docstring\" nil) @@ -226,16 +214,40 @@ {:kind #(= nil $)} {:label #(= nil $)}]) - (check "(let [x :hi] - (x:|))" - [:x:gsub - :x:match - :x:match - :x:sub - :x:len - :x:find] - [{:documentation #(= nil $)}]) - + (each [_ mode (ipairs [true false])] + (check "(fn x [a b c] + \"docstring\" + nil) + (let [str :hi] + (|))" + [;; builtin specials + {:label :local + :kind kinds.Operator + :documentation true} + ;; builtin macros + {:label :-?> + :kind kinds.Keyword + :documentation true} + ;; builtin globals + {:label :table + :kind kinds.Module + :documentation true} + {:label :_G + :kind kinds.Variable + :documentation true} + ;; method fields + {:label :str:gsub :kind kinds.Method :documentation true} + {:label :str:match :kind kinds.Method :documentation true} + {:label :str:match :kind kinds.Method :documentation true} + {:label :str:sub :kind kinds.Method :documentation true} + {:label :str:len :kind kinds.Method :documentation true} + {:label :str:find :kind kinds.Method :documentation true} + ;; things in scope + {:label :x :kind kinds.Function :documentation true}] + [{:documentation #(= nil $) :label #(not (. things-that-are-allowed-to-have-missing-docs $))} + {:kind #(= nil $) :label #(not (. things-that-are-allowed-to-have-missing-docs $))} + {:label #(= nil $)}] + mode)) nil) (fn test-module [] diff --git a/test/utils/init.fnl b/test/utils/init.fnl index 5266aa2..5b904d0 100644 --- a/test/utils/init.fnl +++ b/test/utils/init.fnl @@ -73,7 +73,7 @@ (icollect [_ range (ipairs ranges) &into highlights] {: range :kind 1})) - params {:capabilities {:general {:positionEncodings (un-nil (or opts.position-encodings [default-encoding]))}} + params {:capabilities (or opts.capabilities {:general {:positionEncodings [default-encoding]}}) :clientInfo (un-nil (or opts.client-info {:name "Neovim" :version "0.7.2"})) :initializationOptions opts.initialization-options :processId 16245