Sending code to a multiplexer

🧭

This example sends code to Zellij (see Zellij).

Sending code to Zellij

Code

The code is a simple minimum working example:

 local M = {} -- define a table to hold our module
 
 
 
---Run a shell command and capture the output
---@param cmd string
---@return string
local function shell(cmd)
  print(cmd)
  local handle = io.popen(cmd)
  if handle == nil then
    print("Failed to run the command.")
  else
    local output = handle:read("*a")
    handle:close()
    return output
  end
end
 
local function get_zellij_sessions()
  local zellij_out = shell("zellij list-sessions -n")
  -- Split into a table
  local sessions = vim.split(zellij_out, "\n")
  -- Remove empty lines
  sessions = vim.tbl_filter(function(line)
    local allowed = true
    allowed = allowed and line ~= ""
    return line ~= ""
  end, sessions)
  -- Remove all text before first space
  for i, line in ipairs(sessions) do
    sessions[i] = vim.split(line, " ")[1]
  end
  -- print(vim.inspect(out))
  return sessions
end
 
local function session_exists(session)
  local sessions = get_zellij_sessions()
  for _, s in ipairs(sessions) do
    if s == session then
      return true
    end
  end
  return false
end
 
local function create_session_if_needed(session)
  if not session_exists(session) then
    shell("zellij -s " .. session)
  end
end
 
local function zellij_write_chars_cmd(session, text)
  return "zellij -s " .. session .. " action write-chars " .. [[']] .. text .. [[']]
end
 
local function escape_single_quotes(text)
  return text:gsub("'", "'\\''")
end
 
local function escape(text)
  local out = escape_single_quotes(text)
  return out
end
 
local function zellij_send(session, text)
  local text_to_send = escape(text) .. "\n"
  create_session_if_needed(session)
  shell(zellij_write_chars_cmd(session, text_to_send))
end
 
local function zellij_send_range(session, start, stop)
  local buf = vim.api.nvim_get_current_buf()
  local lines = vim.api.nvim_buf_get_lines(buf, start, stop, false)
  -- join the lines by newline
  local text = table.concat(lines, "\n")
  zellij_send(session, text)
end
 
local function zellij_send_line(session)
  local line = vim.api.nvim_get_current_line()
  zellij_send(session, line)
end
 
local function zellij_send_selection(session)
  local start = vim.fn.getpos("'<")[2] - 1
  local stop = vim.fn.getpos("'>")[2] - 1
  zellij_send_range(session, start, stop)
end
 
-- Define the function we want to export
function M.Zellij_send_range(session, start, stop)
  zellij_send_range(session, start, stop)
end
 
function M.Zellij_send_line(session)
  zellij_send_line(session)
end
 
function M.Zellij_send_selection(session)
  zellij_send_selection(session)
end
 
-- Return the module table so that it can be required by other scripts
return M
 
 

Using that

Write a function to detect markdown cells

local function get_start_line_of_cell_at_cursor()
  local api = vim.api
  local buf = api.nvim_get_current_buf()
  local lines = api.nvim_buf_get_lines(buf, 0, -1, false)
  local current_location = api.nvim_win_get_cursor(0)
  local current_line = current_location[1]
  local lang = nil
  local context_path = "nvim_my_babel_context"
  local cell_path = "nvim_my_babel_cell"
  local start_line, end_line = nil, nil
 
  -- Loop backwards for the start of the code block
  for i = current_line, 1, -1 do
    local line = lines[i]
    if line:match("^```") then
      start_line = i + 1 -- Don't include fence
      lang = get_lang(line)
      break
    end
  end
 
  -- Search forward for the end of the code block
  for i = current_line, #lines do
    if lines[i]:match("^```") then
      end_line = i - 1 -- don't include fence
      break
    end
  end
 
  return { start_line = start_line, end_line = end_line, lang = lang }
end
 
function M.zellij_send_markdown_cell()
  local current_cell = get_start_line_of_cell_at_cursor()
  local first_line_num = current_cell.start_line
  local last_line_num = current_cell.end_line
  local lang = current_cell.lang
  require('utils/send_code_zellij').Zellij_send_range(lang, first_line_num-1, last_line_num)
end

Create an autocommand to set a keybinding

vim.api.nvim_create_autocmd({ 'FileType' }, {
  pattern = 'markdown',
  callback = function()
    map('n', '<M-S-CR>', '',
      {
        -- callback = require("utils/markdown_babel").send_slime_markdown_cell,
        callback = require("utils/markdown_babel").zellij_send_markdown_cell,
        noremap = true,
        silent = true,
        desc =
        "Use Treesitter to Insert a Markdown Heading of the right level"
      })
    })
 

Do it

Now open up a markdown file, hover over a cell and use the keybinding.