make the completion tests run faster

performance is starting to bother me, but I've made completions faster (in tests).
This commit is contained in:
XeroOl 2025-07-16 02:05:31 -05:00
parent 8811454456
commit 1c3d7fbe21
6 changed files with 122 additions and 117 deletions

View File

@ -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))

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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 []

View File

@ -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