forked from nvim-java/nvim-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrunner.lua
More file actions
362 lines (320 loc) · 9.09 KB
/
runner.lua
File metadata and controls
362 lines (320 loc) · 9.09 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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
local log = require('java.utils.log')
local async = require('java-core.utils.async').sync
local get_error_handler = require('java.handlers.error')
local jdtls = require('java.utils.jdtls')
local DapSetup = require('java-dap.api.setup')
local ui = require('java.utils.ui')
local profile_config = require('java.api.profile_config')
local class = require('java-core.utils.class')
local group = vim.api.nvim_create_augroup('logger', { clear = true })
--- @class RunnerApi
--- @field client LspClient
--- @field private dap java.DapSetup
local RunnerApi = class()
function RunnerApi:_init(args)
self.client = args.client
self.dap = DapSetup(args.client)
end
function RunnerApi:get_config()
local configs = self.dap:get_dap_config()
return ui.select_from_dap_configs(configs)
end
--- @param callback fun(cmd, config)
--- @param args string
function RunnerApi:run_app(callback, args)
local config = self:get_config()
if not config then
return
end
config.request = 'launch'
local enrich_config = self.dap:enrich_config(config)
local class_paths = table.concat(enrich_config.classPaths, ':')
local main_class = enrich_config.mainClass
local java_exec = enrich_config.javaExec
local active_profile =
profile_config.get_active_profile(enrich_config.mainClass)
local vm_args = ''
local prog_args = ''
if active_profile then
prog_args = (active_profile.prog_args or '') .. ' ' .. (args or '')
vm_args = active_profile.vm_args or ''
end
local cmd = {
java_exec,
vm_args,
'-cp',
class_paths,
main_class,
prog_args,
}
log.debug('run app cmd: ', cmd)
callback(cmd, config)
end
--- @class RunningApp
--- @field win number
--- @field bufnr number
--- @field job_id number
--- @field chan number
--- @field dap_config table
--- @field is_open boolean
--- @field running_status string
local RunningApp = class()
--- @param dap_config table
function RunningApp:_init(dap_config)
self.is_open = false
self.dap_config = dap_config
self.bufnr = vim.api.nvim_create_buf(false, true)
end
--- @class BuiltInMainRunner
--- @field running_apps table<string, RunningApp>
--- @field current_app RunningApp
local BuiltInMainRunner = class()
function BuiltInMainRunner:_init()
self.running_apps = {}
self.current_app = nil
end
--- @param running_app RunningApp
function BuiltInMainRunner.set_up_buffer_autocmd(running_app)
vim.api.nvim_create_autocmd({ 'BufHidden' }, {
group = group,
buffer = running_app.bufnr,
callback = function(_)
running_app.is_open = false
end,
})
end
--- @param running_app RunningApp
function BuiltInMainRunner.stop(running_app)
if running_app.job_id ~= nil then
vim.fn.jobstop(running_app.job_id)
vim.fn.jobwait({ running_app.job_id }, 1000)
running_app.job_id = nil
end
end
--- @param running_app RunningApp
function BuiltInMainRunner.set_up_buffer(running_app)
vim.cmd('sp | winc J | res 15 | buffer ' .. running_app.bufnr)
running_app.win = vim.api.nvim_get_current_win()
vim.wo[running_app.win].number = false
vim.wo[running_app.win].relativenumber = false
vim.wo[running_app.win].signcolumn = 'no'
BuiltInMainRunner.set_up_buffer_autocmd(running_app)
running_app.is_open = true
end
--- @param exit_code number
--- @param running_app RunningApp
function BuiltInMainRunner.on_exit(exit_code, running_app)
local exit_message = 'Process finished with exit code ' .. exit_code
vim.fn.chansend(running_app.chan, '\n' .. exit_message .. '\n')
local current_buf = vim.api.nvim_get_current_buf()
if current_buf == running_app.bufnr then
vim.cmd('stopinsert')
end
vim.notify(running_app.dap_config.name .. ' ' .. exit_message)
running_app.running_status = exit_message
end
--- @param running_app RunningApp
function BuiltInMainRunner.scroll_down(running_app)
local last_line = vim.api.nvim_buf_line_count(running_app.bufnr)
vim.api.nvim_win_set_cursor(running_app.win, { last_line, 0 })
end
--- @param running_app RunningApp
function BuiltInMainRunner.hide_logs(running_app)
if not running_app or not running_app.is_open then
return
end
if running_app.bufnr then
vim.api.nvim_buf_call(running_app.bufnr, function()
vim.cmd('hide')
end)
end
end
--- @param running_app RunningApp
function BuiltInMainRunner.toggle_logs(running_app)
if running_app and not running_app.is_open then
vim.api.nvim_buf_call(running_app.bufnr, function()
BuiltInMainRunner.set_up_buffer(running_app)
BuiltInMainRunner.scroll_down(running_app)
end)
else
BuiltInMainRunner.hide_logs(running_app)
end
end
function BuiltInMainRunner:toggle_current_app_logs()
local running_app = self.current_app
if not running_app then
return
end
BuiltInMainRunner.toggle_logs(running_app)
end
--- @param data string[]
--- @param running_app RunningApp
function BuiltInMainRunner.on_stdout(data, running_app)
vim.fn.chansend(running_app.chan, data)
if not running_app.is_open then
return
end
vim.api.nvim_buf_call(running_app.bufnr, function()
local current_buf = vim.api.nvim_get_current_buf()
local mode = vim.api.nvim_get_mode().mode
if current_buf ~= running_app.bufnr or mode ~= 'i' then
BuiltInMainRunner.scroll_down(running_app)
end
end)
end
--- @param cmd string[]
--- @param config table
function BuiltInMainRunner:run_app(cmd, config)
local selected_app = self:select_app_with_dap_config(config)
if self.current_app then
if self.current_app.job_id == selected_app.job_id then
BuiltInMainRunner.stop(selected_app)
end
end
self:change_current_app(selected_app)
if not selected_app.is_open or not selected_app.chan then
vim.api.nvim_buf_call(selected_app.bufnr, function()
BuiltInMainRunner.set_up_buffer(selected_app)
BuiltInMainRunner.scroll_down(selected_app)
end)
vim.api.nvim_buf_set_name(selected_app.bufnr, selected_app.dap_config.name)
end
selected_app.chan = vim.api.nvim_open_term(selected_app.bufnr, {
on_input = function(_, _, _, data)
if selected_app.job_id then
vim.fn.chansend(selected_app.job_id, data)
end
end,
})
selected_app.running_status = '(running)'
local command = table.concat(cmd, ' ')
vim.fn.chansend(selected_app.chan, command)
selected_app.job_id = vim.fn.jobstart(command, {
pty = true,
on_stdout = function(_, data)
BuiltInMainRunner.on_stdout(data, selected_app)
end,
on_exit = function(_, exit_code)
BuiltInMainRunner.on_exit(exit_code, selected_app)
end,
})
end
--- @return RunningApp|nil
function BuiltInMainRunner:select_app_with_ui()
--- @type RunningApp
local app = nil
local count = 0
for _ in pairs(self.running_apps) do
count = count + 1
end
if count == 0 then
error('No running apps')
elseif count == 1 then
for _, _app in pairs(self.running_apps) do
app = _app
end
else
local configs = {}
for _, _app in pairs(self.running_apps) do
_app.dap_config.extra_args = _app.running_status
table.insert(configs, _app.dap_config)
end
local selected = ui.select_from_dap_configs(configs)
if not selected then
return nil
end
app = self.running_apps[selected.mainClass]
end
self:change_current_app(app)
return app
end
--- @param app RunningApp
function BuiltInMainRunner:change_current_app(app)
if
self.current_app
and self.current_app.dap_config.name ~= app.dap_config.name
then
BuiltInMainRunner.hide_logs(self.current_app)
end
self.current_app = app
end
--- @param config table|nil
--- @return RunningApp
function BuiltInMainRunner:select_app_with_dap_config(config)
--- @type RunningApp
if not config then
error('No config')
end
if self.running_apps and self.running_apps[config.mainClass] then
return self.running_apps[config.mainClass]
end
local running_app = RunningApp(config)
self.running_apps[running_app.dap_config.mainClass] = running_app
return running_app
end
function BuiltInMainRunner:switch_app()
local selected_app = self:select_app_with_ui()
if not selected_app then
return
end
if not selected_app.is_open then
BuiltInMainRunner.toggle_logs(selected_app)
end
end
function BuiltInMainRunner:stop_app()
local selected_app = self:select_app_with_ui()
if not selected_app then
return
end
BuiltInMainRunner.stop(selected_app)
BuiltInMainRunner.toggle_logs(selected_app)
end
local M = {
built_in = {},
--- @type BuiltInMainRunner
runner = BuiltInMainRunner(),
}
--- @param callback fun(cmd, config)
--- @param args string
function M.run_app(callback, args)
return async(function()
return RunnerApi(jdtls()):run_app(callback, args)
end)
.catch(get_error_handler('failed to run app'))
.run()
end
--- @param opts {}
function M.built_in.run_app(opts)
async(function()
M.run_app(function(cmd, config)
M.runner:run_app(cmd, config)
end, opts.args)
end)
.catch(get_error_handler('failed to run app'))
.run()
end
function M.built_in.toggle_logs()
async(function()
M.runner:toggle_current_app_logs()
end)
.catch(get_error_handler('failed to toggle logs'))
.run()
end
function M.built_in.switch_app()
async(function()
M.runner:switch_app()
end)
.catch(get_error_handler('failed to switch app'))
.run()
end
function M.built_in.stop_app()
async(function()
M.runner:stop_app()
end)
.catch(get_error_handler('failed to stop app'))
.run()
end
M.RunnerApi = RunnerApi
M.BuiltInMainRunner = BuiltInMainRunner
M.RunningApp = RunningApp
return M