From 2c47e61f2c6c86c745d9c9bcab295fb484b04267 Mon Sep 17 00:00:00 2001 From: XeroOl Date: Mon, 29 Aug 2022 10:10:09 -0500 Subject: [PATCH] Refactoring / comments --- src/fennel-ls/compiler.fnl | 27 ++++++++-------- src/fennel-ls/handlers.fnl | 66 ++++++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/fennel-ls/compiler.fnl b/src/fennel-ls/compiler.fnl index bb2ea73..3aee418 100644 --- a/src/fennel-ls/compiler.fnl +++ b/src/fennel-ls/compiler.fnl @@ -39,10 +39,11 @@ later by fennel-ls.language to answer requests from the client." "Compile the file, and record all the useful information from the compiler into the file object" ;; The useful information being recorded: (let [definitions-by-scope (doto {} (setmetatable has-tables-mt)) - definitions {} - diagnostics {} - references {} - require-calls {}] + definitions {} ; symbol -> definition + diagnostics {} ; [diagnostic] + references {} ; symbol -> references + scopes {} ; ast -> scope + require-calls {}]; ast -> boolean (does this ast start with the symbol `require) (λ find-definition [name ?scope] (when ?scope @@ -106,7 +107,7 @@ later by fennel-ls.language to answer requests from the client." (define-function-args ast scope)) (λ call [ast scope] - ;; handles every function call + (tset scopes ast scope) ;; Most calls aren't interesting, but here's the list of the ones that are: (match ast ;; This cannot be done through the :fn feature of the compiler plugin system @@ -114,10 +115,6 @@ later by fennel-ls.language to answer requests from the client." ;; TODO check if hashfn needs to be here [-fn-] (define-function ast scope) - [-λ-] - (define-function ast scope) - [-lambda-] - (define-function ast scope) [-require- modname] (tset require-calls ast true))) @@ -144,6 +141,8 @@ later by fennel-ls.language to answer requests from the client." :codeDescription "compiler error"})) (error "__NOT_AN_ERROR")) + (local allowed-globals (icollect [k v (pairs _G)] k)) + ;; TODO clean up this code. It's awful now that there is error handling (let [plugin @@ -157,7 +156,7 @@ later by fennel-ls.language to answer requests from the client." scope (fennel.scope) opts {:filename file.uri :plugins [plugin] - :allowedGlobals (icollect [k v (pairs _G)] k) + :allowedGlobals allowed-globals :requireAsInclude false : scope} parser (partial pcall (fennel.parser file.text file.uri opts)) @@ -168,14 +167,14 @@ later by fennel-ls.language to answer requests from the client." (table.insert diagnostics {:range (message.pos->range 0 0 0 0) :message err})))] - (set file.ast ast) ;; write things back to the file object - ;; (set file.definitions-by-scope definitions-by-scope) ;; not needed yet + (set file.ast ast) + (set file.scopes scopes) (set file.definitions definitions) (set file.diagnostics diagnostics) (set file.references references) - (set file.require-calls require-calls)))) - ;; (set file.compiled? true)) + (set file.require-calls require-calls) + (set file.allowed-globals allowed-globals)))) {: compile} diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index 3ad5062..01510b2 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -3,13 +3,14 @@ You finally made it. Here is the main code that implements the language server p Every time the client sends a message, it gets handled by a function in the corresponding table type. (ie, a textDocument/didChange notification will call notifications.textDocument/didChange - and a textDocument/defintion request will call requests.textDocument/didChange)" + and a textDocument/defintion request will call requests.textDocument/definition)" (local {: pos->byte : apply-changes} (require :fennel-ls.utils)) (local message (require :fennel-ls.message)) (local state (require :fennel-ls.state)) (local language (require :fennel-ls.language)) (local formatter (require :fennel-ls.formatter)) +(local utils (require :fennel-ls.utils)) (local {: view} (require :fennel)) @@ -19,8 +20,11 @@ Every time the client sends a message, it gets handled by a function in the corr (local capabilities {:textDocumentSync 1 ;; FIXME: upgrade to 2 ;; :notebookDocumentSync nil - ;; :completionProvider nil - :hoverProvider {:workDoneProgress false} + :completionProvider {:workDoneProgress false} ;; TODO + :hoverProvider {:workDoneProgress false + :resolveProvider false + :triggerCharacters ["(" "[" "{" "." ":" "\""] + :completionItem {:labelDetailsSupport false}} ;; :signatureHelpProvider nil ;; :declarationProvider nil :definitionProvider {:workDoneProgress false} @@ -63,29 +67,43 @@ Every time the client sends a message, it gets handled by a function in the corr :serverInfo {:name "fennel-ls" :version "0.0.0"}}) (λ requests.textDocument/definition [self send {: position :textDocument {: uri}}] - (local file (state.get-by-uri self uri)) - (local byte (pos->byte file.text position.line position.character)) - (match-try (language.find-symbol file.ast byte) - (symbol parents) - (match-try - (let [parent (. parents (length parents))] - (if (. file.require-calls parent) - (language.search self file parent []))) - nil - (language.search-main self file symbol)) - (result result-file) - (message.range-and-uri - (or result.binding result.?definition) - result-file) - (catch _ nil))) + (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 parents) + (match-try + (let [parent (. parents (length parents))] + (if (. file.require-calls parent) + (language.search self file parent []))) + nil + (language.search-main self file symbol)) + (result result-file) + (message.range-and-uri + (or result.binding result.?definition) + result-file) + (catch _ nil)))) (λ requests.textDocument/hover [self send {: position :textDocument {: uri}}] - (local file (state.get-by-uri self uri)) - (local byte (pos->byte file.text position.line position.character)) - (match-try (language.find-symbol file.ast byte) - symbol (language.search-main self file symbol) - result {:contents {:kind "markdown" - :value (formatter.hover-format result)}})) + (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) + result {:contents {:kind "markdown" + :value (formatter.hover-format result)}}))) + +(λ requests.textDocument/completion [self send {: position :textDocument {: uri}}] + (let [file (state.get-by-uri self uri) + byte (pos->byte file.text position.line position.character) + (?symbol parents) (language.find-symbol file.ast byte)] + ;; TODO build a recursive searcher, + ;; store file scopes parents length parents as an intermediate + ;; potentially reverse parents order so it's only (. parents 1) + (let [begin (if (?. file.scopes (. parents (length parents))) + (icollect [k (pairs (. file.scopes (. parents (length parents)) :manglings))] + {:label k}) + [])] + (icollect [_ k (ipairs file.allowed-globals) &into begin] {:label k})))) + (λ notifications.textDocument/didChange [self send {: contentChanges :textDocument {: uri}}] (local file (state.get-by-uri self uri))