Regarding those I have a suggestion - maybe rename them so BQN stands out as a
prefix? I feel like this will make all BQN related commands more discoverable:
:BQNEvalTillLine
:BQNEvalRange
:BQNEvalFile
:BQNClearAfterLine
:BQNClearRange
:BQNClearFile
This commit makes nvim-bqn use virtual lines feature of neovim 0.6.0
show output of running BQN expressions.
The set of available command has changed, first we have the following
commands to eval BQN expressions:
:EvalBQNTillLine
:EvalBQNRange
:EvalBQNFile
and then a set of commands to clear output:
:ClearBQNAfterLine
:ClearBQNRange
:ClearBQNFile
There's one change to the mappings is that `<CR>` is not mapped to
`:EvalBQNTillLine` and thus it means it evaluates everything from the
start of the buffer till the line the cursor is at. This behaviour is
useful when you bindings defined above the cursor.
When rendering output the highlight group is used either `bqnoutok` or
`bqnouterr` depending on if the interpreter returned an error. By
default those groups are configured as:
hi link bqnoutok Comment
hi link bqnouterr Error
---
Ok, I think this is good now.
Regarding mappings — I didn't map "clearing output" commands to anything yet.
I was thinking of <C-CR> but then maybe it's useful to keep for the possible
future action "eval this expression and step to the next one". Your call here.
The issue of <C-CR> is that it cannot be reliably mapped. That was the
initial mapping I wanted to do for evaluating a whole file, but I did
not get it to map properly so I went for <C-Space> instead.
Following my suggestion above - probably `<leader>bef` - "BQN eval file" or
"<leader>bf" if this is needed really often (I found myself mostly using just
<CR>).
I think this is quite usable as-is, but I managed to run into some
annoying corner cases. I'll post those into the bug tracker later today.
In the meanwhile, I'll apply this commit into a branch called
virtual-lines.
ftplugin/bqn.vim | 2 +-lua/bqn.lua | 84 +++++++++++++++++++++++++++---------------------plugin/bqn.vim | 36 ++++++++++++++++++---
3 files changed, 80 insertions(+), 42 deletions(-)
diff --git a/ftplugin/bqn.vim b/ftplugin/bqn.vim
index 5721033..069cb05 100644
--- a/ftplugin/bqn.vim+++ b/ftplugin/bqn.vim
@@ -1,3 +1,3 @@
-nnoremap <buffer> <CR> :EvalBQNRange<CR>+nnoremap <buffer> <CR> :EvalBQNTillLine<CR>nnoremap <buffer> <C-Space> :EvalBQNFile<CR>
xnoremap <buffer> <CR> :EvalBQNRange<CR>
diff --git a/lua/bqn.lua b/lua/bqn.lua
index de733b3..33b95c8 100644
--- a/lua/bqn.lua+++ b/lua/bqn.lua
@@ -1,36 +1,28 @@
-local buf = nil-local win = nil+local ns = vim.api.nvim_create_namespace('bqnout')-local function check_buf()- if win == nil or not vim.api.nvim_win_is_valid(win) then- local prev = vim.api.nvim_get_current_win()- if buf == nil then- buf = vim.api.nvim_create_buf(false, false)- end- vim.api.nvim_buf_set_name(buf, "BQN")- vim.api.nvim_buf_set_option(buf, "buftype", "nofile")- vim.api.nvim_buf_set_option(buf, "swapfile", false)- vim.api.nvim_buf_set_option(buf, "modeline", false)- vim.cmd("below 3split")- vim.api.nvim_win_set_buf(vim.api.nvim_get_current_win(), buf)- win = vim.api.nvim_get_current_win()- vim.api.nvim_win_set_option(win, "wrap", false)- vim.api.nvim_set_current_win(prev)- elseif vim.api.nvim_win_is_valid(win) then- local winid = vim.api.nvim_eval("bufwinid(" .. buf .. ")")- if winid == -1 then- local prev = vim.api.nvim_get_current_win()- vim.cmd("below 3split")- vim.api.nvim_win_set_buf(vim.api.nvim_get_current_win(), buf)- win = vim.api.nvim_get_current_win()- vim.api.nvim_set_current_win(prev)- end- end+function clearBQN(from, to)+ vim.api.nvim_buf_clear_namespace(0, ns, from, to)end
function evalBQN(from, to, pretty)
- local code = vim.api.nvim_buf_get_lines(0, from - 1, to, true)+ if to < 0 then+ to = vim.api.nvim_buf_line_count(0) + to + 1+ end+ -- Compute `to` position by looking back till we find first non-empty line.+ while to > 0 do+ local line = vim.api.nvim_buf_get_lines(0, to - 1, to, true)[1]+ if #line ~= 0 and line:find("^%s*#") == nil then break end+ to = to - 1+ end++ if from > to then+ from = to+ end+ to = math.max(to, 1)+ from = math.max(from, 0)++ local code = vim.api.nvim_buf_get_lines(0, from, to, true) local program = ""
for k, v in ipairs(code) do
program = program .. v .. "\n"
@@ -49,25 +41,43 @@ function evalBQN(from, to, pretty)
if not found then
bqn = "BQN"
end
-- local executable = assert(io.popen(bqn .. " -" .. flag .. " \"" .. program .. "\""))+ local cmd = bqn .. " -" .. flag .. " \"" .. program .. "\""+ local executable = assert(io.popen(cmd)) local output = executable:read('*all')
- executable:close()-- check_buf() local lines = {}
local line_count = 0
+ local is_error = nil for line in output:gmatch("[^\n]+") do
- table.insert(lines, line)+ if is_error == nil then+ is_error = line:find("^Error:") ~= nil+ end+ local hl = 'bqnoutok'+ if is_error then hl = 'bqnouterr' end+ table.insert(lines, {{' ' .. line, hl}}) line_count = line_count + 1
end
+ table.insert(lines, {{' ', 'bqnoutok'}})++ -- Compute `cto` (clear to) position by looking forward from `to` till we+ -- find first non-empty line. We do this so we clear all "orphaned" virtual+ -- line blocks (which correspond to already deleted lines).+ local total_lines = vim.api.nvim_buf_line_count(0)+ local cto = to+ while cto < total_lines do+ local line = vim.api.nvim_buf_get_lines(0, cto, cto + 1, true)[1]+ if #line ~= 0 and line:find("^%s*#") == nil then break end+ cto = cto + 1+ end- vim.api.nvim_buf_set_lines(buf, -1, -1, false, lines)- vim.api.nvim_win_set_height(win, line_count)- vim.api.nvim_win_set_cursor(win, {vim.api.nvim_buf_line_count(buf), 0})+ vim.api.nvim_buf_clear_namespace(0, ns, to - 1, cto)+ vim.api.nvim_buf_set_extmark(0, ns, to - 1, 0, {+ end_line = to - 1,+ virt_lines=lines+ })end
return {
evalBQN = evalBQN,
+ clearBQN = clearBQN,}
diff --git a/plugin/bqn.vim b/plugin/bqn.vim
index e87288d..9c84e58 100644
--- a/plugin/bqn.vim+++ b/plugin/bqn.vim
@@ -1,6 +1,34 @@
-function! EvalBQNWrapper() range- return luaeval('require("bqn").evalBQN(_A[1], _A[2], true)', [a:firstline, a:lastline])+function! EvalBQNTillLine()+ return luaeval(+ \ 'require("bqn").evalBQN(0, _A[1], true)',+ \ [line(".")])endfunction
-command! -range EvalBQNRange <line1>,<line2>call EvalBQNWrapper()-command! EvalBQNFile :lua require("bqn").evalBQN(1, -1, false)+function! EvalBQNRange() range+ return luaeval(+ \ 'require("bqn").evalBQN(_A[1] - 1, _A[2], true)',+ \ [a:firstline, a:lastline])+endfunction++function! ClearBQNAfterLine()+ return luaeval(+ \ 'require("bqn").clearBQN(_A[1] - 1, -1)',+ \ [line(".")])+endfunction++function! ClearBQNRange()+ return luaeval(+ \ 'require("bqn").clearBQN(_A[1] - 1, _A[2])',+ \ [a:firstline, a:lastline])+endfunction++hi link bqnoutok Comment+hi link bqnouterr Error++command! EvalBQNTillLine call EvalBQNTillLine()+command! -range EvalBQNRange <line1>,<line2>call EvalBQNRange()+command! EvalBQNFile :lua require("bqn").evalBQN(0, -1, true)++command! ClearBQNAfterLine call ClearBQNAfterLine()+command! -range ClearBQNRange <line1>,<line2>call ClearBQNRange()+command! ClearBQNFile :lua require("bqn").clearBQN(0, -1)
--
2.30.2