diff --git a/API.md b/API.md index aeee7b4..e69de29 100644 --- a/API.md +++ b/API.md @@ -1,313 +0,0 @@ -format: using built-in markdown -format: using built-in markdown -format: discount not found, using markdown -# acid.connections -low-level connection handler - -## `acid.connections.add(addr)` -Stores connection for reuse later - -addr **({string,string})**: Address tuple with ip and port. - - -## `acid.connections.select(pwd, ix)` -Elects selected connection as primary (thus default) for a certain address - -pwd **(string)**: path (usually project root). - Assumed to be neovim's `pwd`. - -ix **(int)**: index of the stored connection - - -## `acid.connections.unselect(pwd)` -Dissociates the connection for the given path - -pwd **(string)**: path (usually project root). - - -## `acid.connections.peek([pwd])` -Return active connection for the given path - -*pwd* **(string)**: path (usually project root). - - -**(string)** Id of the current connection for the path or nil. - - -## `acid.connections.get(pwd)` -Return active connection for the given path - -pwd **(string)**: path (usually project root). - - -**({string,string})** Connection tuple with ip and port or nil. - - -## `acid.connections.set(pwd, addr)` -Add and select the given connection for given path. - -pwd **(string)**: path (usually project root). - -addr **({string,string})**: tuple with ip and port or nil. - - ---- - -# acid.core -low-level connection handler. - -## `acid.core.send([conn], obj, handler)` -Forward messages to the nrepl and registers the handler. - -*conn* **({string,string})**: Ip and Port tuple. Will try to get one if nil. - -obj **(table)**: Payload to be sent to the nrepl. - -handler **(function)**: Handler function to deal with the response. - - ---- - -# extra.ulid -generates the time-based part of a `ulid`. - ---- - -# acid.features -User-facing features and runnable commands - -## `acid.features.eval_cmdline(code[, ns])` -Evaluate the given code and insert the result at the cursor position - -code **(string)**: Clojure s-expression to be evaluated on the nrepl - -*ns* **(string)**: Namespace to be used when evaluating the code. - Defaults to current file's ns. - - -## `acid.features.eval_print(code[, ns])` -Evaluate the given code and print the result. - -code **(string)**: Clojure s-expression to be evaluated on the nrepl - -*ns* **(string)**: Namespace to be used when evaluating the code. - Defaults to current file's ns. - - - -## `acid.features.eval_expr([mode[, replace[, ns]]])` -Evaluate the current form or the given motion. - -*mode* **(string)**: motion mode - -*replace* **(boolean)**: whether it should replace the form with its result - -*ns* **(string)**: Namespace to be used when evaluating the code. - Defaults to current file's ns. - - -## `acid.features.do_require([ns[, ...]])` -Sends a `(require '[...])` function to the nrepl. - -*ns* **(string)**: Namespace to be used when evaluating the code. - Defaults to current file's ns. - -*...*: extra arguments to the require function - - -## `acid.features.do_import(java_ns, symbols)` -Sends a `(import '[...])` function to the nrepl. - -java_ns **(string)**: Namespace of the java symbols that are being imported. - -symbols **({string,...})**: List of java symbols to be imported - - -## `acid.features.go_to([symbol[, ns]])` -Navigates the definition of the given symbol. - -*symbol* **(string)**: Symbol to navigate to. Defaults to symbol under - cursor. - -*ns* **(string)**: Namespace to be used when evaluating the code. - Defaults to current file's ns. - - -## `acid.features.docs([symbol[, ns]])` -Shows the docstring of the given symbol. - -*symbol* **(string)**: Symbol which docs will be shown. Defaults to symbol under cursor. - -*ns* **(string)**: Namespace to be used when evaluating the code. - Defaults to current file's ns. - - -## `acid.features.preload()` -Inject some clojure files into the nrepl session. - - -## `acid.features.load_all_nss()` -Load all namespaces in the current session. - - -## `acid.features.add_require(req)` -Refactor the current file to include the given argument in the -`(:requires ...)` section. - -req **(string)**: require vector, such as `[clojure.string :as str]`. - - -## `acid.features.remove_require(req)` -Refactor the current file to remove the given argument from the -`(:requires ...)` section. - -req **(string)**: require namespace, such as `clojure.string`. - - -## `acid.features.sort_requires()` -Refactor the current file so the `(:require ...)` form is sorted. - - -## `acid.features.clean_ns()` -Refactor the current file so the `(:require ...)` form is sorted. - - ---- - -# acid.forms -Forms extraction - -## `acid.forms.get_form_boundaries([top])` -Returns the coordinates for the boundaries of the current form - -*top* **(boolean)**: if true, recursively searches for top level. - - -**(table)** coordinates {from = {row,col}, to = {row,col}} - - -## `acid.forms.form_from_motion(mode[, bufnr])` -Extracts the form according to given motion (or visual mode) - -mode **(string)**: Motion mode or 'visual' - -*bufnr* **(int)**: Buffer number in neovim. Will take current if none given - - -**(string)** symbol under cursor - -**(table)** coordinates {from = {row,col}, to = {row,col}, bufnr = 1} - - -## `acid.forms.form_under_cursor([top])` -Extracts the innermost form under the cursor - -*top* **(boolean)**: if true, recursively searches for top level. - - -**(string)** symbol under cursor - -**(table)** coordinates {from = {row,col}, to = {row,col}, bufnr = 1} - - -## `acid.forms.symbol_under_cursor()` -Extracts the symbol under the cursor - - -**(string)** symbol under cursor - -**(table)** coordinates {from = {row,col}, to = {row,col}, bofnr = 1} - - ---- - -# acid -Frontend module with most relevant functions - -## `acid.connected([pwd])` -Checks whether a connection exists for supplied path or not. - -*pwd* **(string)**: Path bound to connection. - Will call `getcwd` on neovim if not supplied - - -**(boolean)** Whether a connection exists or not. - - -## `acid.run(cmd, conn)` -Façade to core.send - -cmd: A command (op + payload + handler) to be executed. - -conn: A connection where this command will be run. - - -## `acid.callback(ret)` -Callback proxy for handling command responses - -ret: The response from nrepl - - -## `acid.admin_session_start()` -Setup admin nrepl session - This nrepl session should be used by plugins to deal with clojure code - without injecting things in the user nrepl session - or for things that clojure could deal with better while not having a - nrepl session to use. - - ---- - -# acid.nrepl -nRepl connectivity - -## `middlewares` -List of supported middlewares and the wrappers to invoke when spawning a nrepl process. - -Values: - -* `[nrepl/nrepl]` - -## `default_middlewares` -Default middlewares that will be used by the nrepl server - -Values: - -* `nrepl/nrepl` -* `cider/cider-nrepl` -* `refactor-nrepl` - -## `acid.nrepl.start(obj)` -Starts a tools.deps nrepl server - -obj **(table)**: Configuration for the nrepl process to be spawn - -Parameters for table `obj` are: - -* *obj.pwd* **(string)**: Path where the nrepl process will be started -* *obj.middlewares* **(table)**: List of middlewares. -* *obj.alias* **(string)**: aliases on the local deps.edn -* *obj.connect* **(string)**: -c parameter for the nrepl process -* *obj.bind* **(string)**: -b parameter for the nrepl process -* *obj.skip_autocmd* **(boolean)**: don't fire an autocmd after starting this repl - -**(boolean)** Whether it was possible to spawn a nrepl process - - -## `acid.nrepl.stop(obj)` -Stops a nrepl process managed by acid - -obj **(table)**: Configuration for the nrepl process to be stopped - -Parameters for table `obj` are: - -* obj.pwd **(string)**: Path where the nrepl process was started - -## `acid.nrepl.show([ch])` -Debugs nrepl connection by returning the captured output - -*ch* **(int)**: Neovim's job id of given nrepl process. When not supplied return all. - - -**(table)** table with the captured outputs for given (or all) nrepl process(es). - diff --git a/bin/pctl b/bin/pctl new file mode 100755 index 0000000..21031fb --- /dev/null +++ b/bin/pctl @@ -0,0 +1,48 @@ +#!/bin/bash +set -eou pipefail + +BIN_DIR="$(dirname "$(realpath "$0")")" +ROOT_DIR="$(dirname "$BIN_DIR")" + +LUAROCKS="luarocks-5.1" + +exists() { + command -v "$1" > /dev/null +} + +setup(){ + exists luarocks-5.1 || { + exists luarocks && { + LUAROCKS="luarocks --lua-version 5.1" + } || { + echo 'Please install luarocks' + exit 1 + } + } + + $LUAROCKS install "$1" +} + +tests(){ + exists busted || setup busted + busted +} + +linter(){ + exists luacheck || setup luacheck + luacheck lua/ +} + +run() { + tests + linter +} + + +run-dev(){ +inotifywait -r -q -m -e close_write --format %e lua spec | while read -r ; do +busted +done +} + +cd $ROOT_DIR && "$@" diff --git a/clj/acid/inject.clj b/clj/acid/inject.clj index 88aa6af..03c4482 100644 --- a/clj/acid/inject.clj +++ b/clj/acid/inject.clj @@ -5,27 +5,28 @@ (let [[[h] v] (split-at 1 reqs)] (conj (sort-by first (modify v)) h))) -(defn sort-reqs [reqs] - (manipulate-req reqs identity)) - -(defn add-req [new-req reqs] - (manipulate-req reqs #(conj % new-req))) - -(defn rem-req [old-req reqs] - (manipulate-req reqs (partial remove #(= old-req (first %))))) - -(defn map-if [pred action col] - (apply list (map (fn [v] - (if (pred v) - (action v) - v)) - col))) - (defn format-code [code] (p/with-pprint-dispatch p/code-dispatch (p/pprint - (clojure.edn/read-string (str code))))) + (clojure.edn/read-string code)))) + +(defn update-ns-decl [ns-decl decl fn-] + (let [seq-ns-decl (sequence (comp + (map-indexed list) + (filter (comp coll? second))) + ns-decl)] + (if-let [ix (first (filter (comp + #{decl} + first + second) + seq-ns-decl))] + (sequence (update (vec ns-decl) (first ix) fn-)) + (if-let [[ix _] (first seq-ns-decl)] + (let [[before after] (split-at ix ns-decl)] + (concat before (conj after (fn- (list decl))))) + (concat ns-decl (list (fn- (list decl)))))))) + +(defn add-req [arg] #(sequence (conj (vec %) (vec arg)))) -(defn upd-ns [decl symb action] - (map-if #(when (seq? %) (#{symb} (first %))) action decl)) +(defn rem-req [old-req] (partial remove #(= old-req (first %)))) diff --git a/lua/acid/core.lua b/lua/acid/core.lua index 5d10b69..f4e1313 100644 --- a/lua/acid/core.lua +++ b/lua/acid/core.lua @@ -23,8 +23,6 @@ core.send = function(connection, obj, handler) return end - local pwd = vim.api.nvim_call_function("getcwd", {}) - local ctp = type(connection) if ctp == "string" then conn_id = connection diff --git a/lua/acid/extra/ulid.lua b/lua/acid/extra/ulid.lua index de3dd86..05509a8 100644 --- a/lua/acid/extra/ulid.lua +++ b/lua/acid/extra/ulid.lua @@ -77,8 +77,6 @@ local _M = { ulid = ulid, encode_time = encode_time, encode_random = encode_random, - set_time_func = set_time_func, - set_random_func = set_random_func, } return setmetatable(_M, { diff --git a/lua/acid/features.lua b/lua/acid/features.lua index 5758f5a..e4bdf3e 100644 --- a/lua/acid/features.lua +++ b/lua/acid/features.lua @@ -79,6 +79,7 @@ features.eval_expr = function(mode, replace, ns) form, coord = forms.form_under_cursor(true) payload.code = table.concat(form, "\n") else + local lines lines, coord = forms.form_from_motion(mode) payload.code = table.concat(lines, "\n") end @@ -118,7 +119,8 @@ features.do_require = function(ns, ...) ns = vim.api.nvim_call_function("AcidGetNs", {}) end acid.run(commands.req{ns = ns, mod = {...}}:with_handler(middlewares - .doautocmd{autocmd = "AcidRequired"} + .doautocmd{autocmd = "AcidRequired"} + .err{} )) end @@ -128,7 +130,8 @@ end -- @tparam {string,...} symbols List of java symbols to be imported features.do_import = function(java_ns, symbols) acid.run(commands.import{java_ns = java_ns, symbols = symbols}:with_handler(middlewares - .doautocmd{autocmd = "AcidImported"} + .doautocmd{autocmd = "AcidImported"} + .err{} )) end @@ -172,6 +175,12 @@ features.docs = function(symbol, ns) elseif data.member ~= nil then table.insert(lines, data.member) end + if data.eldoc == nil then + if utils.find(data.status, "no-eldoc") then + local log = require("acid.log") + log.msg("No documentation for symbol " .. symbol) + end + end for _, v in ipairs(data.eldoc) do table.insert(lines, "[" .. table.concat(v, " ") .. "]") end @@ -212,24 +221,38 @@ end --`(:requires ...)` section. -- @tparam string req require vector, such as `[clojure.string :as str]`. features.add_require = function(req) - local lines, coords = forms.form_under_cursor() + local lines, coords = forms.ns() local content = table.concat(lines, "") - local code = "(format-code (upd-ns '" .. content .. " :require (partial add-req '" .. req .. ")))" + local format = function(data) + if data.status ~= nil then + return + else + return ops.eval{ + ns = "acid.inject", + code = '(format-code "' .. data.value .. '")' + }:with_handler(middlewares + .refactor(utils.merge({ + accessor = function(dt) + return dt['out'] + end + }, coords))) + end + end + + local code = "(update-ns-decl '" .. content .. " :require (add-req '" .. req .. "))" - acid.run(ops.eval{code = code, ns = "acid.inject"}:with_handler(middlewares - .refactor(coords) - )) + acid.run(ops.eval{code = code, ns = "acid.inject"}:with_handler(format)) end --- Refactor the current file to remove the given argument from the --`(:requires ...)` section. -- @tparam string req require namespace, such as `clojure.string`. features.remove_require = function(req) - local lines, coords = forms.form_under_cursor() + local lines, coords = forms.ns() local content = table.concat(lines, "") - local code = "(format-code (upd-ns '" .. content .. " :require (partial rem-req '" .. req .. ")))" + local code = "(format-code (upd-ns '" .. content .. " :require (rem-req '" .. req .. ")))" acid.run(ops.eval{code = code, ns = "acid.inject"}:with_handler(middlewares .refactor(coords) @@ -238,15 +261,24 @@ end --- Refactor the current file so the `(:require ...)` form is sorted. features.sort_requires = function() - local lines, coords = forms.form_under_cursor() + local lines, coords = forms.ns() local content = table.concat(lines, "") - local code = "(format-code (upd-ns '" .. content .. " :require sort-reqs))" - acid.run(ops.eval{code = code, ns = "acid.inject"}:with_handler(middlewares - .refactor(coords) - )) -end + local code = "(upd-ns '" .. content .. " :require sort-reqs)" + + acid.run(ops.eval{code = code, ns = "acid.inject"}:with_handler( + function(data) + return ops['format-code']{ + code = data.out + }:with_handler(middlewares + .refactor(utils.merge({ + accessor = function(dt) + return dt['formatted-code'] + end + }, coords))) + end)) + end features.thread_first = function() local lines, coords = forms.form_under_cursor() @@ -266,11 +298,11 @@ end --- Refactor the current file so the `(:require ...)` form is sorted. features.clean_ns = function() - local lines, coords = forms.form_under_cursor() + local _, coords = forms.ns() local fpath = vim.api.nvim_call_function('expand', {'%:p'}) - coords.accessor = function(x) - return x.ns + coords.accessor = function(data) + return data.ns end acid.run(ops['clean-ns']{path = fpath}:with_handler(middlewares @@ -358,22 +390,6 @@ features.thread_last = function() )) end ---- Refactor the current file so the `(:require ...)` form is sorted. -features.clean_ns = function() - local lines, coords = forms.form_under_cursor() - local fpath = vim.api.nvim_call_function('expand', {'%:p'}) - - coords.accessor = function(x) - return x.ns - end - - acid.run(ops['clean-ns']{path = fpath}:with_handler(middlewares - .refactor(coords) - )) - -end - - features.thread_first = function() local lines, coords = forms.form_under_cursor() local content = table.concat(lines, "\n") @@ -390,19 +406,5 @@ features.thread_last = function() )) end ---- Refactor the current file so the `(:require ...)` form is sorted. -features.clean_ns = function() - local lines, coords = forms.form_under_cursor() - local fpath = vim.api.nvim_call_function('expand', {'%:p'}) - - coords.accessor = function(x) - return x.ns - end - - acid.run(ops['clean-ns']{path = fpath}:with_handler(middlewares - .refactor(coords) - )) - -end return features diff --git a/lua/acid/forms.lua b/lua/acid/forms.lua index 54c0e2e..1b86fe5 100644 --- a/lua/acid/forms.lua +++ b/lua/acid/forms.lua @@ -4,6 +4,24 @@ -- @module acid.forms local forms = {} +forms.ns_pos = function() + local curpos = vim.api.nvim_win_get_cursor(0) + local from = vim.api.nvim_call_function("searchpos", {"(ns", "bcnw"}) + + vim.api.nvim_win_set_cursor(0, {from[1], from[2] - 1}) + + local pos = forms.get_form_boundaries(true) + + vim.api.nvim_win_set_cursor(0, curpos) + + return pos +end + +forms.ns = function() + local coordinates = forms.ns_pos() + return forms.extract(coordinates) +end + --- Returns the coordinates for the boundaries of the current form -- @tparam[opt] boolean top if true, recursively searches for top level. -- @treturn table coordinates {from = {row,col}, to = {row,col}} @@ -114,12 +132,12 @@ end -- @treturn string symbol under cursor -- @treturn table coordinates {from = {row,col}, to = {row,col}, bofnr = 1} forms.symbol_under_cursor = function() - local isk = vim.api.nvim_get_option('iskeyword') - vim.api.nvim_command("setlocal iskeyword=" .. isk .. ",#,%,&,'") + local isk = vim.api.nvim_buf_get_option(0, 'iskeyword') + vim.api.nvim_buf_set_option(0, 'iskeyword', isk .. ",#,%,&,'") local cw = vim.api.nvim_call_function("expand", {""}) local from = vim.api.nvim_call_function("searchpos", {cw, "nc"}) local to = vim.api.nvim_call_function("searchpos", {cw, "nce"}) - vim.api.nvim_command("setlocal iskeyword=" .. isk) + vim.api.nvim_buf_set_option(0, 'iskeyword', isk) return cw, { from = from, diff --git a/lua/acid/middlewares/err.lua b/lua/acid/middlewares/err.lua index a97fd07..2061457 100644 --- a/lua/acid/middlewares/err.lua +++ b/lua/acid/middlewares/err.lua @@ -16,7 +16,7 @@ err.middleware = function(config) table.insert(cache, data.err) end - if not has_err or not config.bail_out then + if not has_err or config.pass_through then return middleware(data) end end diff --git a/lua/acid/middlewares/insert.lua b/lua/acid/middlewares/insert.lua index 1047041..535c4dd 100644 --- a/lua/acid/middlewares/insert.lua +++ b/lua/acid/middlewares/insert.lua @@ -9,7 +9,9 @@ insert.middleware = function(config) return end - local text = vim.split(config.current_line:sub(1, config.coords[3] - 1) .. config.accessor(data) .. config.current_line:sub(config.coords[3]), "\n", false) + local text = vim.split(config.current_line:sub(1, config.coords[3] - 1) .. + config.accessor(data) .. + config.current_line:sub(config.coords[3]), "\n", false) vim.api.nvim_buf_set_lines(config.cb, config.coords[2] - 1, config.coords[2] + #text -1, true, text) diff --git a/lua/acid/middlewares/interrupt.lua b/lua/acid/middlewares/interrupt.lua index 812de1d..3a5705d 100644 --- a/lua/acid/middlewares/interrupt.lua +++ b/lua/acid/middlewares/interrupt.lua @@ -35,4 +35,4 @@ end -return virtualtext +return interrupt diff --git a/lua/acid/middlewares/output.lua b/lua/acid/middlewares/output.lua index 5f0d4d1..9fbbd2a 100644 --- a/lua/acid/middlewares/output.lua +++ b/lua/acid/middlewares/output.lua @@ -1,11 +1,9 @@ -- luacheck: globals vim -local do_print = {} +local mdw = {} local output = require("acid.output") local sessions = require("acid.sessions") -local utils = require("acid.utils") -local log = require("acid.log") -output.middleware = function(config) +mdw.middleware = function(config) return function(middleware) return function(data) local session = data.session @@ -21,7 +19,6 @@ output.middleware = function(config) output.draw(conn_id, "!! " .. data.ex) end if data.err ~= nil then - local out = {} output.draw(conn_id, data.err) end @@ -37,4 +34,4 @@ output.middleware = function(config) end end -return output +return mdw diff --git a/lua/acid/middlewares/quickfix.lua b/lua/acid/middlewares/quickfix.lua index f989972..77a4e0d 100644 --- a/lua/acid/middlewares/quickfix.lua +++ b/lua/acid/middlewares/quickfix.lua @@ -15,7 +15,6 @@ quickfix.config.qflistid = vim.fn.getqflist({id = 0, title = "[acid] clojure.test failures", }).id - quickfix.set = function(config) return function(middleware) return function(data) @@ -24,19 +23,28 @@ quickfix.set = function(config) for ns, tests in pairs(data.results) do for test, asserts in pairs(tests) do for _, assert in ipairs(asserts) do - if assert.type == "fail" then + if assert.type ~= "pass" then local fpath = vim.fn.globpath( vim.fn.getcwd(), '**/' .. assert.file, false, true)[1] - table.insert(qf, { + local obj = { module = ns .. "/" .. test, lnum = assert.line, - nr = assert.index, - text = assert.context, + nr = assert.index + 1, + valid = assert.context, + type = 'F', filename = fpath - }) + } + + if assert.type == 'fail' then + obj.text = assert.actual .. " != " .. assert.expected + elseif assert.type == 'error' then + obj.text = assert.error + end + + table.insert(qf, obj) end end end diff --git a/lua/acid/middlewares/virtualtext.lua b/lua/acid/middlewares/virtualtext.lua index 27cabf0..ae39aa7 100644 --- a/lua/acid/middlewares/virtualtext.lua +++ b/lua/acid/middlewares/virtualtext.lua @@ -1,50 +1,55 @@ -- luacheck: globals vim local virtualtext = {} +local forms = require("acid.forms") virtualtext.name = "virtualtext" -virtualtext.cache_index = {} -virtualtext.cache = {} - virtualtext.ns = vim.api.nvim_create_namespace("acid") virtualtext.toggle = function() local cb = vim.api.nvim_get_current_buf() - local ln = vim.api.nvim_call_function("line", {"."}) - 1 - local key = tostring(cb) .. "/" .. tostring(ln) + local coords = forms.get_form_boundaries(true) + local extmarks = vim.api.nvim_buf_get_extmarks(cb, virtualtext.ns, coords.from, coords.to, {details = true}) - local possible_vts = virtualtext.cache[key] - local current_ix = virtualtext.cache_index[key] + local nxt = extmarks[1] - if #possible_vts > 1 then - current_ix = current_ix - 1 - if current_ix == 0 then - current_ix = #possible_vts - end - end + nxt[4].priority = 10 + nxt[4].id = nxt[1] + + -- TODO fix + nxt[4].end_line = nxt[4].end_row + nxt[4].end_row = nil + + vim.api.nvim_buf_set_extmark( + 0, + virtualtext.ns, + nxt[2], + nxt[3] , + nxt[4] + ) - vim.api.nvim_buf_set_virtual_text(cb, virtualtext.ns, ln, possible_vts[current_ix], {}) - vim.api.nvim__buf_redraw_range(cb, ln, ln) - virtualtext.cache_index[key] = current_ix + + --if #possible_vts > 1 then + --current_ix = current_ix - 1 + --if current_ix == 0 then + --current_ix = #possible_vts + --end + --end + + --vim.api.nvim_buf_set_virtual_text(cb, virtualtext.ns, ln, possible_vts[current_ix], {}) + --vim.api.nvim__buf_redraw_range(cb, ln, ln) + --virtualtext.cache_index[key] = current_ix end virtualtext.middleware = function(config) return function(middleware) return function(data) - local cb = vim.api.nvim_get_current_buf() - local ln = config.to[1] - 1 - local key = tostring(cb) .. "/" .. tostring(ln) - if data.status then return end - if virtualtext.cache[key] == nil then - virtualtext.cache[key] = {} - end - local vt = {} if data.ex ~= nil then @@ -61,13 +66,21 @@ virtualtext.middleware = function(config) if #vt > 0 then table.insert(vt, 1, {";; => ", "Comment"}) - table.insert(virtualtext.cache[key], vt) - virtualtext.cache_index[key] = #virtualtext.cache[key] + vim.api.nvim_buf_set_extmark( + 0, + virtualtext.ns, + config.from[1] - 1, + config.from[2] - 1 , + { + end_line = config.to[1] - 1, + end_col = config.to[2] - 1, + virt_text = vt + }) -- TODO split_lines - vim.api.nvim_buf_set_virtual_text(cb, virtualtext.ns, ln, vt, {}) - vim.api.nvim__buf_redraw_range(cb, ln, ln) + --vim.api.nvim_buf_set_virtual_text(cb, virtualtext.ns, ln, vt, {}) + --vim.api.nvim__buf_redraw_range(cb, ln, ln) end return middleware(data) @@ -77,17 +90,12 @@ end virtualtext.clear = function(ln) local cb = vim.api.nvim_get_current_buf() - local to - local from + local from, to if ln ~= nil then - local key = tostring(cb) .. "/" .. tostring(ln) - ln = tonumber(ln) - 1 - virtualtext.cache[key] = {} from = ln to = ln + 1 else - virtualtext.cache = {} from = 0 to = -1 end diff --git a/lua/acid/nrepl.lua b/lua/acid/nrepl.lua index 9a751a4..c1b8775 100644 --- a/lua/acid/nrepl.lua +++ b/lua/acid/nrepl.lua @@ -2,7 +2,6 @@ --- nRepl connectivity -- @module acid.nrepl -local nvim = vim.api local log = require("acid.log") local utils = require("acid.utils") local connections = require("acid.connections") @@ -11,13 +10,15 @@ local output = require("acid.output") local job_mapping = {} local nrepl = {} +-- TODO Move to external resource +-- TODO Allow to be globally configurable local deps = { - ['nrepl/nrepl'] = '{:mvn/version "0.6.0"}', - ['org.clojure/clojurescript'] = '{:mvn/version "1.10.439"}', - ['cider/piggieback'] = '{:mvn/version "0.4.0"}', - ['cider/cider-nrepl'] = '{:mvn/version "0.24.0"}', - ['refactor-nrepl'] = '{:mvn/version "2.5.0"}', - ['iced-nrepl'] = '{:mvn/version "1.0.0"}' + ['nrepl/nrepl'] = '0.8.3', + ['org.clojure/clojurescript'] = '1.10.844', + ['cider/piggieback'] = '0.4.0', + ['cider/cider-nrepl'] = '0.26.0', + ['refactor-nrepl/refactor-nrepl'] = '2.5.1', + ['com.github.liquidz/iced-nrepl'] = '1.2.4' } --- List of supported middlewares and the wrappers to invoke when spawning a nrepl process. @@ -26,15 +27,15 @@ nrepl.middlewares = { ['nrepl/nrepl'] = {}, ['cider/cider-nrepl'] = {'cider.nrepl/cider-middleware'}, ['cider/piggieback'] = {'cider.piggieback/wrap-cljs-repl'}, - ['refactor-nrepl'] = {'refactor-nrepl.middleware/wrap-refactor'}, - ['iced-nrepl'] = {'iced.nrepl/wrap-iced'} + ['refactor-nrepl/refactor-nrepl'] = {'refactor-nrepl.middleware/wrap-refactor'}, + ['com.github.liquidz/iced-nrepl'] = {'iced.nrepl/wrap-iced'} } local get_deps = function(selected) return "{:deps {" .. table.concat( utils.map(selected, function(k) - return k .. " " .. deps[k] + return k .. " " .. '{:mvn/version "' .. deps[k] .. '"}' end) , ", " ) @@ -42,7 +43,7 @@ local get_deps = function(selected) end local supplied = function(fname) - return table.concat(vim.api.nvim_call_function("readfile", {fname}), "\n") + return table.concat(vim.fn.readfile(fname), "\n") end local build_cmd = function(obj) @@ -50,6 +51,7 @@ local build_cmd = function(obj) "clojure", "-Sdeps", get_deps(obj.selected), + "-M", "-m", "nrepl.cmdline", "--middleware", @@ -64,9 +66,8 @@ local build_cmd = function(obj) opts[3] = supplied(obj.deps_file) end - if obj.alias ~= nil then - table.insert(opts, 4, "-C" .. table.concat(obj.alias, "")) - table.insert(opts, 4, "-R" .. table.concat(obj.alias, "")) + if obj.alias ~= nil and #obj.alias > 0 then + table.insert(opts, 4, "-A" .. table.concat(obj.alias, "")) end if obj.port ~= nil then @@ -99,7 +100,7 @@ nrepl.default_middlewares = {'nrepl/nrepl', 'cider/cider-nrepl', 'refactor-nrepl -- @tparam[opt] boolean obj.disable_output_capture disables output capturing. -- @treturn boolean Whether it was possible to spawn a nrepl process nrepl.start = function(obj) - local pwd = utils.ensure_path(obj.pwd or vim.api.nvim_call_function("getcwd", {})) + local pwd = utils.ensure_path(obj.pwd or vim.fn.getcwd()) local selected = obj.middlewares or nrepl.default_middlewares local bind = obj.bind @@ -113,13 +114,43 @@ nrepl.start = function(obj) bind = bind or "127.0.0.1" - local ret = nvim.nvim_call_function('jobstart', { - cmd , { - on_stdout = "AcidJobHandler", - on_stderr = "AcidJobHandler", - on_exit = "AcidJobCleanup", - cwd = pwd - } + local first_err = true + + local ret = vim.fn.jobstart( + cmd, { + on_stdout = function(id, data, _) + local job = job_mapping[id] + + if not job.init then + for _, ln in ipairs(data) do + if string.sub(ln, 1, 20) == "nREPL server started" then + local port = ln:match("%d+") + connections.store[job.conn][2] = port + connections.select(job.pwd, job.conn) + job_mapping[id].init = true + if not nrepl.cache[job.pwd].skip_autocmd then + log.msg("Connected on port", tostring(port)) + vim.cmd[[doautocmd User AcidConnected]] + end + break + end + end + end + + nrepl.handle.stdout(data, id) + end, + on_stderr = function(id, data, _) + + if first_err then + print(vim.inspect(obj)) + first_err = false + end + + print(vim.inspect{error = data}) + nrepl.handle.stderr(data, id) + end, + on_exit = nrepl.cleanup, + cwd = pwd }) if ret <= 0 then @@ -148,29 +179,29 @@ nrepl.start = function(obj) end nrepl.bbnrepl = function(obj) - local pwd = utils.ensure_path(obj.pwd or vim.api.nvim_call_function("getcwd", {})) + obj.pwd = utils.ensure_path(obj.pwd or vim.fn.getcwd()) - obj.port = obj.port or "1667" + obj.port = obj.port or math.random(1024, 65535) local cmd = { "bb", "--nrepl-server", obj.port } - local ret = nvim.nvim_call_function('jobstart', { - cmd , { - on_exit = "AcidJobCleanup", - cwd = pwd + local ret = vim.fn.jobstart( + cmd, { + on_exit = nrepl.cleanup, + cwd = obj.pwd } - }) + ) - if ret <= 0 then + if ret < 0 then -- TODO log, inform.. return false end local conn = {"127.0.0.1", obj.port} - nrepl.cache[pwd] = { + nrepl.cache[obj.pwd] = { skip_autocmd = true, job = ret, addr = conn @@ -179,7 +210,7 @@ nrepl.bbnrepl = function(obj) local conn_id = connections.add(conn) connections.select(obj.pwd, conn_id) - nrepl.cache[pwd].id = conn_id + nrepl.cache[obj.pwd].id = conn_id end @@ -187,7 +218,7 @@ end -- @tparam table obj Configuration for the nrepl process to be stopped -- @tparam string obj.pwd Path where the nrepl process was started nrepl.stop = function(obj) - nvim.nvim_call_function("jobstop", {nrepl.cache[obj.pwd].job}) + vim.fn.jobstop(nrepl.cache[obj.pwd].job) connections.remove(nrepl.cache[obj.pwd].id) nrepl.cache[obj.pwd] = nil end @@ -207,25 +238,6 @@ nrepl.handle = { _store = {}, stdout = function(dt, ch) nrepl.handle._store[ch] = nrepl.handle._store[ch] or {} - local job = job_mapping[ch] - - if not job.init then - for _, ln in ipairs(dt) do - if string.sub(ln, 1, 20) == "nREPL server started" then - local port = ln:match("%d+") - connections.store[job.conn][2] = port - connections.select(job.pwd, job.conn) - job_mapping[ch].init = true - if not nrepl.cache[job.pwd].skip_autocmd then - log.msg("Connected on port", tostring(port)) - vim.api.nvim_command("doautocmd User AcidConnected") - end - break - end - end - end - - output.draw(job.conn, dt) table.insert(nrepl.handle._store[ch], dt) end, stderr = function(dt, ch) diff --git a/lua/acid/output.lua b/lua/acid/output.lua index 2209704..f63c43c 100644 --- a/lua/acid/output.lua +++ b/lua/acid/output.lua @@ -59,7 +59,7 @@ output.draw = function(conn, lines) local buf = output.conn_to_buf[conn] if type(lines) == "string" then - old = lines + local old = lines lines = {} old:gsub("[^\n]+", function(dt) table.insert(lines, dt) end) end @@ -71,10 +71,10 @@ output.draw = function(conn, lines) end -output.open = function() +output.open = function(opt) local conn = connections.peek() - output.window(conn) + output.window(conn, opt) end output.close = function() diff --git a/lua/acid/sessions.lua b/lua/acid/sessions.lua index 237045b..220c2fa 100644 --- a/lua/acid/sessions.lua +++ b/lua/acid/sessions.lua @@ -1,21 +1,12 @@ -- luacheck: globals vim local connections = require("acid.connections") local ops = require("acid.ops") -local utils = require("acid.utils") local core = require("acid.core") -local pwd_to_key = function(pwd) - if not utils.ends_with(pwd, "/") then - return pwd .. "/" - end - return pwd -end - local sessions = {} sessions.store = {} - sessions.register_session = function(connection_ix, session) if sessions.store[connection_ix] == nil then sessions.store[connection_ix] = { diff --git a/plugin/acid.vim b/plugin/acid.vim index c46a89a..a415bd5 100644 --- a/plugin/acid.vim +++ b/plugin/acid.vim @@ -61,8 +61,6 @@ function! AcidFnAddRequire(req) endfunction function! AcidCleanNs() - call search("(ns") - exec "normal vaf\" lua require("acid.features").clean_ns() endfunction @@ -94,10 +92,6 @@ function! AcidJobHandler(id, data, stream) call luaeval('require("acid.nrepl").handle[_A[1]](_A[2], _A[3])', [a:stream, a:data, a:id]) endfunction -function! AcidJobCleanup(id, data, _) - call luaeval('require("acid.nrepl").cleanup(_A[1])', [a:id]) -endfunction - map (acid-interrupt) lua require("acid.features").interrupt() map (acid-go-to) lua require("acid.features").go_to() @@ -114,6 +108,8 @@ map (acid-eval-expr) lua require("acid.features").eval_expr()< map (acid-eval-print) call AcidSendEval("eval_print") +map (acid-clear-ns) lua require("acid.features").clean_ns() + map (acid-replace-op) set opfunc=AcidEvalInplaceg@ map (acid-replace-symbol) call AcidEvalInplace("symbol") map (acid-replace-visual) call AcidEvalInplace("visual") @@ -136,9 +132,14 @@ map (acid-run-tests) lua require("acid.features").run_test{}(acid-run-tests-here) lua require("acid.features").run_test{['get-ns'] = true} map (acid-run-the-tests) lua require("acid.features").run_test{['get-symbol'] = true, ['get-ns'] = true} +map (acid-open-output-window) lua require("acid.output").open() +map (acid-clear-output-window) lua require("acid.output").clear() +map (acid-close-output-window) lua require("acid.output").close() + augroup acid autocmd! autocmd BufWritePost *.clj call require() + autocmd BufWritePost *.cljc call require() autocmd User AcidConnected lua require("acid.sessions").new_session() autocmd User AcidConnected lua require("acid.features").preload() @@ -179,6 +180,8 @@ if !g:acid_no_default_keymappings autocmd FileType clojure nmap crt (acid-replace-top-expr) autocmd FileType clojure nmap crr (acid-replace-expr) + autocmd FileType clojure map cl (acid-clear-ns) + autocmd FileType clojure map ll (acid-virtualtext-clear-line) autocmd FileType clojure map ln (acid-virtualtext-toggle) autocmd FileType clojure map la (acid-virtualtext-clear-all) @@ -186,6 +189,12 @@ if !g:acid_no_default_keymappings autocmd FileType clojure map oo (acid-output-open) autocmd FileType clojure map ox (acid-output-close) autocmd FileType clojure map ol (acid-output-clear) + + autocmd FileType clojure map coo (acid-open-output-window) + autocmd FileType clojure map col (acid-clear-output-window) + autocmd FileType clojure map coq (acid-close-output-window) + + augroup END endif diff --git a/rplugin/python3/acid/__init__.py b/rplugin/python3/acid/__init__.py index c5c1bf8..7d8fadb 100644 --- a/rplugin/python3/acid/__init__.py +++ b/rplugin/python3/acid/__init__.py @@ -105,6 +105,7 @@ def acid_alternate_file(self, args): def acid_new_file(self, args): ns = args[0] has_path = len(args) > 1 + log_debug("Args: {}", args) if not has_path: fname = "{}.clj".format(ns_to_path(ns)) base = 'test' if ns.endswith('-test') else 'src' @@ -113,6 +114,8 @@ def acid_new_file(self, args): else: path = args[1] + log_debug("path: {}", path) + if os.path.exists(path): log_debug("File already exists. Aborting.") return path