From 2d7c8b1ad7bcb3e7447ec40857bfaf91d4e35e2c Mon Sep 17 00:00:00 2001 From: XeroOl Date: Sat, 4 May 2024 15:36:03 -0500 Subject: [PATCH] Lints for doc fields, doc hovers on strings --- src/fennel-ls/compiler.fnl | 9 ++++++--- src/fennel-ls/language.fnl | 21 +++++++++++---------- test/hover.fnl | 11 +++++++++++ test/lint.fnl | 5 ++++- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/fennel-ls/compiler.fnl b/src/fennel-ls/compiler.fnl index 367514c..f83e3d0 100644 --- a/src/fennel-ls/compiler.fnl +++ b/src/fennel-ls/compiler.fnl @@ -6,9 +6,10 @@ compiler's plugin hook callbacks. It stores lexical info about which identifiers are declared / referenced in which places." (local {: sym? : list? : sequence? : table? : sym : view &as fennel} (require :fennel)) +(local docs (require :fennel-ls.docs)) (local message (require :fennel-ls.message)) -(local utils (require :fennel-ls.utils)) (local searcher (require :fennel-ls.searcher)) +(local utils (require :fennel-ls.utils)) (fn scope? [candidate] ;; just checking a couple of the fields @@ -86,10 +87,12 @@ identifiers are declared / referenced in which places." (assert (scope? scope) :not-a-scope) ;; find reference (let [name (string.match (tostring symbol) "[^%.:]+")] - (case (find-definition (tostring name) scope) + (case (or (find-definition (tostring name) scope) + (docs.get-global-metadata name)) target (let [ref {: symbol : target : ref-type}] (tset references symbol ref) - (table.insert target.referenced-by ref))))) + (when target.referenced-by + (table.insert target.referenced-by ref)))))) (λ symbol-to-expression [ast scope ?reference?] (assert (sym? ast) "symbols only") diff --git a/src/fennel-ls/language.fnl b/src/fennel-ls/language.fnl index d884a65..263f572 100644 --- a/src/fennel-ls/language.fnl +++ b/src/fennel-ls/language.fnl @@ -65,6 +65,7 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find (stack-add-split! stack (utils.multi-sym-split symbol))) (λ search-document [self document stack opts] + (doto opts (tset :searched-through-require true)) (if (= 0 (length stack)) document (. document.fields (. stack (length stack))) @@ -90,23 +91,23 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find (search-assignment self file {:target (. ?fields (table.remove stack))} stack opts) (search-multival self file ?definition (stack-add-keys! stack ?keys) (or ?multival 1) opts)))) +(λ search-reference [self file ref stack opts] + (if ref.target.metadata + (search-document self ref.target stack opts) + ref.target.binding + (search-assignment self file ref stack opts))) + (λ search-symbol [self file symbol stack opts] (if (= (tostring symbol) :nil) (if (= 0 (length stack)) {:definition symbol : file} nil) (if (. file.references symbol) - (search-assignment self file (. file.references symbol) (stack-add-multisym! stack symbol) opts) - (let [parts (utils.multi-sym-split symbol)] - (case (docs.get-global-metadata (. parts 1)) - document (search-document self document (stack-add-split! stack parts) opts) - _ nil))))) + (search-reference self file (. file.references symbol) (stack-add-multisym! stack symbol) opts)))) (λ search-table [self file tbl stack opts] (if (. tbl (. stack (length stack))) (search-val self file (. tbl (table.remove stack)) stack opts) - (= 0 (length stack)) - {:definition tbl : file} ;; BASE CASE !! nil)) ;; BASE CASE Give up (λ search-list [self file call stack multival opts] @@ -151,8 +152,9 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find (varg? ast) nil ;; TODO function-args (= 1 multival) (if (sym? ast) (search-symbol self file ast stack opts) + (= 0 (length stack)) {:definition ast : file} ;; BASE CASE !! (= :table (type ast)) (search-table self file ast stack opts) - (= 0 (length stack)) {:definition ast : file}) ;; BASE CASE !! + (= :string (type ast)) (search-document self (docs.get-global-metadata :string) stack opts)) nil))) @@ -175,7 +177,7 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find (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) + ref (search-reference self file ref stack opts) _ (case (. file.definitions symbol) def (search-multival self file def.definition (stack-add-keys! stack def.keys) (or def.multival 1) opts))))))) @@ -260,6 +262,5 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find {: find-symbol : find-nearest-definition : search-main - : search-assignment : search-name-and-scope :search-ast search-val} diff --git a/test/hover.fnl b/test/hover.fnl index 0e3c14d..82baf2a 100644 --- a/test/hover.fnl +++ b/test/hover.fnl @@ -65,6 +65,16 @@ new message handler `msgh`.") (check "(table.inser|t [] :message" #($:find "```fnl\n(insert list ?pos value)\n```" 1 true)) nil) +(fn test-module [] + (check "coroutine.yie|ld" + "```fnl\n(yield ...)\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(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.") + (check "(local x :hello) + x.cha|r" + "```fnl\n(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.")) + + (fn test-functions [] (check "(fn my-function| [arg1 arg2 arg3] (print arg1 arg2 arg3))" @@ -124,6 +134,7 @@ new message handler `msgh`.") {: test-literals : test-builtins : test-globals + : test-module : test-functions : test-multisym : test-crash diff --git a/test/lint.fnl b/test/lint.fnl index c0176fc..e039550 100644 --- a/test/lint.fnl +++ b/test/lint.fnl @@ -88,7 +88,10 @@ "(local {: a : c &as guy} (require :the-guy-they-tell-you-not-to-worry-about)) (print guy.b guy.d)"} [{:code 302}] [{:code 302 :message "unknown module field: a"} - {:code 302 :message "unknown module field: b"}])) + {:code 302 :message "unknown module field: b"}]) + (check "table.insert2" + [{:code 302}] + [])) (fn test-unnecessary-colon [] (check "(let [x :haha] (: x :find :a))"