all repos

viye @ 896d55427eac536be9d99d6c941215e4bf165ac1

my shot at reimplementing xiki

viye/plugin/viye.lua (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
fix splitLeaf; add some tests; move some code around, 1 month ago
1
local function indent(t) return #t:match("^%s*") end
2
local function line_type(line)
3
  if not line:find("%S") then return "empty" end
4
  return line:find("^%s*[|:]") and "data" or "node"
5
end
6
7
local function children_of(cmd_lnum)
8
  local depth = indent(vim.fn.getline(cmd_lnum))
9
  local first, last = cmd_lnum + 1, nil
10
  for i = first, vim.fn.line("$") do
11
    local l = vim.fn.getline(i)
12
    if l == "" or indent(l) <= depth then break end
13
    last = i
14
  end
15
  return first, last
16
end
17
18
local function parent_of(lnum)
19
  local d = indent(vim.fn.getline(lnum))
20
  for i = lnum - 1, 1, -1 do
21
    local l = vim.fn.getline(i)
22
    if line_type(l) == "node" and indent(l) < d then return i end
23
  end
24
  return nil
25
end
26
27
local function ancestors(cmd_lnum)
28
  local parts = {}
29
  local lnum = cmd_lnum
30
  while lnum do
31
    local l = vim.fn.getline(lnum)
32
    local line = l:match("^%s*[+-] (.*)") or vim.trim(l)
33
    local words = vim.split(line, "%s+")
34
    for i = #words, 1, -1 do table.insert(parts, 1, words[i]) end
35
    lnum = parent_of(lnum)
36
  end
37
  return parts
38
end
39
40
local function body_of(cmd_lnum)
41
  local depth = indent(vim.fn.getline(cmd_lnum))
42
  local first, last = children_of(cmd_lnum)
43
  local body = {}
44
  if last then
45
    for i = first, last do
46
      local l = vim.fn.getline(i)
47
      local val = indent(l) == depth + 2 and l:match("^%s*: (.*)")
48
      if val then table.insert(body, ": " .. val) end
49
    end
50
  end
51
  return body
52
end
53
54
local function run(cmd_lnum)
55
  local cmd = ancestors(cmd_lnum)
56
  if #cmd == 0 then return end
57
  table.insert(cmd, 1, "viye")
58
59
  local body = body_of(cmd_lnum)
60
  if #body > 0 then vim.list_extend(vim.list_extend(cmd, { "--" }), body) end
61
62
  local res = vim.system(cmd, { text = true }):wait(2000)
63
  if res.code ~= 0 then
64
    vim.notify(vim.trim(res.stderr), vim.log.levels.ERROR)
65
    return
66
  end
67
  return res.stdout
68
end
69
70
local function insert_output(cmd_lnum, out)
71
  local pad = string.rep(" ", indent(vim.fn.getline(cmd_lnum)) + 2)
72
  local lines = vim.split(out, "\n", { trimempty = true })
73
  for i, l in ipairs(lines) do
74
    lines[i] = pad .. l
75
  end
76
  vim.fn.append(cmd_lnum, lines)
77
end
78
79
local function toggle_bullet(cmd_lnum)
80
  vim.fn.setline(cmd_lnum, (vim.fn.getline(cmd_lnum):gsub("^[+-] ", function(c)
81
    return c == "+" and "-" or "+"
82
  end, 1)))
83
end
84
85
local function exec()
86
  local lnum = vim.fn.line(".")
87
  local line = vim.fn.getline(lnum)
88
  local cmd_lnum = line_type(line) == "data" and parent_of(lnum) or lnum
89
  if not cmd_lnum then return end
90
  local first, last = children_of(cmd_lnum)
91
  local has_children = last ~= nil
92
  local on_cmd = cmd_lnum == lnum
93
  if on_cmd and not has_children then
94
    return
95
  end
96
  local out = run(cmd_lnum)
97
  if not out then return end
98
  if last then vim.cmd(string.format("%d,%ddelete _", first, last)) end
99
  if out ~= "" then insert_output(cmd_lnum, out) end
100
  toggle_bullet(cmd_lnum)
101
end
102
103
vim.filetype.add { extension = { viye = "viye" } }
104
local group = vim.api.nvim_create_augroup("viye", { clear = true })
105
vim.api.nvim_create_autocmd("BufEnter", {
106
  pattern = "*",
107
  group = group,
108
  callback = function()
109
    if vim.api.nvim_buf_get_name(0) == "" then
110
      vim.bo.filetype = "viye"
111
    end
112
  end,
113
})
114
vim.api.nvim_create_autocmd("FileType", {
115
  pattern = "viye",
116
  group = group,
117
  callback = function()
118
    vim.keymap.set("n", "<CR>", exec, { buffer = true, silent = true })
119
  end,
120
})