~detegr/nvim-bqn

Use virtual lines to show output v2 APPLIED

Andrey Popp: 1
 Use virtual lines to show output

 3 files changed, 80 insertions(+), 42 deletions(-)
Hi,
Next
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
Next
Hi.
Next
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~detegr/nvim-bqn/patches/27101/mbox | git am -3
Learn more about email & git

[PATCH v2] Use virtual lines to show output Export this patch

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.
I also want to point out that <C-Space> mapping is a bit problematic for macOS
users and by default <C-Space> changes keyboard layout in macOS.
 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