From 66bcfc65e5ae91fcd9dcae71e05db67917039445 Mon Sep 17 00:00:00 2001 From: XeroOl Date: Fri, 1 Mar 2024 15:22:32 -0600 Subject: [PATCH] fix completions for M style modules --- src/fennel-ls/handlers.fnl | 22 +++++++++++++++------- src/fennel-ls/language.fnl | 5 ++++- test/completion.fnl | 15 +++++++-------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index 6405a85..0fe5889 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -156,19 +156,27 @@ Every time the client sends a message, it gets handled by a function in the corr (case (. file.references symbol) ref (let [stack (fcollect [i (- (length split) 1) 2 -1] - (. split i))] - (case (language.search-assignment self file ref stack {}) + (. split i)) + last-found-binding []] + (case (language.search-assignment self file ref stack {:save-last-binding last-found-binding}) {: definition : file} (case (values definition (type definition)) ;; fields of a string are hardcoded to "string" (_str :string) (icollect [label _ (pairs string)] {: label :kind kinds.Field :textEdit {:newText label}}) ;; fields of a table - (tbl :table) (icollect [label _ (pairs tbl)] - (if (= (type label) :string) - (case (language.search-ast self file tbl [label] {}) - def (formatter.completion-item-format label def) - _ {: label :kind kinds.Field :textEdit {:newText label}})))) + (tbl :table) (let [keys []] + (icollect [label _ (pairs tbl) &into keys] + label) + (when (?. last-found-binding 1 :fields) + (icollect [label _ (pairs (. last-found-binding 1 :fields)) &into keys] + label)) + (icollect [_ label (pairs keys)] + (if (= (type label) :string) + (case (language.search-ast self file tbl [label] {}) + def (formatter.completion-item-format label def) + _ {: label :kind kinds.Field :textEdit {:newText label}}))))) + _ nil)))) (λ requests.textDocument/completion [self send {: position :textDocument {: uri}}] diff --git a/src/fennel-ls/language.fnl b/src/fennel-ls/language.fnl index 8022f34..b45e1ea 100644 --- a/src/fennel-ls/language.fnl +++ b/src/fennel-ls/language.fnl @@ -23,7 +23,7 @@ The search failed, and encountered something that isn't implemented. # A definition: `{:definition _ :file _}` The search succeeded and found a file with a user definition of a value. -# A binding: `{:definition _ :file _ :binding _ :multival ?_ :keys ?_ :referenced-by ?_ :var? ?true}` +# A binding: `{:definition _ :file _ :binding _ :multival ?_ :keys ?_ :referenced-by ?_ :var? ?true :fields ?extra_fields}` If you set the option `opts.stop-early?`, search may stop at a binding instead of a true definition. A binding is a place where an identifier gets introduced. @@ -72,6 +72,9 @@ a user-written file. :keys ?keys :multival ?multival :fields ?fields}} assignment] + (when (and (= 0 (length stack)) + opts.save-last-binding) + (tset opts.save-last-binding 1 assignment.target)) (if (and (= 0 (length stack)) opts.stop-early?) assignment.target ;; BASE CASE!! ;; search a virtual field from :fields diff --git a/test/completion.fnl b/test/completion.fnl index e2006bd..758c308 100644 --- a/test/completion.fnl +++ b/test/completion.fnl @@ -143,14 +143,13 @@ :fooo.fnl "(fn my-export [x] (print x)) {: my-export :constant 10}"} [:my-export :constant] - [:_G :local :doto :+] - ;; TODO fix completions of virtual fields - ; (check - ; {:main.fnl "(let [foo (require :fooo)] - ; foo.|)))" - ; :fooo.fnl "(local M {:constant 10}) - ; (fn M.my-export [x] (print x)) - ; M"} + [:_G :local :doto :+]) + (check + {:main.fnl "(let [foo (require :fooo)] + foo.|)))" + :fooo.fnl "(local M {:constant 10}) + (fn M.my-export [x] (print x)) + M"} [:my-export :constant] [:_G :local :doto :+]) ;; no globals, specials, macros, or others (check "(local x {:field (fn [])})\n(x:fi|" [:field] [:table])