all repos

viye @ 3fb8292

my shot at reimplementing xiki

viye/lua/viye.lua (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
init, 2 months ago
1
local M = {}
2
3
local function indent(text) return #text:match "^%s*" end
4
local function is_data(text) return text:find "^%s*[|:] " ~= nil end
5
local function strip_bullet(text) return (text:gsub("^[+-] ", "", 1)) end
6
7
local function build_path()
8
  local lnum = vim.fn.line "."
9
  local line = vim.fn.getline(lnum)
10
  local depth = indent(line)
11
  local parts = { strip_bullet(vim.trim(line)) }
12
13
  local i = lnum - 1
14
  while i >= 1 do
15
    local l = vim.fn.getline(i)
16
    local d = indent(l)
17
    if d == 0 and l:find "%S" and depth > 0 then
18
      table.insert(parts, 1, strip_bullet(vim.trim(l)))
19
      break
20
    end
21
    if d < depth and l:find "%S" then
22
      table.insert(parts, 1, strip_bullet(vim.trim(l)))
23
      depth = d
24
    end
25
    i = i - 1
26
  end
27
28
  for idx = 1, #parts - 1 do
29
    parts[idx] = parts[idx]:gsub("/+$", "")
30
  end
31
32
  return table.concat(parts, "/")
33
end
34
35
local function has_children()
36
  local lnum = vim.fn.line "."
37
  local depth = indent(vim.fn.getline(lnum))
38
  local next_line = vim.fn.getline(lnum + 1)
39
  return next_line ~= "" and indent(next_line) > depth
40
end
41
42
local function collapse()
43
  local lnum = vim.fn.line "."
44
  local depth = indent(vim.fn.getline(lnum))
45
  local s = lnum + 1
46
  local e = s
47
  while e <= vim.fn.line "$" do
48
    local l = vim.fn.getline(e)
49
    if l == "" or indent(l) <= depth then break end
50
    e = e + 1
51
  end
52
  if e > s then vim.cmd(string.format("%d,%ddelete _", s, e - 1)) end
53
end
54
55
local function toggle_bullet()
56
  local lnum = vim.fn.line "."
57
  local line = vim.fn.getline(lnum)
58
  local toggled = line:gsub("^%+ ", "- ", 1)
59
  if toggled ~= line then
60
    vim.fn.setline(lnum, toggled)
61
    return
62
  end
63
  toggled = line:gsub("^%- ", "+ ", 1)
64
  if toggled ~= line then vim.fn.setline(lnum, toggled) end
65
end
66
67
local function insert_output(output)
68
  local lnum = vim.fn.line "."
69
  local pad = string.rep(" ", indent(vim.fn.getline(lnum)) + 2)
70
  local lines = vim.split(output, "\n", { trimempty = true })
71
  for i, line in ipairs(lines) do lines[i] = pad .. line end
72
  vim.fn.append(lnum, lines)
73
end
74
75
local function exec()
76
  local line = vim.fn.getline "."
77
  if is_data(line) then
78
    local lnum = vim.fn.line "."
79
    local depth = indent(line)
80
    local i = lnum - 1
81
    while i >= 1 do
82
      local l = vim.fn.getline(i)
83
      if not is_data(l) and indent(l) < depth and l:find "%S" then
84
        vim.fn.cursor(i, 1)
85
        exec()
86
        return
87
      end
88
      i = i - 1
89
    end
90
    return
91
  end
92
93
  if has_children() then
94
    collapse()
95
    toggle_bullet()
96
    return
97
  end
98
99
  local path = build_path()
100
  if path == "" then return end
101
102
  local cmd = "viye " .. vim.fn.shellescape(path)
103
  vim.notify("viye: " .. cmd, vim.log.levels.INFO)
104
105
  local out = vim.fn.system(cmd)
106
  if vim.v.shell_error ~= 0 then
107
    vim.notify("viye: " .. out:gsub("\n$", ""), vim.log.levels.ERROR)
108
    return
109
  end
110
111
  if out ~= "" then
112
    insert_output(out)
113
    toggle_bullet()
114
  end
115
end
116
117
function M.setup()
118
  vim.filetype.add { extension = { viye = "viye" } }
119
  vim.api.nvim_create_autocmd("FileType", {
120
    pattern = "viye",
121
    group = vim.api.nvim_create_augroup("viye_plugin", { clear = true }),
122
    callback = function() vim.keymap.set("n", "<CR>", exec, { buffer = true, silent = true }) end,
123
  })
124
end
125
126
return M