From 0b3d1b47a5d58ccd6784d8e5d9ecbca997b11ebe Mon Sep 17 00:00:00 2001 From: XeroOl Date: Sat, 1 Jun 2024 23:02:37 -0500 Subject: [PATCH] Rename self->server --- src/fennel-ls/compiler.fnl | 20 +++--- src/fennel-ls/dispatch.fnl | 28 ++++---- src/fennel-ls/docs.fnl | 14 ++-- src/fennel-ls/handlers.fnl | 128 ++++++++++++++++++------------------- src/fennel-ls/language.fnl | 80 +++++++++++------------ src/fennel-ls/lint.fnl | 58 ++++++++--------- src/fennel-ls/message.fnl | 16 ++--- src/fennel-ls/searcher.fnl | 8 +-- src/fennel-ls/state.fnl | 67 ++++++++++--------- 9 files changed, 209 insertions(+), 210 deletions(-) diff --git a/src/fennel-ls/compiler.fnl b/src/fennel-ls/compiler.fnl index 3ad3811..462c296 100644 --- a/src/fennel-ls/compiler.fnl +++ b/src/fennel-ls/compiler.fnl @@ -46,16 +46,16 @@ identifiers are declared / referenced in which places." (tset self key val) val))}) -(λ line+byte->range [self file line byte] +(λ line+byte->range [server file line byte] (let [line (- line 1) ;; some errors in fennel erroneously say column -1 ;; try compiling "(do\n" to see what I mean byte (math.max 0 byte) - position (utils.pos->position file.text line byte self.position-encoding)] + position (utils.pos->position file.text line byte server.position-encoding)] {:start position :end position})) -(λ compile [{:configuration {: macro-path} :root-uri ?root-uri &as self} file] +(λ compile [{:configuration {: macro-path} :root-uri ?root-uri &as server} file] "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)) @@ -79,7 +79,7 @@ identifiers are declared / referenced in which places." ;; find reference (let [name (string.match (tostring symbol) "[^%.:]+")] (case (or (find-definition (tostring name) scope) - (docs.get-global self name)) + (docs.get-global server name)) target (let [ref {: symbol : target : ref-type}] (tset references symbol ref) (when target.referenced-by @@ -264,8 +264,8 @@ identifiers are declared / referenced in which places." true)))) (λ on-compile-error [_ msg ast call-me-to-reset-the-compiler] - (let [range (or (message.ast->range self file ast) - (line+byte->range self file 1 1))] + (let [range (or (message.ast->range server file ast) + (line+byte->range server file 1 1))] (table.insert diagnostics {:range range :message msg @@ -280,7 +280,7 @@ identifiers are declared / referenced in which places." (λ on-parse-error [msg filename line byte _source call-me-to-reset-the-compiler] (let [line (if (= line "?") 1 line) - range (line+byte->range self file line byte)] + range (line+byte->range server file line byte)] (table.insert diagnostics {:range range :message msg @@ -293,8 +293,8 @@ identifiers are declared / referenced in which places." (call-me-to-reset-the-compiler) (error "__NOT_AN_ERROR")))) - (local allowed-globals (docs.get-all-globals self)) - (each [_ v (ipairs (utils.split-spaces self.configuration.extra-globals))] + (local allowed-globals (docs.get-all-globals server)) + (each [_ v (ipairs (utils.split-spaces server.configuration.extra-globals))] (table.insert allowed-globals v)) ;; TODO clean up this code. It's awful now that there is error handling @@ -329,7 +329,7 @@ identifiers are declared / referenced in which places." (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) + {:range (line+byte->range server file 1 1) :message (.. "unrecoverable " component " error: " err)})))) parser (let [p (fennel.parser file.text file.uri opts)] diff --git a/src/fennel-ls/dispatch.fnl b/src/fennel-ls/dispatch.fnl index 9531e9c..42ab31e 100644 --- a/src/fennel-ls/dispatch.fnl +++ b/src/fennel-ls/dispatch.fnl @@ -10,12 +10,12 @@ In general, this involves: (local handlers (require :fennel-ls.handlers)) (local message (require :fennel-ls.message)) -(λ handle-request [self send id method ?params] +(λ handle-request [server send id method ?params] ;; Call the appropriate request handler. ;; The return value of the request is sent back to the server. (case (. handlers.requests method) callback - (case (callback self send ?params) + (case (callback server send ?params) (nil err) (send (message.create-error :InternalError err id)) ?response (send (message.create-response id ?response))) nil @@ -25,47 +25,47 @@ In general, this involves: (.. "\"" method "\" is not in the request-handlers table") id)))) -(λ handle-response [self send id result] +(λ handle-response [server send id result] ;; I don't care about responses yet nil) -(λ handle-bad-response [self send id err] +(λ handle-bad-response [server send id err] ;; Handle a message indicating an error. Right now, it just crashes the server. (error (.. "Client sent fennel-ls an error: " err.code))) -(λ handle-notification [self send method ?params] +(λ handle-notification [server send method ?params] ;; Call the appropriate notification handler. (case (. handlers.notifications method) - callback (callback self send ?params))) + callback (callback server send ?params))) ;; Silent error for unknown notifications -(λ handle [self send msg] +(λ handle [server send msg] "Figures out what to do with a message. This can involve updating the state of the server, and/or sending messages to the server. Takes: -* `self`, which is the state of the server, +* `server`, which is the state of the server, * `send`, which is a callback for sending responses, and * `msg`, which is the message to receive." (case (values msg (type msg)) {:jsonrpc "2.0" : id : method :params ?params} - (handle-request self send id method ?params) + (handle-request server send id method ?params) {:jsonrpc "2.0" : method :params ?params} - (handle-notification self send method ?params) + (handle-notification server send method ?params) {:jsonrpc "2.0" : id : result} - (handle-response self send id result) + (handle-response server send id result) {:jsonrpc "2.0" : id :error err} - (handle-bad-response self send id err) + (handle-bad-response server send id err) (str :string) (send (message.create-error :ParseError str)) _ (send (message.create-error :BadMessage nil msg.id)))) -(λ handle* [self msg] +(λ handle* [server msg] "handles a message, and returns all the responses in a table" (let [out []] - (handle self (partial table.insert out) msg) + (handle server (partial table.insert out) msg) out)) {: handle diff --git a/src/fennel-ls/docs.fnl b/src/fennel-ls/docs.fnl index 8ede7a2..0a7e966 100644 --- a/src/fennel-ls/docs.fnl +++ b/src/fennel-ls/docs.fnl @@ -35,25 +35,25 @@ (fennel.view (doto (icollect [key (pairs libraries)] key) table.sort))))) (. libraries library)) -(fn get-all-globals [self] +(fn get-all-globals [server] (let [result []] - (each [_ library (ipairs self.configuration.native-libraries)] + (each [_ library (ipairs server.configuration.native-libraries)] (icollect [name (pairs (get-native-library library)) &into result] name)) - (icollect [name (pairs (get-lua-version self.configuration.version)) &into result] + (icollect [name (pairs (get-lua-version server.configuration.version)) &into result] name))) -(fn get-global [self global-name] +(fn get-global [server global-name] (or (accumulate [result nil - _ library (ipairs self.configuration.native-libraries) + _ library (ipairs server.configuration.native-libraries) &until result] (. (get-native-library library) global-name)) - (. (get-lua-version self.configuration.version) + (. (get-lua-version server.configuration.version) global-name))) -(fn get-builtin [_self builtin-name] +(fn get-builtin [_server builtin-name] (or (. specials builtin-name) (. macros* builtin-name))) diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index 60801f1..92b369d 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -17,10 +17,10 @@ Every time the client sends a message, it gets handled by a function in the corr (local requests []) (local notifications []) -(λ requests.initialize [self send params] - (state.init-state self params) +(λ requests.initialize [server send params] + (state.init-state server params) (let [capabilities - {:positionEncoding self.position-encoding + {:positionEncoding server.position-encoding :textDocumentSync {:openClose true :change 2} ;; :notebookDocumentSync nil :completionProvider {:workDoneProgress false @@ -68,48 +68,48 @@ Every time the client sends a message, it gets handled by a function in the corr {: capabilities :serverInfo {:name "fennel-ls" :version "0.1.0"}})) -(λ requests.textDocument/definition [self send {: position :textDocument {: uri}}] - (let [file (state.get-by-uri self uri) - byte (utils.position->byte file.text position self.position-encoding)] +(λ requests.textDocument/definition [server send {: position :textDocument {: uri}}] + (let [file (state.get-by-uri server uri) + byte (utils.position->byte file.text position server.position-encoding)] (case-try (language.find-symbol file.ast byte) (symbol [parent]) (if ;; require call (. file.require-calls parent) - (language.search-ast self file parent [] {:stop-early? true}) + (language.search-ast server file parent [] {:stop-early? true}) ;; regular symbol - (language.search-main self file symbol {:stop-early? true} {: byte})) + (language.search-main server file symbol {:stop-early? true} {: byte})) result (if result.file - (message.range-and-uri self result.file (or result.binding result.definition))) + (message.range-and-uri server result.file (or result.binding result.definition))) (catch _ nil)))) -(λ requests.textDocument/references [self send {: position - :textDocument {: uri} - :context {:includeDeclaration ?include-declaration?}}] - (let [file (state.get-by-uri self uri) - byte (utils.position->byte file.text position self.position-encoding)] +(λ requests.textDocument/references [server send {: position + :textDocument {: uri} + :context {:includeDeclaration ?include-declaration?}}] + (let [file (state.get-by-uri server uri) + byte (utils.position->byte file.text position server.position-encoding)] (case-try (language.find-symbol file.ast byte) symbol - (language.find-nearest-definition self file symbol byte) + (language.find-nearest-definition server file symbol byte) (where definition (not= definition.referenced-by nil)) (let [result (icollect [_ {: symbol} (ipairs definition.referenced-by)] - (message.range-and-uri self definition.file symbol))] + (message.range-and-uri server definition.file symbol))] (if ?include-declaration? (table.insert result - (message.range-and-uri self definition.file definition.binding))) + (message.range-and-uri server definition.file definition.binding))) ;; TODO don't include duplicates result) (catch _ nil)))) -(λ requests.textDocument/hover [self send {: position :textDocument {: uri}}] - (let [file (state.get-by-uri self uri) - byte (utils.position->byte file.text position self.position-encoding)] +(λ requests.textDocument/hover [server send {: position :textDocument {: uri}}] + (let [file (state.get-by-uri server uri) + byte (utils.position->byte file.text position server.position-encoding)] (case-try (language.find-symbol file.ast byte) - symbol (language.search-main self file symbol {} {: byte}) + symbol (language.search-main server file symbol {} {: byte}) result {:contents (formatter.hover-format result) - :range (message.ast->range self file symbol)} + :range (message.ast->range server file symbol)} (catch _ nil)))) ;; All of the helper functions for textDocument/completion are here until I @@ -130,12 +130,12 @@ Every time the client sends a message, it gets handled by a function in the corr :Snippet 15 :Color 16 :File 17 :Reference 18 :Folder 19 :EnumMember 20 :Constant 21 :Struct 22 :Event 23 :Operator 24 :TypeParameter 25}) -(λ make-completion-item [self file name scope] - (case (language.search-name-and-scope self file name scope) +(λ make-completion-item [server file name scope] + (case (language.search-name-and-scope server file name scope) def (formatter.completion-item-format name def) _ {:label name})) -(λ scope-completion [self file byte ?symbol parents] +(λ scope-completion [server file byte ?symbol parents] (let [scope (or (accumulate [result nil _ parent (ipairs parents) &until result] @@ -145,24 +145,24 @@ Every time the client sends a message, it gets handled by a function in the corr result [] in-call-position? (and (fennel.list? ?parent) (= ?symbol (. ?parent 1)))] - (collect-scope scope :manglings #(doto (make-completion-item self file $ scope) (tset :kind kinds.Variable)) result) + (collect-scope scope :manglings #(doto (make-completion-item server file $ scope) (tset :kind kinds.Variable)) result) (when in-call-position? - (collect-scope scope :macros #(doto (make-completion-item self file $ scope) (tset :kind kinds.Keyword)) result) - (collect-scope scope :specials #(doto (make-completion-item self file $ scope) (tset :kind kinds.Operator)) result)) + (collect-scope scope :macros #(doto (make-completion-item server file $ scope) (tset :kind kinds.Keyword)) result) + (collect-scope scope :specials #(doto (make-completion-item server file $ scope) (tset :kind kinds.Operator)) result)) (icollect [_ k (ipairs file.allowed-globals) &into result] - (make-completion-item self file k scope)))) + (make-completion-item server file k scope)))) -(λ field-completion [self file symbol split] +(λ field-completion [server file symbol split] (let [stack (fcollect [i (- (length split) 1) 2 -1] (. split i)) last-found-binding [] - result (language.search-main self file symbol {:save-last-binding last-found-binding} {: stack})] + result (language.search-main server file symbol {:save-last-binding last-found-binding} {: stack})] (case result {: definition : file} (case (values definition (type definition)) ;; fields of a string are hardcoded to "string" - (_str :string) (icollect [label info (pairs (. (docs.get-global self :string) :fields))] + (_str :string) (icollect [label info (pairs (. (docs.get-global server :string) :fields))] (formatter.completion-item-format label info)) ;; fields of a table (tbl :table) (let [keys []] @@ -173,7 +173,7 @@ Every time the client sends a message, it gets handled by a function in the corr label)) (icollect [_ label (pairs keys)] (if (= (type label) :string) - (case (language.search-ast self file tbl [label] {}) + (case (language.search-ast server file tbl [label] {}) def (formatter.completion-item-format label def) _ {: label :kind kinds.Field}))))) {: metadata : fields} @@ -182,16 +182,16 @@ Every time the client sends a message, it gets handled by a function in the corr (formatter.completion-item-format label info))) _ nil))) -(λ requests.textDocument/completion [self send {: position :textDocument {: uri}}] - (let [file (state.get-by-uri self uri) - byte (utils.position->byte file.text position self.position-encoding) +(λ requests.textDocument/completion [server send {: position :textDocument {: uri}}] + (let [file (state.get-by-uri server uri) + byte (utils.position->byte file.text position server.position-encoding) (?symbol parents) (language.find-symbol file.ast byte)] (case (-?> ?symbol utils.multi-sym-split) ;; completion from current scope (where (or nil [_ nil])) - (let [input-range (if ?symbol (message.multisym->range self file ?symbol -1) {:start position :end position}) - ?completions (scope-completion self file byte ?symbol parents)] + (let [input-range (if ?symbol (message.multisym->range server file ?symbol -1) {:start position :end position}) + ?completions (scope-completion server file byte ?symbol parents)] (if ?completions (let [?completions (utils.uniq-by ?completions #$.label)] (each [_ completion (ipairs ?completions)] @@ -200,10 +200,10 @@ Every time the client sends a message, it gets handled by a function in the corr ;; completion from field [_a _b &as split] - (let [input-range (message.multisym->range self file ?symbol -1) - ?completions (field-completion self file ?symbol split)] + (let [input-range (message.multisym->range server file ?symbol -1) + ?completions (field-completion server file ?symbol split)] (if ?completions - (if self.EGLOT_COMPLETION_QUIRK_MODE + (if server.EGLOT_COMPLETION_QUIRK_MODE (let [prefix (string.gsub (tostring ?symbol) "[^.:]*$" "")] (each [_ completion (ipairs ?completions)] (set completion.filterText (.. prefix completion.label)) @@ -214,21 +214,21 @@ Every time the client sends a message, it gets handled by a function in the corr -(λ requests.textDocument/rename [self send {: position :textDocument {: uri} :newName new-name}] - (let [file (state.get-by-uri self uri) - byte (utils.position->byte file.text position self.position-encoding)] +(λ requests.textDocument/rename [server send {: position :textDocument {: uri} :newName new-name}] + (let [file (state.get-by-uri server uri) + byte (utils.position->byte file.text position server.position-encoding)] (case-try (language.find-symbol file.ast byte) symbol - (language.find-nearest-definition self file symbol symbol.bytestart) + (language.find-nearest-definition server file symbol symbol.bytestart) ;; TODO we are assuming that every reference is in the same file (where definition (not= definition.referenced-by nil)) (let [usages (icollect [_ {: symbol} (ipairs definition.referenced-by) - &into [{:range (message.multisym->range self definition.file definition.binding 1) + &into [{:range (message.multisym->range server definition.file definition.binding 1) :newText new-name}]] (if (and (. file.lexical symbol) (not (rawequal symbol definition.binding))) {:newText new-name - :range (message.multisym->range self definition.file symbol 1)}))] + :range (message.multisym->range server definition.file symbol 1)}))] ;; NOTE: I don't care about encoding here because we just need the relative positions (table.sort usages @@ -252,45 +252,45 @@ Every time the client sends a message, it gets handled by a function in the corr (and (pos<= range-1.start range-2.end) (pos<= range-2.start range-1.end))) -(λ requests.textDocument/codeAction [self send {: range :textDocument {: uri} &as params}] - (let [file (state.get-by-uri self uri)] +(λ requests.textDocument/codeAction [server send {: range :textDocument {: uri} &as params}] + (let [file (state.get-by-uri server uri)] (icollect [_ diagnostic (ipairs file.diagnostics)] (if (and (overlap? diagnostic.range range) diagnostic.quickfix) {:title diagnostic.codeDescription :edit {:changes {uri (diagnostic.quickfix)}}})))) -(λ notifications.textDocument/didChange [self send {: contentChanges :textDocument {: uri}}] - (local file (state.get-by-uri self uri)) - (state.set-uri-contents self uri (utils.apply-changes file.text contentChanges self.position-encoding)) - (lint.check self file) +(λ notifications.textDocument/didChange [server send {: contentChanges :textDocument {: uri}}] + (local file (state.get-by-uri server uri)) + (state.set-uri-contents server uri (utils.apply-changes file.text contentChanges server.position-encoding)) + (lint.check server file) (send (message.diagnostics file))) -(λ notifications.textDocument/didOpen [self send {:textDocument {: languageId : text : uri}}] - (local file (state.set-uri-contents self uri text)) - (lint.check self file) +(λ notifications.textDocument/didOpen [server send {:textDocument {: languageId : text : uri}}] + (local file (state.set-uri-contents server uri text)) + (lint.check server file) (send (message.diagnostics file)) (set file.open? true)) -(λ notifications.textDocument/didSave [self send {:textDocument {: uri}}] +(λ notifications.textDocument/didSave [server send {:textDocument {: uri}}] ;; TODO be careful about which modules need to be recomputed, and also eagerly flush existing files (set fennel.macro-loaded [])) -(λ notifications.textDocument/didClose [self send {:textDocument {: uri}}] - (local file (state.get-by-uri self uri)) +(λ notifications.textDocument/didClose [server send {:textDocument {: uri}}] + (local file (state.get-by-uri server uri)) (set file.open? false) (set fennel.macro-loaded []) ;; TODO only reload from disk if we didn't get a didSave, instead of always - (state.flush-uri self uri)) + (state.flush-uri server uri)) -(λ notifications.workspace/didChangeConfiguration [self send {: settings}] - (state.write-configuration self (?. settings :fennel-ls))) +(λ notifications.workspace/didChangeConfiguration [server send {: settings}] + (state.write-configuration server (?. settings :fennel-ls))) -(λ requests.shutdown [self send] +(λ requests.shutdown [server send] "The server still needs to respond to this request, so the program can't close yet. Just wait until notifications.exit" nil) -(λ notifications.exit [self] +(λ notifications.exit [server] "This is the real shutdown request, we can quit now" (os.exit 0)) diff --git a/src/fennel-ls/language.fnl b/src/fennel-ls/language.fnl index 7c76b55..9759609 100644 --- a/src/fennel-ls/language.fnl +++ b/src/fennel-ls/language.fnl @@ -64,7 +64,7 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find "add the multisy values to the end of the stack in reverse order" (stack-add-split! stack (utils.multi-sym-split symbol))) -(λ search-document [self document stack opts] +(λ search-document [server document stack opts] (when (and (not= (tostring (?. document :binding)) :_G) (= (length stack) 1)) (set opts.searched-through-require-with-stack-size-1 true)) @@ -72,13 +72,13 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find document (and document.fields (. document.fields (. stack (length stack)))) - (search-document self (. document.fields (table.remove stack)) stack opts))) + (search-document server (. document.fields (table.remove stack)) stack opts))) -(λ search-val [self file ?ast stack opts] +(λ search-val [server file ?ast stack opts] "searches for the definition of the ast, adjusted to 1 value" - (search-multival self file ?ast stack 1 opts)) + (search-multival server file ?ast stack 1 opts)) -(λ search-assignment [self file assignment stack opts] +(λ search-assignment [server file assignment stack opts] (let [{:target {:binding _ :definition ?definition :keys ?keys @@ -91,56 +91,56 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find assignment.target ;; BASE CASE!! ;; search a virtual field from :fields (and (not= 0 (length stack)) (?. ?fields (. stack (length stack)))) - (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-assignment server file {:target (. ?fields (table.remove stack))} stack opts) + (search-multival server file ?definition (stack-add-keys! stack ?keys) (or ?multival 1) opts)))) -(λ search-reference [self file ref stack opts] +(λ search-reference [server file ref stack opts] (if ref.target.metadata - (search-document self ref.target stack opts) + (search-document server ref.target stack opts) ref.target.binding - (search-assignment self file ref stack opts))) + (search-assignment server file ref stack opts))) -(λ search-symbol [self file symbol stack opts] +(λ search-symbol [server file symbol stack opts] (if (= (tostring symbol) :nil) (if (= 0 (length stack)) {:definition symbol : file} nil) (if (. file.references symbol) - (search-reference self file (. file.references symbol) (stack-add-multisym! stack symbol) opts)))) + (search-reference server file (. file.references symbol) (stack-add-multisym! stack symbol) opts)))) -(λ search-table [self file tbl stack opts] +(λ search-table [server file tbl stack opts] (if (. tbl (. stack (length stack))) - (search-val self file (. tbl (table.remove stack)) stack opts) + (search-val server file (. tbl (table.remove stack)) stack opts) nil)) ;; BASE CASE Give up -(λ search-list [self file call stack multival opts] +(λ search-list [server file call stack multival opts] (let [head (. call 1)] (if (sym? head) (case (tostring head) (where (or :do :let)) - (search-multival self file (. call (length call)) stack multival opts) + (search-multival server file (. call (length call)) stack multival opts) :values (let [len (- (length call) 1)] (if (< multival len) - (search-val self file (. call (+ 1 multival)) stack opts) - (search-multival self file (. call (+ len 1)) stack (+ multival (- len) 1) opts))) + (search-val server file (. call (+ 1 multival)) stack opts) + (search-multival server file (. call (+ len 1)) stack (+ multival (- len) 1) opts))) (where (or :require :include)) (let [mod (. call 2)] (if (= multival 1) (when (= :string (type mod)) - (let [newfile (state.get-by-module self mod)] + (let [newfile (state.get-by-module server mod)] (when newfile (let [newitem (. newfile.ast (length newfile.ast))] (when (= (length stack) 1) (set opts.searched-through-require-with-stack-size-1 true)) - (search-val self newfile newitem stack opts))))))) + (search-val server newfile newitem stack opts))))))) "." (if (= multival 1) (let [[_ & rest] call] - (search-val self file (. call 2) (stack-add-split! stack rest) opts))) + (search-val server file (. call 2) (stack-add-split! stack rest) opts))) ;; TODO assume-function-name analyze-metatable :setmetatable - (search-val self file (. call 2) stack opts) + (search-val server file (. call 2) stack opts) (where (or :fn :lambda :λ)) (if (and (= multival 1) (= 0 (length stack))) @@ -152,20 +152,20 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find {:definition call : file}))))) ;; BASE CASE!! (set search-multival - (λ [self file ?ast stack multival opts] + (λ [server file ?ast stack multival opts] (let [ast ?ast] ;; it was a bad idea to use λ because ast may be nil - (if (list? ast) (search-list self file ast stack multival opts) + (if (list? ast) (search-list server file ast stack multival opts) (varg? ast) nil ;; TODO function-args (= 1 multival) - (if (sym? ast) (search-symbol self file ast stack opts) + (if (sym? ast) (search-symbol server file ast stack opts) (= 0 (length stack)) {:definition ast : file} ;; BASE CASE !! - (= :table (type ast)) (search-table self file ast stack opts) - (= :string (type ast)) (search-document self (docs.get-global self :string) stack opts)) + (= :table (type ast)) (search-table server file ast stack opts) + (= :string (type ast)) (search-document server (docs.get-global server :string) stack opts)) nil)))) ;; the options thing is getting out of hand -(λ search-main [self file symbol opts initialization-opts] +(λ search-main [server file symbol opts initialization-opts] "Find the definition of a symbol" (assert (= (type initialization-opts) :table)) @@ -179,12 +179,12 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find (let [?byte initialization-opts.byte split (utils.multi-sym-split symbol (if ?byte (- ?byte symbol.bytestart)))] (stack-add-split! [] split)))] - (case (docs.get-builtin self (utils.multi-sym-base symbol)) - document (search-document self document stack opts) + (case (docs.get-builtin server (utils.multi-sym-base symbol)) + document (search-document server document stack opts) _ (case (. file.references symbol) - ref (search-reference self file ref stack opts) + ref (search-reference server 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))))))) + def (search-multival server file def.definition (stack-add-keys! stack def.keys) (or def.multival 1) opts))))))) (λ find-local-definition [file name ?scope] (when ?scope @@ -192,18 +192,18 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find definition definition _ (find-local-definition file name ?scope.parent)))) -(λ search-name-and-scope [self file name scope ?opts] +(λ search-name-and-scope [server file name scope ?opts] "find a definition just from the name of the item, and the scope it is in" (assert (= (type name) :string)) (let [split (utils.multi-sym-split name) stack (stack-add-split! [] split) opts (or ?opts {})] - (case (docs.get-builtin self (. split 1)) - metadata (search-document self metadata stack opts) - _ (case (docs.get-global self (. split 1)) - metadata (search-document self metadata stack opts) + (case (docs.get-builtin server (. split 1)) + metadata (search-document server metadata stack opts) + _ (case (docs.get-global server (. split 1)) + metadata (search-document server metadata stack opts) _ (case (find-local-definition file name scope) - def (search-val self file def.definition (stack-add-keys! stack def.keys) opts)))))) + def (search-val server file def.definition (stack-add-keys! stack def.keys) opts)))))) (λ _past? [?ast byte] ;; check if a byte is past an ast object @@ -262,10 +262,10 @@ 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-definition [self file symbol ?byte] +(λ find-nearest-definition [server file symbol ?byte] (if (. file.definitions symbol) (. file.definitions symbol) - (search-main self file symbol {:stop-early? true} {:byte ?byte}))) + (search-main server file symbol {:stop-early? true} {:byte ?byte}))) {: find-symbol : find-nearest-definition diff --git a/src/fennel-ls/lint.fnl b/src/fennel-ls/lint.fnl index 800bcc9..7745f18 100644 --- a/src/fennel-ls/lint.fnl +++ b/src/fennel-ls/lint.fnl @@ -1,5 +1,5 @@ "Diagnostics -Provides the function (check self file), which goes through a file and mutates +Provides the function (check server file), which goes through a file and mutates the `file.diagnostics` field, filling it with diagnostics." (local {: sym? : list? : view} (require :fennel)) @@ -10,8 +10,8 @@ the `file.diagnostics` field, filling it with diagnostics." (require :fennel.compiler)) (local diagnostic-mt {:__json_exclude_keys {:quickfix true}}) -(fn diagnostic [self] - (setmetatable self diagnostic-mt)) +(fn diagnostic [server] + (setmetatable server diagnostic-mt)) (local ops {"+" 1 "-" 1 "*" 1 "/" 1 "//" 1 "%" 1 "^" 1 ">" 1 "<" 1 ">=" 1 "<=" 1 "=" 1 "not=" 1 ".." 1 "." 1 "and" 1 "or" 1 "band" 1 "bor" 1 "bxor" 1 "bnot" 1 "lshift" 1 "rshift" 1}) (fn special? [item] @@ -24,7 +24,7 @@ the `file.diagnostics` field, filling it with diagnostics." (. ops (tostring item)) item)) -(λ unused-definition [self file symbol definition] +(λ unused-definition [server file symbol definition] "local variable that is defined but not used" (if (not (or (= "_" (: (tostring symbol) :sub 1 1)) (accumulate [reference false @@ -33,7 +33,7 @@ the `file.diagnostics` field, filling it with diagnostics." (or (= ref.ref-type :read) (= ref.ref-type :mutate))))) (diagnostic - {:range (message.ast->range self file symbol) + {:range (message.ast->range server file symbol) :message (.. "unused definition: " (tostring symbol)) :severity message.severity.WARN :code 301 @@ -41,20 +41,20 @@ the `file.diagnostics` field, filling it with diagnostics." :quickfix #[{:range (message.ast->range symbol) :newText (.. "_" (tostring symbol))}]}))) -(λ unknown-module-field [self file] +(λ unknown-module-field [server file] "any multisym whose definition can't be found through a (require) call" (icollect [symbol (pairs file.references) &into file.diagnostics] (if (. (utils.multi-sym-split symbol) 2) (let [opts {} - item (language.search-ast self file symbol [] opts)] + item (language.search-ast server file symbol [] opts)] (if (and (not item) opts.searched-through-require-with-stack-size-1) - {:range (message.ast->range self file symbol) + {:range (message.ast->range server file symbol) :message (.. "unknown field: " (tostring symbol)) :severity message.severity.WARN :code 302 :codeDescription "unknown-module-field"}))))) -(λ unnecessary-method [self file colon call] +(λ unnecessary-method [server file colon call] "a call to the : builtin that could just be a multisym" (if (and (sym? colon ":") (sym? (. call 2)) @@ -63,13 +63,13 @@ the `file.diagnostics` field, filling it with diagnostics." (if (and (= :string (type method)) (not (method:find "^[0-9]")) (not (method:find "[^!$%*+-/0-9<=>?A-Z\\^_a-z|\128-\255]"))) - {:range (message.ast->range self file call) + {:range (message.ast->range server file call) :message (.. "unnecessary : call: use (" (tostring (. call 2)) ":" method ")") :severity message.severity.WARN :code 303 :codeDescription "unnecessary-method"})))) -(λ bad-unpack [self file op call] +(λ bad-unpack [server file op call] "an unpack call leading into an operator" (let [last-item (. call (length call))] (if (and (op? op) @@ -81,7 +81,7 @@ the `file.diagnostics` field, filling it with diagnostics." (. file.lexical last-item) (. file.lexical call)) (diagnostic - {:range (message.ast->range self file last-item) + {:range (message.ast->range server file last-item) :message (.. "faulty unpack call: " (tostring op) " isn't variadic at runtime." (if (sym? op "..") (let [unpackme (view (. last-item 2))] @@ -93,19 +93,19 @@ the `file.diagnostics` field, filling it with diagnostics." :quickfix (if (and (= (length call) 2) (= (length (. call 2)) 2) (sym? op "..")) - #[{:range (message.ast->range self file call) + #[{:range (message.ast->range server file call) :newText (.. "(table.concat " (view (. call 2 2)) ")")}])})))) -(λ var-never-set [self file symbol definition] +(λ var-never-set [server file symbol definition] (if (and definition.var? (not definition.var-set) (. file.lexical symbol)) - {:range (message.ast->range self file symbol) + {:range (message.ast->range server file symbol) :message (.. "var is never set: " (tostring symbol) " Consider using (local) instead of (var)") :severity message.severity.WARN :code 305 :codeDescription "var-never-set"})) (local op-identity-value {:+ 0 :* 1 :and true :or false :band -1 :bor 0 :.. ""}) -(λ op-with-no-arguments [self file op call] +(λ op-with-no-arguments [server file op call] "A call like (+) that could be replaced with a literal" (let [identity (. op-identity-value (tostring op))] (if (and (op? op) @@ -113,15 +113,15 @@ the `file.diagnostics` field, filling it with diagnostics." (. file.lexical call) (not= nil identity)) (diagnostic - {:range (message.ast->range self file call) + {:range (message.ast->range server file call) :message (.. "write " (view identity) " instead of (" (tostring op) ")") :severity message.severity.WARN :code 306 :codeDescription "op-with-no-arguments" - :quickfix #[{:range (message.ast->range self file call) + :quickfix #[{:range (message.ast->range server file call) :newText (view identity)}]})))) -(λ multival-in-middle-of-call [self file fun call arg index] +(λ multival-in-middle-of-call [server file fun call arg index] "generally, values and unpack are signs that the user is trying to do something with multiple values. However, multiple values will get \"adjusted\" to one value if they don't come at the end of the call." @@ -132,29 +132,29 @@ the `file.diagnostics` field, filling it with diagnostics." (sym? (. arg 1) :unpack) (sym? (. arg 1) :_G.unpack) (sym? (. arg 1) :table.unpack))) - {:range (message.ast->range self file arg) + {:range (message.ast->range server file arg) :message (.. "bad " (tostring (. arg 1)) " call: only the first value of the multival will be used") :severity message.severity.WARN :code 307 :codeDescription "bad-unpack"})) -(λ check [self file] +(λ check [server file] "fill up the file.diagnostics table with linting things" - (let [checks self.configuration.checks + (let [checks server.configuration.checks diagnostics file.diagnostics] ;; definition lints (each [symbol definition (pairs file.definitions)] - (if checks.unused-definition (table.insert diagnostics (unused-definition self file symbol definition))) - (if checks.var-never-set (table.insert diagnostics (var-never-set self file symbol definition)))) + (if checks.unused-definition (table.insert diagnostics (unused-definition server file symbol definition))) + (if checks.var-never-set (table.insert diagnostics (var-never-set server file symbol definition)))) ;; call lints ;; all non-macro calls. This only covers specials and function calls. (each [[head &as call] (pairs file.calls)] (when head - (if checks.bad-unpack (table.insert diagnostics (bad-unpack self file head call))) - (if checks.unnecessary-method (table.insert diagnostics (unnecessary-method self file head call))) - (if checks.op-with-no-arguments (table.insert diagnostics (op-with-no-arguments self file head call))) + (if checks.bad-unpack (table.insert diagnostics (bad-unpack server file head call))) + (if checks.unnecessary-method (table.insert diagnostics (unnecessary-method server file head call))) + (if checks.op-with-no-arguments (table.insert diagnostics (op-with-no-arguments server file head call))) ;; argument lints ;; every argument to a special or a function call @@ -162,10 +162,10 @@ the `file.diagnostics` field, filling it with diagnostics." ;; I'll wait till we have more lints in here to see if it needs to change. (for [index 2 (length call)] (let [arg (. call index)] - (if checks.multival-in-middle-of-call (table.insert diagnostics (multival-in-middle-of-call self file head call arg index))))))) + (if checks.multival-in-middle-of-call (table.insert diagnostics (multival-in-middle-of-call server file head call arg index))))))) (if checks.unknown-module-field - (unknown-module-field self file)))) + (unknown-module-field server file)))) ;; (if checks.unnecessary-values ;; (unnecessary-values file))) ;; (if checks.unnecessary-do) diff --git a/src/fennel-ls/message.fnl b/src/fennel-ls/message.fnl index efe2ee4..4989411 100644 --- a/src/fennel-ls/message.fnl +++ b/src/fennel-ls/message.fnl @@ -58,14 +58,14 @@ LSP json objects." : id :result (nullify ?result)}) -(λ ast->range [self file ?ast] +(λ ast->range [server file ?ast] (case (fennel.ast-source ?ast) {: bytestart : byteend} {:start (utils.byte->position file.text bytestart - self.position-encoding) + server.position-encoding) :end (utils.byte->position file.text (+ byteend 1) - self.position-encoding)})) + server.position-encoding)})) -(λ multisym->range [self file ast n] +(λ multisym->range [server file ast n] (let [spl (utils.multi-sym-split ast) n (if (< n 0) (+ n 1 (length spl)) n)] (case (values (utils.get-ast-info ast :bytestart) @@ -77,12 +77,12 @@ LSP json objects." bytesubend (faccumulate [b byteend i (+ n 1) (length spl)] (- b (length (. spl i)) 1))] - {:start (utils.byte->position file.text bytesubstart self.position-encoding) - :end (utils.byte->position file.text (+ bytesubend 1) self.position-encoding)})))) + {:start (utils.byte->position file.text bytesubstart server.position-encoding) + :end (utils.byte->position file.text (+ bytesubend 1) server.position-encoding)})))) -(λ range-and-uri [self {: uri &as file} ?ast] +(λ range-and-uri [server {: uri &as file} ?ast] "if possible, returns the location of a symbol" - (case (ast->range self file ?ast) + (case (ast->range server file ?ast) range {: range : uri})) (λ diagnostics [file] diff --git a/src/fennel-ls/searcher.fnl b/src/fennel-ls/searcher.fnl index 6e5c1b1..517316d 100644 --- a/src/fennel-ls/searcher.fnl +++ b/src/fennel-ls/searcher.fnl @@ -37,12 +37,12 @@ I suspect this file may be gone after a bit of refactoring." (table.insert result (join (utils.uri->path workspace) path))))) (table.concat result ";"))) -(fn file-exists? [self uri] - (or (. self.preload uri) +(fn file-exists? [server uri] + (or (. server.preload uri) (case (io.open (utils.uri->path uri)) f (do (f:close) true)))) -(λ lookup [{:configuration {: fennel-path} :root-uri ?root-uri &as self} mod] +(λ lookup [{:configuration {: fennel-path} :root-uri ?root-uri &as server} mod] "Use the fennel path to find a file on disk" (when ?root-uri (let [mod (mod:gsub "%." sep) @@ -55,7 +55,7 @@ I suspect this file may be gone after a bit of refactoring." segment (join root-path segment)) segment (utils.path->uri segment)] - (if (file-exists? self segment) + (if (file-exists? server segment) segment)))))) {: lookup diff --git a/src/fennel-ls/state.fnl b/src/fennel-ls/state.fnl index e81f9cf..99bfbe8 100644 --- a/src/fennel-ls/state.fnl +++ b/src/fennel-ls/state.fnl @@ -4,15 +4,14 @@ This module keeps track of the state of the language server: * Loaded files There is no global state in this project: all state is stored -in the \"self\" object. Pretty much every \"self\" in the -entire fennel-ls project is referring to the same object." +in the \"server\" object." (local searcher (require :fennel-ls.searcher)) (local utils (require :fennel-ls.utils)) (local {: compile} (require :fennel-ls.compiler)) -(λ read-file [self uri] - (let [text (case (. self.preload uri) +(λ read-file [server uri] + (let [text (case (. server.preload uri) preload preload _ (let [file (io.open (utils.uri->path uri))] (if file @@ -22,48 +21,48 @@ entire fennel-ls project is referring to the same object." (error (.. "failed to open file" uri)))))] {: uri : text})) -(λ get-by-uri [self uri] - (or (. self.files uri) - (let [file (read-file self uri)] - (compile self file) - (tset self.files uri file) +(λ get-by-uri [server uri] + (or (. server.files uri) + (let [file (read-file server uri)] + (compile server file) + (tset server.files uri file) file))) -(λ get-by-module [self module] +(λ get-by-module [server module] ;; check the cache - (case (. self.modules module) + (case (. server.modules module) uri - (or (get-by-uri self uri) + (or (get-by-uri server uri) ;; if the cached uri isn't found, clear the cache and try again - (do (tset self.modules module nil) - (get-by-module self module))) + (do (tset server.modules module nil) + (get-by-module server module))) nil - (case (searcher.lookup self module) + (case (searcher.lookup server module) uri (do - (tset self.modules module uri) - (get-by-uri self uri))))) + (tset server.modules module uri) + (get-by-uri server uri))))) -(λ set-uri-contents [self uri text] - (case (. self.files uri) +(λ set-uri-contents [server uri text] + (case (. server.files uri) ;; modify existing file file (do (when (not= text file.text) (set file.text text) - (compile self file)) + (compile server file)) file) ;; create new file nil (let [file {: uri : text}] - (tset self.files uri file) - (compile self file) + (tset server.files uri file) + (compile server file) file))) -(λ flush-uri [self uri] +(λ flush-uri [server uri] "get rid of data about a file, in case it changed in some way" - (tset self.files uri nil)) + (tset server.files uri nil)) ;; TODO: set the warning levels of lints ;; allow all globals @@ -127,20 +126,20 @@ However, when not an option, fennel-ls will fall back to positionEncoding=\"utf- :utf-8 :utf-16))) -(λ init-state [self params] - (set self.files {}) - (set self.preload {}) - (set self.modules {}) - (set self.root-uri params.rootUri) - (set self.position-encoding (choose-position-encoding params)) - (set self.configuration (make-configuration (?. params :initializationOptions :fennel-ls))) +(λ init-state [server params] + (set server.files {}) + (set server.preload {}) + (set server.modules {}) + (set server.root-uri params.rootUri) + (set server.position-encoding (choose-position-encoding params)) + (set server.configuration (make-configuration (?. params :initializationOptions :fennel-ls))) ;; Eglot does completions differently than every other client I've seen so far, in that it considers foo.bar to be one "symbol". ;; If the user types `foo.b`, every other client accepts `bar` as a completion, bun eglot wants the full `foo.bar` multisym. - (set self.EGLOT_COMPLETION_QUIRK_MODE (= (?. params :clientInfo :name) :Eglot))) + (set server.EGLOT_COMPLETION_QUIRK_MODE (= (?. params :clientInfo :name) :Eglot))) -(λ write-configuration [self ?configuration] +(λ write-configuration [server ?configuration] "This is where we can put anything that needs to react to config changes" - (set self.configuration (make-configuration ?configuration))) + (set server.configuration (make-configuration ?configuration))) {: flush-uri : get-by-module