Rename self->server
This commit is contained in:
parent
bb47e723a6
commit
0b3d1b47a5
@ -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)]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)))
|
||||
|
||||
|
||||
@ -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))
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user