diff --git a/TODO.md b/TODO.md index 149eaf8..2245597 100644 --- a/TODO.md +++ b/TODO.md @@ -2,8 +2,20 @@ ([X] = complete, [ ] = planned) My current goal is to work on completions a little bit more. +- [ ] create a release -- [ ] Fix crash-files.test2 +refactor brainstorm: +- [ ] get rid of `bytes` stuff and use "stack" everywhere +- [ ] search caching +- [ ] search depth limit / stop recursion +- [ ] search into calls + +- [ ] entry point measurement for reference search + +- [ ] arg return count + - [ ] i guess searching into calls could do this? + +- [ ] diagnostic code actions Here is my feature wishlist. I don't expect to ever get all of this done, but these are the sort of enhancements I am thinking about. - [X] Able to connect to a client @@ -36,7 +48,7 @@ Here is my feature wishlist. I don't expect to ever get all of this done, but th - [X] from macros (only on first form in a list) - [X] from specials (only on first form in a list) - [X] "dot completion" for table fields - - [ ] dot completion is aware of a stdlib + - [1/2] dot completion is aware of a stdlib - [ ] actually compliant rules about lexical scope (only see things declared before, not after) - [x] show docs/icons on each suggestion - [ ] "dot completion" for metatable `__index` fields diff --git a/src/fennel-ls/compiler.fnl b/src/fennel-ls/compiler.fnl index 8c80242..7d0c2e1 100644 --- a/src/fennel-ls/compiler.fnl +++ b/src/fennel-ls/compiler.fnl @@ -261,7 +261,11 @@ later by fennel-ls.language to answer requests from the client." (local allowed-globals (icollect [k _ (pairs _G)] k)) + + ;; just a couple of globals that are probably not errors + ;; TODO make this configurable in a better way (table.insert allowed-globals :vim) + (table.insert allowed-globals :love) ;; TODO clean up this code. It's awful now that there is error handling (let [macro-file? (= (: file.text :sub 1 24) ";; fennel-ls: macro-file") @@ -286,47 +290,35 @@ later by fennel-ls.language to answer requests from the client." :allowedGlobals allowed-globals :requireAsInclude false : scope} + filter-errors (fn _filter-errors [component ...] + (case ... + (true ?item1 ?item2) (values ?item1 ?item2) + (where (or (nil err) (false err)) (not (err:find "^[^\n]-__NOT_AN_ERROR\n"))) + (if (os.getenv :TESTING) + (error (.. "\nYou have crashed fennel-ls (or the fennel " component ") with the following message\n:" err + "\n\n^^^ the error message above here is the root problem\n\n")) + (table.insert diagnostics + {:range (line+byte->range self file 1 1) + :message (.. "unrecoverable " component " error: " err)})))) parser (let [p (fennel.parser file.text file.uri opts)] - ;; TODO factor this garbage out into a function - (fn p1 [p2 p3] - (case (xpcall #(p p2 p3) fennel.traceback) - (true r1 r2) (values r1 r2) - (where (or (nil err) (false err)) (not (err:find "^[^\n]-__NOT_AN_ERROR\n"))) - (if (os.getenv :TESTING) - (error (.. "\nYou have crashed the fennel parser or fennel-ls with the following message\n:" err - "\n\n^^^ the error message above here is the root problem\n\n")) - (table.insert diagnostics - {:range (line+byte->range self file 1 1) - :message (.. "unrecoverable compiler error: " err)}))))) + (fn _p1 [p2 p3] + (filter-errors :parser (xpcall #(p p2 p3) fennel.traceback)))) ast (icollect [ok ast parser &until (not ok)] ast)] ;; This is bad; we mutate fennel.macro-path (let [old-macro-path fennel.macro-path] - (set fennel.macro-path (searcher.add-workspaces-to-path macro-path [root-uri])) + (set fennel.macro-path + (searcher.add-workspaces-to-path macro-path [root-uri])) ;; compile (each [_i form (ipairs (if macro-file? (ast->macro-ast ast) ast))] - (case (xpcall #(fennel.compile form opts) fennel.traceback) - (where (or (nil err) (false err)) (not (err:find "^[^\n]-__NOT_AN_ERROR\n"))) - (if (os.getenv :TESTING) - (error (.. "\nYou have crashed the fennel compiler or fennel-ls with the following message\n:" err - "\n\n^^^ the error message above here is the root problem\n\n")) - (table.insert diagnostics - {:range (line+byte->range self file 1 1) - :message (.. "unrecoverable compiler error: " err)})))) + (filter-errors :compiler (xpcall #(fennel.compile form opts) fennel.traceback))) (set fennel.macro-path old-macro-path)) - ; (each [sym target (pairs references)] - ; (if - ; (sym? target) - ; (list? target) - ; (= :table (type target)))) - ; ;; base case??? - (set file.ast ast) (set file.calls calls) (set file.scope scope) diff --git a/src/fennel-ls/state.fnl b/src/fennel-ls/state.fnl index 0a7437f..c944af0 100644 --- a/src/fennel-ls/state.fnl +++ b/src/fennel-ls/state.fnl @@ -115,7 +115,6 @@ However, fennel-ls can fall back to positionEncoding=utf-16 (with a performance :utf-8 :utf-16))) - (λ init-state [self params] (set self.files {}) (set self.modules {}) diff --git a/test/completion-test.fnl b/test/completion-test.fnl index 16ae6af..1d31bec 100644 --- a/test/completion-test.fnl +++ b/test/completion-test.fnl @@ -156,26 +156,49 @@ {:label :-?> :kind (= kinds.Keyword) :documentation documentation} - (not= documentation :nil))))))) + (not= documentation :nil))))) - ; (it "offers rich information about everything" + (it "offers rich information about all builtin/globals" + (let [client (doto (create-client) + (: :open-file! filename "(")) + [{:result completions}] (client:completion filename 0 1) + _ (table.sort completions #(< $1.label $2.label)) + missing-docs (icollect [_ completion (ipairs completions)] + (if (not (and (= (type completion.label) :string) + (= (type completion.kind) :number) + (= (type completion.documentation) :table))) + completion.label)) + allowed-missing-docs {:lua true + :set-forcibly! true + ;; TODO remove these from fennel-ls when they become configurable + :love true + :vim true}] + (each [_ completion (ipairs completions)] + (when (not (. allowed-missing-docs completion.label)) + (is.same (type completion.label) :string "unlabeled completion") + (is.same (type completion.kind) :number (.. completion.label " needs a kind")) + (is.same (type completion.documentation) :table (.. completion.label " needs documentation")) + (is.not.same completion.documentation :nil (.. completion.label " needs documentation")))))))) + + ; (it "offers rich information about fields" ; (let [client (doto (create-client) - ; (: :open-file! filename "(")) - ; [{:result completions}] (client:completion filename 0 1) + ; (: :open-file! filename "(let [x (fn x [a b c] \"\"\"docstring\"\"\" nil)\n t {: x}]\n (t.")) + ; [{:result completions}] (client:completion filename 2 5) ; _ (table.sort completions #(< $1.label $2.label)) - ; count (accumulate [sum 0 _ completion (ipairs completions)] - ; (if (and (= (type completion.label) :string) - ; (= (type completion.kind) :number) - ; (= (type completion.documentation) :table)) - ; (+ sum 1) - ; sum))] - ; (if (< count (length completions)) - ; (print "!!!" (- (length completions) count) "items are missing a label or kind or doc")) + ; missing-docs (icollect [_ completion (ipairs completions)] + ; (if (not (and (= (type completion.label) :string) + ; (= (type completion.kind) :number) + ; (= (type completion.documentation) :table))) + ; completion.label)) + ; allowed-missing-docs {}] ; (each [_ completion (ipairs completions)] - ; (is.same (type completion.label) :string "unlabeled completion") - ; (is.same (type completion.kind) :number (.. completion.label " needs a kind")) - ; (is.same (type completion.documentation) :table (.. completion.label " needs documentation")) - ; (is.not.same completion.documentation :nil (.. completion.label " needs documentation"))))))) + ; (when (not (. allowed-missing-docs completion.label)) + ; (is.same (type completion.label) :string "unlabeled completion") + ; (is.same (type completion.kind) :number (.. completion.label " needs a kind")) + ; (is.same (type completion.documentation) :table (.. completion.label " needs documentation")) + ; (is.not.same completion.documentation :nil (.. completion.label " needs documentation")))))))) + + ;; (it "offers rich information about variable completions")