diff --git a/src/fennel-ls/analyzer.fnl b/src/fennel-ls/analyzer.fnl index b048359..89fabac 100644 --- a/src/fennel-ls/analyzer.fnl +++ b/src/fennel-ls/analyzer.fnl @@ -274,12 +274,11 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find (fcollect [i 1 (length parents)] (. parents (- (length parents) i -1))))) -(λ find-nearest-call [server file position] +(λ find-nearest-call [_server file byte] "Find the nearest call returns the called symbol and the argument number position points to" - (let [byte (utils.position->byte file.text position server.position-encoding) - (_ [[call] [parent]]) (find-symbol file.ast byte)] + (let [(_ [[call] [parent]]) (find-symbol file.ast byte)] (if (special? parent) (values parent -1) (values call -1)))) diff --git a/src/fennel-ls/formatter.fnl b/src/fennel-ls/formatter.fnl index 0eb2b96..9f82860 100644 --- a/src/fennel-ls/formatter.fnl +++ b/src/fennel-ls/formatter.fnl @@ -11,34 +11,27 @@ user code. Fennel-ls doesn't support user-code formatting as of now." (λ render-arg [arg] (case (type arg) - :table (view arg {:one-line? true - :prefer-colon? true}) + :table (: (view arg {:one-line? true + :prefer-colon? true}) + ;; transform {:key key} to {: key} + :gsub ":([%w?_-]+) ([%w?]+)([ }])" + #(if (= $1 $2) + (.. ": " $2 $3))) _ (tostring arg))) -(λ fn-signature-format [name args] +(fn fn-signature-format [special name args] (let [args (case (type (?. args 1)) :table (icollect [_ v (ipairs args)] (render-arg v)) _ args)] (.. "(" - (tostring name) " " + (tostring (or name special)) " " (table.concat args " ") ")"))) (fn fn-format [special name args docstring] - (.. (code-block (.. "(" - (tostring special) - (if name (.. " " (tostring name)) "") - (.. " " - (: (view args - {:empty-as-sequence? true - :one-line? true - :prefer-colon? true}) - :gsub ":([%w?_-]+) ([%w?]+)([ }])" - #(if (= $1 $2) - (.. ": " $2 $3)))) - " ...)")) - (if docstring (.. "\n" docstring) ""))) + (.. (code-block (fn-signature-format special name args)) + (if docstring (.. "\n---\n" docstring) ""))) (fn metadata-format [{: binding : metadata}] "formats a special using its builtin metadata magic" @@ -49,7 +42,7 @@ user code. Fennel-ls doesn't support user-code formatting as of now." (= 0 (length metadata.fnl/arglist)) (.. "(" (tostring binding) ")") (.. "(" (tostring binding) " " (table.concat metadata.fnl/arglist " ") ")"))) - "\n" + "\n---\n" (or metadata.fnl/docstring ""))) (λ fn? [symbol] @@ -99,15 +92,15 @@ fntype is one of fn or λ or lambda" symbol can be an actual ast symbol or a binding object from a docset" (case (analyze-fn symbol.definition) - {:name ?name :arglist ?arglist :docstring ?docstring} - {:label (fn-signature-format ?name ?arglist) + {:fntype ?fntype :name ?name :arglist ?arglist :docstring ?docstring} + {:label (fn-signature-format ?fntype ?name ?arglist) :documentation ?docstring :parameters (if ?arglist (icollect [_ arg (ipairs ?arglist)] {:label (render-arg arg)}))} _ (case symbol {: binding :metadata {:fnl/arglist arglist :fnl/docstring docstring}} - {:label (fn-signature-format binding arglist) + {:label (fn-signature-format :fn binding arglist) :documentation docstring} _ {:label (.. "ERROR: don't know how to format " (tostring symbol)) :documentation (code-block diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index b8bc15f..b64513f 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -140,8 +140,9 @@ Every time the client sends a message, it gets handled by a function in the corr (λ requests.textDocument/signatureHelp [server _send {:textDocument {: uri} : position}] - (let [file (files.get-by-uri server uri)] - (case-try (analyzer.find-nearest-call server file position) + (let [file (files.get-by-uri server uri) + byte (utils.position->byte file.text position server.position-encoding)] + (case-try (analyzer.find-nearest-call server file byte) (symbol active-parameter) (analyzer.find-nearest-definition server file symbol) {:indeterminate nil &as result} diff --git a/test/hover.fnl b/test/hover.fnl index 48b84cb..69fdea8 100644 --- a/test/hover.fnl +++ b/test/hover.fnl @@ -33,13 +33,14 @@ nil) (fn test-builtins [] - (check "(d|o nil)" "```fnl\n(do ...)\n```\nEvaluate multiple forms; return last value.") - (check "(|doto nil (print))" "```fnl\n(doto val ...)\n```\nEvaluate val and splice it into the first argument of subsequent forms.") - (check "(le|t [x 10] 10)" "```fnl\n(let [name1 val1 ... nameN valN] ...)\n```\nIntroduces a new scope in which a given set of local bindings are used.") + (check "(d|o nil)" "```fnl\n(do ...)\n```\n---\nEvaluate multiple forms; return last value.") + (check "(|doto nil (print))" "```fnl\n(doto val ...)\n```\n---\nEvaluate val and splice it into the first argument of subsequent forms.") + (check "(le|t [x 10] 10)" "```fnl\n(let [name1 val1 ... nameN valN] ...)\n```\n---\nIntroduces a new scope in which a given set of local bindings are used.") nil) (fn test-globals [] (check "(pri|nt :hello :world)" "```fnl\n(print ...)\n``` +--- Receives any number of arguments and prints their values to `stdout`, converting each argument to a string @@ -51,6 +52,7 @@ for instance for debugging. For complete control over the output, use `string.format` and `io.write`.") (check "(local x print) (x| :hello :world)" "```fnl\n(print ...)\n``` +--- Receives any number of arguments and prints their values to `stdout`, converting each argument to a string @@ -64,6 +66,7 @@ use `string.format` and `io.write`.") (check "(xpca|ll io.open debug.traceback :filename.txt)" "```fnl (xpcall f msgh ?arg1 ...) ``` +--- This function is similar to `pcall`, except that it sets a new message handler `msgh`.") (check "(table.inser|t [] :message" #($:find "```fnl\n(table.insert list value)\n```" 1 true)) @@ -71,43 +74,43 @@ except that it sets a new message handler `msgh`.") (fn test-module [] (check "coroutine.yie|ld" - "```fnl\n(coroutine.yield ...)\n```\nSuspends the execution of the calling coroutine.\nAny arguments to `yield` are passed as extra results to `resume`.") + "```fnl\n(coroutine.yield ...)\n```\n---\nSuspends the execution of the calling coroutine.\nAny arguments to `yield` are passed as extra results to `resume`.") (check "string.cha|r" - "```fnl\n(string.char ...)\n```\nReceives zero or more integers.\nReturns a string with length equal to the number of arguments,\nin which each character has the internal numeric code equal\nto its corresponding argument.\n\nNumeric codes are not necessarily portable across platforms.") + "```fnl\n(string.char ...)\n```\n---\nReceives zero or more integers.\nReturns a string with length equal to the number of arguments,\nin which each character has the internal numeric code equal\nto its corresponding argument.\n\nNumeric codes are not necessarily portable across platforms.") (check "(local x :hello) x.cha|r" - "```fnl\n(string.char ...)\n```\nReceives zero or more integers.\nReturns a string with length equal to the number of arguments,\nin which each character has the internal numeric code equal\nto its corresponding argument.\n\nNumeric codes are not necessarily portable across platforms.")) + "```fnl\n(string.char ...)\n```\n---\nReceives zero or more integers.\nReturns a string with length equal to the number of arguments,\nin which each character has the internal numeric code equal\nto its corresponding argument.\n\nNumeric codes are not necessarily portable across platforms.")) (fn test-functions [] (check "(fn my-function| [arg1 arg2 arg3] (print arg1 arg2 arg3))" - "```fnl\n(fn my-function [arg1 arg2 arg3] ...)\n```") + "```fnl\n(my-function arg1 arg2 arg3)\n```") (check "(fn my-function| [arg1 arg2 arg3] \"this is a doc string\" (print arg1 arg2 arg3))" - "```fnl\n(fn my-function [arg1 arg2 arg3] ...)\n```\nthis is a doc string") + "```fnl\n(my-function arg1 arg2 arg3)\n```\n---\nthis is a doc string") (check "(fn my-function [arg1 arg2 arg3] \"this is a doc string\" (print arg1 arg2 arg3)) (|my-function)" - "```fnl\n(fn my-function [arg1 arg2 arg3] ...)\n```\nthis is a doc string") + "```fnl\n(my-function arg1 arg2 arg3)\n```\n---\nthis is a doc string") (check "(fn my-function [arg1 arg2 arg3] \"this is a doc string\" (print arg1 arg2 arg3)) (my-function)|" nil) (check "(fn foo| [x ...] \"not a docstring, this gets returned\")" - "```fnl\n(fn foo [x ...] ...)\n```") + "```fnl\n(foo x ...)\n```") (check "(λ foo| [x ...] \"not a docstring, this gets returned\")" - "```fnl\n(λ foo [x ...] ...)\n```") + "```fnl\n(foo x ...)\n```") (check "(λ foo| [{: start : end}] :body)" - "```fnl\n(λ foo [{: end : start}] ...)\n```") + "```fnl\n(foo {: end : start})\n```") (check "(λ foo| [{:list [a b c] :table {: d : e : f}}] :body)" - "```fnl\n(λ foo [{:list [a b c] :table {: d : e : f}}] ...)\n```") + "```fnl\n(foo {:list [a b c] :table {: d : e : f}})\n```") nil) (fn test-multisym [] @@ -150,7 +153,7 @@ except that it sets a new message handler `msgh`.") \"docstring!\" `(,a ,b ,c)) (fo|o print :hello :world)" - "```fnl\n(foo a b c)\n```\ndocstring!") + "```fnl\n(foo a b c)\n```\n---\ndocstring!") ; (check {:main.fnl "(import-macros cool :cool) ; (coo|l.=)" ; :cool.fnl ";; fennel-ls: macro-file