-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathForBash.lua
More file actions
207 lines (184 loc) · 6.49 KB
/
Copy pathForBash.lua
File metadata and controls
207 lines (184 loc) · 6.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
---@mod buffls.ForBash BuffLS for Bash buffer
local util = require'buffls.util'
local BufflsTsLs = require'buffls.TsLs'
---An extension to |BufflsTsLs| for working with with Bash buffers.
---
---Create and register instances of with `for_buffer` like you would a
---|BufflsTsLs|.
---@class BufflsForBash: BufflsTsLs
---@field package arg_completers (fun(ctx: table): table)[]
---@field package flags table
local BufflsForBash = setmetatable({}, {__index = BufflsTsLs})
---@private
BufflsForBash.__index = BufflsForBash
---@param completer fun(ctx: table): table?
function BufflsForBash:add_cli_arg(completer)
table.insert(self.arg_completers, completer)
end
---Add completion for a flag.
---
---The flag name(s) must be given together with the preceding `-` or `--`. The
---argument can be:
---- Omitted for argumentless flags.
---- A list of possible flags.
---- A function that returns a list of possible flags.
---For the list/function, each flag must either be a string or an LSP
---completion item.
---@param flag string|string[] the name of the flag. Table for multiple names
---@param args? (string|table)[]|function the options for flag arguments
function BufflsForBash:add_flag(flag, args)
if type(flag) == 'string' then
flag = {flag}
end
local flag_value
if args == nil then
flag_value = false
elseif vim.is_callable(args) then
flag_value = args
elseif vim.islist(args) then
flag_value = function()
return args
end
else
error('Illegal value for `args`')
end
for _, flag_name in ipairs(flag) do
self.flags[flag_name] = flag_value
end
end
local bash_word_query = vim.treesitter.query.parse('bash', '(word) @_')
local function find_range_of_real_word_for_completion(ctx)
for _, node in bash_word_query:iter_captures(ctx.tstree:root(), ctx.params.bufnr) do
if ctx:is_node_in_range(node) then
local sr, sc = node:range()
return sr, sc
end
end
return nil
end
local function find_real_word_for_completion(ctx)
local sr, sc = find_range_of_real_word_for_completion(ctx)
if sr then
return table.concat(vim.api.nvim_buf_get_text(ctx.params.bufnr, sr, sc, ctx.params.row - 1, ctx.params.col, {}), '\n')
else
return ''
end
end
local function normalize_completion(completion)
if type(completion) == 'string' then
return {label = completion}
else
return completion
end
end
---@param bufnr? integer the buffer number. Leave empty for current buffer.
---@return BufflsForBash
function BufflsForBash:for_buffer(bufnr)
bufnr = bufnr or 0
if vim.api.nvim_get_option_value('filetype', {buf = bufnr}) == '' then
vim.api.nvim_set_option_value('filetype', 'bash', {buf = bufnr})
end
if self.__index == self then
self = self:new()
end
vim.api.nvim_buf_set_var(bufnr, 'buffls', function() return self end)
return self
end
---@return BufflsForBash
function BufflsForBash:new()
local ls = setmetatable(BufflsTsLs:new('bash'), self)
ls.arg_completers = {}
ls.flags = {}
ls:add_completions_direct_generator(function(ctx)
local range = util.normalize_range(ctx.params)
local previous_args = {}
local relevant_arg
for _, node in bash_word_query:iter_captures(ctx.tstree:root(), ctx.params.bufnr) do
local sr, sc, er, ec = node:range()
sr = sr + 1
sc = sc + 1
er = er + 1
ec = ec + 1
if range.end_row < sr then
break
end
if range.end_row == sr then
if range.end_col < sc then
break
elseif range.col < ec then
relevant_arg = table.concat(vim.api.nvim_buf_get_text(ctx.params.bufnr, sr - 1, sc - 1, er - 1, range.col, {}), '\n')
break
end
end
local arg_text = table.concat(vim.api.nvim_buf_get_text(ctx.params.bufnr, sr - 1, sc - 1, er - 1, ec -1 , {}), '\n')
table.insert(previous_args, arg_text)
end
local ctx_for_completer = vim.tbl_extend("error", {
arg = relevant_arg,
previous_args = previous_args,
}, ctx)
local result = {}
for _, completer in ipairs(ls.arg_completers) do
local completions = completer(ctx_for_completer)
if completions then
vim.list_extend(result, vim.iter(completions):map(normalize_completion):totable())
end
end
return result
end)
ls:add_completions_ts_generator('((word) @flag (#match? @flag "^-")) @HERE', function(ctx)
local result = {}
local real_word = find_real_word_for_completion(ctx)
local real_word_start_row, real_word_start_col = find_range_of_real_word_for_completion(ctx)
for flag in pairs(ls.flags) do
local textEdit = nil
if real_word_start_row then
textEdit = {
newText = flag,
insert = {
start = {
line = real_word_start_row,
character = real_word_start_col,
},
['end'] = {
line = ctx.params.row - 1,
character = ctx.params.col,
},
},
}
end
table.insert(result, {
label = flag,
textEdit = textEdit,
})
end
return result
end)
ls:add_completions_ts_generator('((word) @flag (#match? @flag "^-")) @AFTER_HERE', function(ctx)
local flag_args = ls.flags[ctx:text('flag')]
if not flag_args then
return
end
local real_word = find_real_word_for_completion(ctx)
local ctx_for_completer = vim.tbl_extend("error", {
param_arg = real_word,
}, ctx)
local possible_args = flag_args(ctx_for_completer)
if not possible_args then
return
end
local result = {}
for _, item in ipairs(possible_args) do
if type(item) == 'string' then
if vim.startswith(item, real_word) then
table.insert(result, {label=item})
end
else
table.insert(result, item)
end
end
return result
end)
return ls
end
return BufflsForBash