diff --git a/src/fennel-ls.fnl b/src/fennel-ls.fnl index 20dbccb..6b3b61d 100644 --- a/src/fennel-ls.fnl +++ b/src/fennel-ls.fnl @@ -1,16 +1,11 @@ (local dispatch (require :fennel-ls.dispatch)) (local json-rpc (require :fennel-ls.json-rpc)) -(local log (io.open "/home/xerool/Documents/projects/fennel-ls/log.txt" "w")) -(local {: view} (require :fennel)) - (λ main-loop [in out] (local send (partial json-rpc.write out)) (local state []) (while true (let [msg (json-rpc.read in)] - (log:write (view msg) "\n") - (log:flush) (dispatch.handle state send msg)))) (λ main [] diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index 37105db..2585ab1 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -74,9 +74,9 @@ Every time the client sends a message, it gets handled by a function in the corr (match-try (let [parent (. parents 1)] (if (. file.require-calls parent) - (language.search self file parent []))) + (language.search self file parent [] {:stop-early? true}))) nil - (language.search-main self file symbol)) + (language.search-main self file symbol {:stop-early? true})) (result result-file) (message.range-and-uri (or result.binding result.definition) @@ -87,7 +87,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 (pos->byte file.text position.line position.character)] (match-try (language.find-symbol file.ast byte) - symbol (language.search-main self file symbol) + symbol (language.search-main self file symbol {}) result {:contents {:kind "markdown" :value (formatter.hover-format result)}}))) @@ -121,7 +121,7 @@ Every time the client sends a message, it gets handled by a function in the corr ref (let [stack (fcollect [i (- (length split) 1) 2 -1] (. split i))] - (match-try (language.search-assignment self file ref stack) + (match-try (language.search-assignment self file ref stack {}) {: definition} (match (values definition (type definition)) (str :string) (icollect [k v (pairs string)] diff --git a/src/fennel-ls/language.fnl b/src/fennel-ls/language.fnl index 1c4f817..96c8c32 100644 --- a/src/fennel-ls/language.fnl +++ b/src/fennel-ls/language.fnl @@ -13,62 +13,72 @@ the data provided by compiler.fnl." (local -dot- (sym :.)) (local -do- (sym :do)) (local -let- (sym :let)) +(local -fn- (sym :fn)) +(local -nil- (sym :nil)) (var search nil) ;; all of the search functions are mutually recursive -(λ search-assignment [self file {: binding :definition ?definition :keys ?keys &as assignment} - stack] - (if (= 0 (length stack)) - (values assignment file) ;; BASE CASE!! - (do - (if ?keys - (fcollect [i (length ?keys) 1 -1 &into stack] - (. ?keys i))) - (search self file ?definition stack)))) +(λ search-assignment [self file assignment stack opts] + (let [{: binding :definition ?definition :keys ?keys} assignment] + (if (and (= 0 (length stack)) opts.stop-early?) + (values assignment file) ;; BASE CASE!! + (do + (if ?keys + (fcollect [i (length ?keys) 1 -1 &into stack] + (. ?keys i))) + (search self file ?definition stack opts))))) -(λ search-symbol [self file symbol stack] - (match (. file.references symbol) - to (search-assignment self file to - (let [split (utils.multi-sym-split symbol)] - (fcollect [i (length split) 2 -1 &into stack] - (. split i)))))) ;; TODO test coverage for this line +(λ search-symbol [self file symbol stack opts] + (if (= symbol -nil-) + (values {:definition symbol} file) ;; BASE CASE !! + (match (. file.references symbol) + to (search-assignment self file to + (let [split (utils.multi-sym-split symbol)] + (fcollect [i (length split) 2 -1 &into stack] + (. split i))) ;; TODO test coverage for this line + opts)))) -(λ search-table [self file tbl stack] +(λ search-table [self file tbl stack opts] (if (. tbl (. stack (length stack))) - (search self file (. tbl (table.remove stack)) stack) + (search self file (. tbl (table.remove stack)) stack opts) (= 0 (length stack)) (values {:definition tbl} file) ;; BASE CASE !! nil)) ;; BASE CASE Give up -(λ search-list [self file call stack] +(λ search-list [self file call stack opts] (match call [-require- mod] (let [newfile (state.get-by-module self mod) newitem (. newfile.ast (length newfile.ast))] - (search self newfile newitem stack)) + (search self newfile newitem stack opts)) ; A . form indexes into item 1 with the other items [-dot- & split] (search self file (. split 1) (fcollect [i (length split) 2 -1 &into stack] - (. split i))) + (. split i)) + opts) ;; A do block returns the last form [-do- & body] - (search self file (. body (length body)) stack) + (search self file (. body (length body)) stack opts) [-let- _binding & body] - (search self file (. body (length body)) stack))) + (search self file (. body (length body)) stack opts) + + ;; functions evaluate to "themselves" + [-fn-] + (values {:definition call} file))) ;; BASE CASE !! (set search - (λ search [self file item stack] + (λ search [self file item stack opts] (if - (sym? item) (search-symbol self file item stack) - (list? item) (search-list self file item stack) - (= :table (type item)) (search-table self file item stack) + (sym? item) (search-symbol self file item stack opts) + (list? item) (search-list self file item stack opts) + (= :table (type item)) (search-table self file item stack opts) (= 0 (length stack)) {:definition item} ;; BASE CASE !! (error (.. "I don't know what to do with " (view item)))))) -(λ search-main [self file symbol] +(λ search-main [self file symbol opts] ;; TODO partial byting, go to different defitition sites depending on which section of the symbol the trigger happens on ;; The stack is the multi-sym parts still to search @@ -80,14 +90,13 @@ the data provided by compiler.fnl." (. split i)))) (match (values (. file.references symbol) (. file.definitions symbol)) (ref _) - (search-assignment self file ref stack) + (search-assignment self file ref stack opts) (_ def) (do (if def.keys (fcollect [i (length def.keys) 1 -1 &into stack] (. def.keys i))) - (search self file def.definition stack)))) - ;; (search self file def.definition stack)))) + (search self file def.definition stack opts)))) (λ past? [?ast byte] ;; check if a byte is past an ast object diff --git a/test/completion-test.fnl b/test/completion-test.fnl index e4df905..d8b9700 100644 --- a/test/completion-test.fnl +++ b/test/completion-test.fnl @@ -93,6 +93,13 @@ "(let [my-table {:foo 10 :bar 20}]\n my-table.)))" 1 11 [:foo :bar] + [:_G :local :doto :1])) ;; no globals, specials, macros, or others + + (it "suggests fields of tables indirectly" + (check-completion + "(let [foo (require :foo)]\n foo.)))" + 1 6 + [:my-export :constant] [:_G :local :doto :1]))) ;; no globals, specials, macros, or others ;; (it "suggests fields of strings"))