|
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 |