diff --git a/TODO.md b/TODO.md index 2245597..e177ebe 100644 --- a/TODO.md +++ b/TODO.md @@ -63,7 +63,7 @@ Here is my feature wishlist. I don't expect to ever get all of this done, but th - [X] Unused locals - [X] Unknown fields of modules - [ ] Discarding results from pcall/xpcall/other functions - - [ ] `unpack` or `values` into a special + - [.] `unpack` or `values` into a special - [ ] `do`/`values` with only one inner form - [ ] redundant `do` as the last/only item in a form that accepts a "body" - [ ] `var` forms that could be `local` diff --git a/src/fennel-ls/formatter.fnl b/src/fennel-ls/formatter.fnl index 222c01d..2386507 100644 --- a/src/fennel-ls/formatter.fnl +++ b/src/fennel-ls/formatter.fnl @@ -99,9 +99,11 @@ fntype is one of fn or λ or lambda" (doto (case (analyze-fn def.definition) {:fntype _} {: label - :kind (if (label:find ":") kinds.Method kinds.Function)} + :kind (if (label:find ":") kinds.Method kinds.Function) + :textEdit {:newText label}} _ {: label - :kind kinds.Variable}) + :kind kinds.Variable + :textEdit {:newText label}}) (tset :documentation (hover-format def)))) {: hover-format diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index 5ac3d43..a6dacc3 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -128,10 +128,9 @@ Every time the client sends a message, it gets handled by a function in the corr :Constant 21 :Struct 22 :Event 23 :Operator 24 :TypeParameter 25}) (λ make-completion-item [self file name scope] - ;; TODO consider passing stop-early? (case (language.search-name-and-scope self file name scope) def (formatter.completion-item-format name def) - _ {:label name})) + _ {:label name :textEdit {:newText name}})) (λ scope-completion [self file byte ?symbol parents] (let [scope (or (accumulate [result nil @@ -142,7 +141,8 @@ Every time the client sends a message, it gets handled by a function in the corr ?parent (. parents 1) result [] in-call-position? (and ?parent (= ?symbol (. ?parent 1)))] - (collect-scope scope :manglings #(make-completion-item self file $ scope) result) + (collect-scope scope :manglings #(doto (make-completion-item self file $ scope) (tset :kind kinds.Variable)) result) + (when in-call-position? (collect-scope scope :macros #(doto (make-completion-item self file $ scope) (tset :kind kinds.Keyword)) result) (collect-scope scope :specials #(doto (make-completion-item self file $ scope) (tset :kind kinds.Operator)) result)) @@ -159,26 +159,40 @@ Every time the client sends a message, it gets handled by a function in the corr (case (values definition (type definition)) ;; fields of a string are hardcoded to "string" (_str :string) (icollect [label _ (pairs string)] - {: label :kind kinds.Field}) + {: label :kind kinds.Field :textEdit {:newText label}}) ;; fields of a table (tbl :table) (icollect [label _ (pairs tbl)] (if (= (type label) :string) (case (language.search-ast self file tbl [label] {}) def (formatter.completion-item-format label def) - _ {: label :kind kinds.Field})))) + _ {: label :kind kinds.Field :textEdit {:newText label}})))) _ nil)))) -(λ _create-completion-item [self file name scope] - (let [result (language.search-name-and-scope self file name scope)] - {:label result.label :kind result.kind})) - (λ requests.textDocument/completion [self send {: position :textDocument {: uri}}] (let [file (state.get-by-uri self uri) byte (utils.position->byte file.text position self.position-encoding) (?symbol parents) (language.find-symbol file.ast byte)] (case (-?> ?symbol utils.multi-sym-split) - (where (or nil [_ nil])) (scope-completion self file byte ?symbol parents) - [_a _b &as split] (field-completion self file ?symbol split)))) + + ;; completion from current scope + (where (or nil [_ nil])) + (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.range input-range))) + ?completions) + + ;; completion from field + [_a _b &as split] + (let [input-range (message.multisym->range self file ?symbol -1) + ?completions (field-completion self file ?symbol split input-range)] + (if ?completions + (each [_ completion (ipairs ?completions)] + (set completion.textEdit.range input-range))) + ?completions)))) + + (λ requests.textDocument/rename [self send {: position :textDocument {: uri} :newName new-name}] (let [file (state.get-by-uri self uri) diff --git a/src/fennel-ls/message.fnl b/src/fennel-ls/message.fnl index 90564fe..237ded9 100644 --- a/src/fennel-ls/message.fnl +++ b/src/fennel-ls/message.fnl @@ -67,7 +67,8 @@ to look to fix this in the future." self.position-encoding)})) (λ multisym->range [self file ast n] - (let [spl (utils.multi-sym-split ast)] + (let [spl (utils.multi-sym-split ast) + n (if (< n 0) (+ n 1 (length spl)) n)] (case (values (utils.get-ast-info ast :bytestart) (utils.get-ast-info ast :byteend)) (bytestart byteend) diff --git a/test/completion-test.fnl b/test/completion-test.fnl index 22c39c4..7b7f612 100644 --- a/test/completion-test.fnl +++ b/test/completion-test.fnl @@ -143,7 +143,8 @@ (where {:label :local :kind (= kinds.Operator) - :documentation documentation} + :documentation documentation + :textEdit {:range {:start {:line 0 :character 1} :end {:line 0 :character 1}}}} (not= documentation :nil))))) (it "offers rich information about builtin-macro completions" diff --git a/test/goto-definition-test.fnl b/test/goto-definition-test.fnl index c1794b5..9df47d6 100644 --- a/test/goto-definition-test.fnl +++ b/test/goto-definition-test.fnl @@ -109,7 +109,6 @@ (: :open-file! :foo.fnl "(local [x y] (values [1 2] [3 4]))\n(local (a b) (values {:x y : y} {: x : y}))\n(print b.x a)")) [find_b] (c:definition :foo.fnl 2 9)] ;; it finds the first `x` symbol - (print (view find_b)) (is.same find_b.result.range {:start {:line 0 :character 8} :end {:line 0 :character 9}}) nil)) diff --git a/test/misc-test.fnl b/test/misc-test.fnl index 5bcd35c..f4a670f 100644 --- a/test/misc-test.fnl +++ b/test/misc-test.fnl @@ -28,8 +28,6 @@ (is.same ["a" "b" "c" "d" "e" "f"] (utils.multi-sym-split "a.b.c.d.e.f")) (is.same ["obj" "bar"] (utils.multi-sym-split (fennel.sym "obj.bar"))))) -(describe "utf8") ;; TODO - (describe "find-symbol" (it "finds a symbol and parents" (let [state (doto (create-client)