Finally, documentation for table.insert

This commit is contained in:
XeroOl 2024-03-02 20:12:27 -06:00
parent 308f7d9930
commit 0a766c6425
6 changed files with 1378 additions and 63 deletions

File diff suppressed because it is too large Load Diff

View File

@ -99,17 +99,17 @@ fntype is one of fn or λ or lambda"
:Snippet 15 :Color 16 :File 17 :Reference 18 :Folder 19 :EnumMember 20
:Constant 21 :Struct 22 :Event 23 :Operator 24 :TypeParameter 25})
(λ completion-item-format [label def]
(λ completion-item-format [label result]
"Makes a completion item"
(doto
(case (analyze-fn def.definition)
(case (analyze-fn result.definition)
{:fntype _} {: label
:kind (if (label:find ":") kinds.Method kinds.Function)
:textEdit {:newText label}}
_ {: label
:kind kinds.Variable
:textEdit {:newText label}})
(tset :documentation (hover-format def))))
(tset :documentation (hover-format result))))
{: hover-format
: completion-item-format}

View File

@ -78,7 +78,7 @@ Every time the client sends a message, it gets handled by a function in the corr
(. file.require-calls parent)
(language.search-ast self file parent [] {:stop-early? true})
;; regular symbol
(language.search-main self file symbol {:stop-early? true} byte))
(language.search-main self file symbol {:stop-early? true} {: byte}))
result
(if result.file
(message.range-and-uri self result.file (or result.binding result.definition)))
@ -107,7 +107,7 @@ Every time the client sends a message, it gets handled by a function in the corr
(let [file (state.get-by-uri self uri)
byte (utils.position->byte file.text position self.position-encoding)]
(case-try (language.find-symbol file.ast byte)
symbol (language.search-main self file symbol {} byte)
symbol (language.search-main self file symbol {} {: byte})
result {:contents (formatter.hover-format result)
:range (message.ast->range self file symbol)}
(catch _ nil))))
@ -153,31 +153,32 @@ Every time the client sends a message, it gets handled by a function in the corr
(make-completion-item self file k scope))))
(λ field-completion [self file symbol split]
(case (. file.references symbol)
ref
(let [stack (fcollect [i (- (length split) 1) 2 -1]
(. split i))
last-found-binding []]
(case (language.search-assignment self file ref stack {:save-last-binding last-found-binding})
{: definition : file}
(case (values definition (type definition))
;; fields of a string are hardcoded to "string"
(_str :string) (icollect [label _ (pairs string)]
{: label :kind kinds.Field :textEdit {:newText label}})
;; fields of a table
(tbl :table) (let [keys []]
(icollect [label _ (pairs tbl) &into keys]
label)
(when (?. last-found-binding 1 :fields)
(icollect [label _ (pairs (. last-found-binding 1 :fields)) &into keys]
label))
(icollect [_ label (pairs keys)]
(if (= (type label) :string)
(case (language.search-ast self file tbl [label] {})
def (formatter.completion-item-format label def)
_ {: label :kind kinds.Field :textEdit {:newText label}})))))
_ nil))))
(let [stack (fcollect [i (- (length split) 1) 2 -1]
(. split i))
last-found-binding []
result (language.search-main self file symbol {:save-last-binding last-found-binding} {: stack})]
(case result
{: definition : file}
(case (values definition (type definition))
;; fields of a string are hardcoded to "string"
(_str :string) (icollect [label _ (pairs string)]
{: label :kind kinds.Field :textEdit {:newText label}})
;; fields of a table
(tbl :table) (let [keys []]
(icollect [label _ (pairs tbl) &into keys]
label)
(when (?. last-found-binding 1 :fields)
(icollect [label _ (pairs (. last-found-binding 1 :fields)) &into keys]
label))
(icollect [_ label (pairs keys)]
(if (= (type label) :string)
(case (language.search-ast self file tbl [label] {})
def (formatter.completion-item-format label def)
_ {: label :kind kinds.Field :textEdit {:newText label}})))))
{: metadata : fields}
(icollect [label info (pairs fields)]
(formatter.completion-item-format label info))
_ nil)))
(λ requests.textDocument/completion [self send {: position :textDocument {: uri}}]
(let [file (state.get-by-uri self uri)

View File

@ -1,6 +1,7 @@
"Language
This module is for searching through the data provided by compiler.fnl. It
provides functions to search through a file.
This module is for searching through the data provided by compiler.fnl.
It searches through a file to find information about symbols that appear
in the file.
Imagine you have the following code.
```fnl
@ -23,18 +24,18 @@ The search failed, and encountered something that isn't implemented.
# A definition: `{:definition _ :file _}`
The search succeeded and found a file with a user definition of a value.
# A binding: `{:definition _ :file _ :binding _ :multival ?_ :keys ?_ :referenced-by ?_ :var? ?true :fields ?extra_fields}`
# A document: `{:metadata {:fnl/docstring _ :fnl/arglist ?_} :fields ?{<key> <document>}}`
A document is a definition that doesn't come from user code. For example,
searching `table.insert` will find a document, but that info does not come from
a user-written file.
# A binding (if opts.stop-early?): `{:definition _ :file _ :binding _ :multival ?_ :keys ?_ :referenced-by ?_ :var? ?true :fields ?extra_fields}`
If you set the option `opts.stop-early?`, search may stop at a binding instead
of a true definition. A binding is a place where an identifier gets introduced.
In the code example above, a search on the final symbol `z` would normally
find the definition `10`, but if `opts.stop-early?` is set, it would find
{:binding z :definition y}, referring to the `(local z y)` binding.
# A document: `{:metadata {:fnl/docstring _ :fnl/arglist ?_ :fnl-ls/fields ?_}}`
A document is a definition that doesn't come from user code. For example,
searching `table.insert` will find a document, but that info does not come from
a user-written file.
"
(local {: sym? : list? : sequence? : varg? : sym} (require :fennel))
@ -155,17 +156,24 @@ a user-written file.
nil)))
(λ search-main [self file symbol opts ?byte]
;; the options thing is getting out of hand
(λ search-main [self file symbol opts initialization-opts]
"Find the definition of a symbol"
(assert (= (type initialization-opts) :table))
;; The stack is the multi-sym parts still to search
;; for example, if I'm searching for "foo.bar.baz", my immediate priority is to find foo,
;; and the stack has ["baz" "bar"]. "bar" is at the "top"/"end" of the stack as the next key to search.
(if (sym? symbol)
(let [split (utils.multi-sym-split symbol (if ?byte (- ?byte symbol.bytestart)))
stack (stack-add-split! [] split)]
(let [stack
(if initialization-opts.stack
initialization-opts.stack
(let [?byte initialization-opts.byte
split (utils.multi-sym-split symbol (if ?byte (- ?byte symbol.bytestart)))]
(stack-add-split! [] split)))]
(case (docs.get-global-metadata (. split 1))
document (search-document self document (stack-add-split! stack split) opts)
(case (docs.get-global-metadata (utils.multi-sym-base symbol))
document (search-document self document stack opts)
_ (case (. file.references symbol)
ref (search-assignment self file ref stack opts)
_ (case (. file.definitions symbol)
@ -247,7 +255,7 @@ a user-written file.
(λ find-nearest-definition [self file symbol ?byte]
(if (. file.definitions symbol)
(. file.definitions symbol)
(search-main self file symbol {:stop-early? true} ?byte)))
(search-main self file symbol {:stop-early? true} {:byte ?byte})))
{: find-symbol
: find-nearest-definition

View File

@ -158,6 +158,15 @@ WARNING: this is only used in the test code, not in the real language server"
(icollect [word (: (.. symbol ".") :gmatch "(.-)[.:]")]
word))))
(fn multi-sym-base [symbol]
(if (or (= symbol ".")
(= symbol "..")
(= symbol "...")
(= symbol ":")
(= symbol "?."))
(tostring symbol)
(pick-values 1 (: (tostring symbol) :match "[^.:]*"))))
(λ type= [val typ]
(= (type val) typ))
@ -184,6 +193,7 @@ WARNING: this is only used in the test code, not in the real language server"
: apply-changes
: apply-edits
: multi-sym-split
: multi-sym-base
: get-ast-info
: uniq-by
: type=

View File

@ -191,6 +191,21 @@
nil)
(fn test-module []
(check "(coroutine.y|"
[{:label "yield"
:documentation #(and $.value ($.value:find "```fnl\n(yield ...)\n```" 1 true))}]
["coroutine" "_G" "do"
{:documentation #(= nil $)}])
(check "(local c coroutine)
(c.y"
[{:label "yield"}]
["coroutine" "_G" "do"])
(check "(local t table)
(t.i"
["insert"]
[{:documentation #(= nil $)}])
nil)
;; ;; Future tests / features
;; ;; Scope Ordering Rules
;; (it "does not suggest locals past the suggestion location when a symbol is partially typed")
@ -221,4 +236,5 @@
: test-local-in-macro
: test-fn-arg
: test-field
: test-docs}
: test-docs
: test-module}