@@ -9,6 +9,7 @@ let s:run_last_command = get(s:, 'run_last_command', '')
9
9
let s: run_last_options = get (s: , ' run_last_options' , {})
10
10
let s: run_killall_ongoing = get (s: , ' run_killall_ongoing' , 0 )
11
11
let s: run_timestamp_format = get (s: , ' run_timestamp_format' , ' %Y-%m-%d %H:%M:%S' )
12
+ let s: run_jobs_to_kill_nvim = get (s: , ' run_jobs_to_kill_nvim' , [])
12
13
13
14
let s: run_edit_path = get (s: , ' run_edit_path' )
14
15
let s: run_edit_cmd_ongoing = get (s: , ' run_edit_cmd_ongoing' , 0 )
@@ -30,11 +31,15 @@ augroup RunCmdBufInput
30
31
let rundirglob = g: rundir . ' /*.log'
31
32
32
33
autocmd !
33
- exec ' autocmd BufWinEnter ' . [editglob, sendglob, rundirglob]- >join (' ,' )
34
+ let wipe_bufs = [editglob, sendglob, rundirglob]
35
+ if has (' nvim' )
36
+ call remove (wipe_bufs, -1 )
37
+ endif
38
+ exec ' autocmd BufWinEnter ' . join (wipe_bufs, ' ,' )
34
39
\ . ' setlocal bufhidden=wipe'
35
- exec ' autocmd BufWinEnter ' . [rundirglob, tempglob]- > join ( ' ,' )
40
+ exec ' autocmd BufWinEnter ' . join ( [rundirglob, tempglob], ' ,' )
36
41
\ . ' setlocal ft=log'
37
- exec ' autocmd BufWinEnter ' . [rundirglob, tempglob]- > join ( ' ,' )
42
+ exec ' autocmd BufWinEnter ' . join ( [rundirglob, tempglob], ' ,' )
38
43
\ . ' setlocal noma'
39
44
exec ' autocmd BufWinLeave ' . editglob . ' call run#cmd_input_finished()'
40
45
exec ' autocmd BufWinLeave ' . sendglob . ' call run#cmd_input_finished({"send":1})'
49
54
" main functions
50
55
function ! run#Run (cmd, ... ) abort
51
56
let options = get (a: , 1 , {})
57
+ if has (' nvim' )
58
+ let options [' nostream' ] = 1
59
+ if get (options , ' split' ) || get (options , ' vsplit' )
60
+ call run#print_formatted (' ErrorMsg' ,
61
+ \ ' Streaming output to a buffer is not supported in Neovim.' )
62
+ return
63
+ endif
64
+ endif
52
65
53
66
" finish editing first
54
67
if s: run_edit_cmd_ongoing
@@ -86,7 +99,7 @@ function! run#Run(cmd, ...) abort
86
99
let s: run_edit_path = s: run_cmd_path . ' edit-' . timestamp . ' .sh'
87
100
let editor_lines = [s: edit_msg , ' ' ]
88
101
if get (options , ' edit_last' )
89
- call extend (editor_lines, s: run_last_command- > split ( " \n " ))
102
+ call extend (editor_lines, split ( s: run_last_command, " \n " ))
90
103
else
91
104
call add (editor_lines, ' ' )
92
105
endif
@@ -106,19 +119,20 @@ function! run#Run(cmd, ...) abort
106
119
107
120
" run job as shell command to tempfile w/ details
108
121
let date_cmd = ' date +"' . s: run_timestamp_format . ' "'
109
- call writefile (a: cmd- >split (" \n " ), currentcmdpath)
122
+ let startline = has (' nvim' ) ? 1 : 2
123
+ call writefile (split (a: cmd , " \n " ), currentcmdpath)
110
124
call writefile ([
111
125
\ ' printf "COMMAND: "' ,
112
- \ ' cat ' . currentcmdpath . " | sed '2 ,${s/^/ /g}'" ,
126
+ \ ' cat ' . currentcmdpath . " | sed '" .startline. " ,${s/^/ /g}'" ,
113
127
\ ' echo WORKDIR: ' . getcwd (),
114
- \ ' printf " STARTED: " ' ,
115
- \ date_cmd ,
128
+ \ ' STARTED=$( ' .date_cmd. ' ) ' ,
129
+ \ ' echo "STARTED: $STARTED" ' ,
116
130
\ ' printf "\n"' ,
117
131
\ g: run_shell . ' ' . currentcmdpath,
118
132
\ ' EXITVAL=$?' ,
119
133
\ ' STATUS=$([ $EXITVAL -eq 0 ] && echo "FINISHED" || echo "FAILED (status $EXITVAL)")' ,
120
- \ ' printf "\n$STATUS: " ' ,
121
- \ date_cmd ,
134
+ \ ' FINISHED=$( ' .date_cmd. ' ) ' ,
135
+ \ ' echo "\n$STATUS: $FINISHED" ' ,
122
136
\ ' exit $EXITVAL' ,
123
137
\ ], execpath)
124
138
@@ -143,13 +157,28 @@ function! run#Run(cmd, ...) abort
143
157
let ext_options[' out_cb' ] = ' run#out_cb'
144
158
endif
145
159
endif
160
+
161
+ " nvim overrides
162
+ if has (' nvim' )
163
+ let ext_options = {}
164
+ let ext_options[' on_exit' ] = ' run#close_cb'
165
+ let ext_options[' on_stdout' ] = ' run#out_cb'
166
+ let ext_options[' out_name' ] = fpath
167
+ " let ext_options['stdout_buffered'] = v:true
168
+ endif
169
+
146
170
call extend (job_options, ext_options)
147
- let job = job_start ([g: run_shell , execpath]- >join (' ' ), job_options)
171
+ if has (' nvim' )
172
+ let job = jobstart (join ([g: run_shell , execpath], ' ' ), job_options)
173
+ let pid = job
174
+ else
175
+ let job = job_start (join ([g: run_shell , execpath], ' ' ), job_options)
176
+ let pid = job_info (job)[' process' ]
177
+ endif
148
178
149
179
" get job info for global job dict
150
- let info = job_info (job)
151
180
let job_obj = {
152
- \ ' pid' : info[ ' process ' ] ,
181
+ \ ' pid' : pid ,
153
182
\ ' command' : a: cmd ,
154
183
\ ' bufname' : (is_nostream ? fpath : temppath),
155
184
\ ' filename' : fpath,
@@ -213,6 +242,11 @@ function! run#RunAgainEdit() abort
213
242
endfunction
214
243
215
244
function ! run#RunSendKeys (cmd, ... ) abort
245
+ if has (' nvim' )
246
+ call run#print_formatted (' ErrorMsg' ,
247
+ \ ' Sending keys to a running job is not supported in Neovim.' )
248
+ return
249
+ endif
216
250
let options = get (a: , 1 , {})
217
251
218
252
" finish editing first
@@ -248,7 +282,7 @@ function! run#RunSendKeys(cmd, ...) abort
248
282
let timestamp = job_info [' timestamp' ]
249
283
let editor_lines = [s: edit_msg , ' ' , ' ' ]
250
284
251
- if empty (a: cmd- > trim ( ))
285
+ if empty (trim ( a: cmd ))
252
286
if is_from_editor
253
287
call run#print_formatted (' WarningMsg' , ' User cancelled command input.' )
254
288
else
@@ -290,14 +324,18 @@ function! run#RunKill(...) abort
290
324
endif
291
325
return 0
292
326
else
293
- call job_stop (job[' job' ], ' kill' )
327
+ if has (' nvim' )
328
+ call jobstop (job[' job' ])
329
+ else
330
+ call job_stop (job[' job' ], ' kill' )
331
+ endif
294
332
return 1
295
333
endif
296
334
endfunction
297
335
298
336
function ! run#RunKillAll () abort
299
337
" user confirm
300
- let running_jobs = run#list_running_jobs ()- > split ( " \n " )
338
+ let running_jobs = split ( run#list_running_jobs (), " \n " )
301
339
if empty (running_jobs)
302
340
call run#print_formatted (' WarningMsg' , ' No jobs are running.' )
303
341
return
@@ -307,8 +345,19 @@ function! run#RunKillAll() abort
307
345
if confirm !=? ' Y'
308
346
return
309
347
endif
348
+
349
+ " in case user confirms late and jobs have stopped
350
+ let running_jobs = split (run#list_running_jobs (), " \n " )
351
+ if empty (running_jobs)
352
+ call run#print_formatted (' WarningMsg' , ' All jobs have finished running.' )
353
+ return
354
+ endif
355
+
310
356
let s: run_killed_jobs = 0
311
357
let s: run_killall_ongoing = len (running_jobs)
358
+ if has (' nvim' )
359
+ let s: run_jobs_to_kill_nvim = running_jobs
360
+ endif
312
361
for job_key in running_jobs
313
362
call run#RunKill (job_key)
314
363
endfor
@@ -330,18 +379,20 @@ function! run#RunClear(status_list) abort
330
379
endif
331
380
" user confirm
332
381
let confirm = input (
333
- \ ' Clear all jobs with status ' . a: status_list- > join ( ' /' ) . ' ? (Y/n) '
382
+ \ ' Clear all jobs with status ' . join ( a: status_list, ' /' ) . ' ? (Y/n) '
334
383
\ )
335
384
if confirm !=? ' Y'
336
385
return
337
386
endif
338
387
339
388
" remove all jobs that match status_list
340
389
let clear_count = 0
341
- for job in s: run_jobs- > values ( )
342
- let status_match = a: status_list- > index ( job[' status' ]) >= 0
390
+ for job in values ( s: run_jobs )
391
+ let status_match = index ( a: status_list, job[' status' ]) >= 0
343
392
if status_match
344
- silent exec ' bw! ' . job[' bufname' ]
393
+ if get (job, ' bufname' )
394
+ silent exec ' bw! ' . job[' bufname' ]
395
+ endif
345
396
unlet s: run_jobs [job[' timestamp' ]]
346
397
let clear_count += 1
347
398
endif
@@ -411,12 +462,12 @@ function! run#RunBrowseLogs(...) abort
411
462
\ " | xargs -n 1 -I FILE" .
412
463
\ " sh -c 'printf \" FILE \" && echo $(head -1 FILE)'"
413
464
let qf_output = []
414
- for entry in system (cmd_get_files)- > trim () - > split ( " \n " )
465
+ for entry in split ( trim ( system (cmd_get_files)), " \n " )
415
466
let qf_item = {}
416
467
let split_str = ' COMMAND: '
417
- let split_cmd = entry - > split (split_str)
468
+ let split_cmd = split (entry, split_str)
418
469
let qf_item[' filename' ] = split_cmd[0 ]
419
- let qf_item[' text' ] = ' SAVED - ' . split_cmd[1 :]- > join ( split_str)
470
+ let qf_item[' text' ] = ' SAVED - ' . join ( split_cmd[1 :], split_str)
420
471
call add (qf_output, qf_item)
421
472
endfor
422
473
@@ -442,7 +493,7 @@ function! run#RunDeleteLogs() abort
442
493
endif
443
494
call system (' rm ' . g: rundir . ' /*.log' )
444
495
445
- let qf_title = getqflist ({' title' : 1 })- > get ( ' title' )
496
+ let qf_title = get ( getqflist ({' title' : 1 }), ' title' )
446
497
if run#is_qf_open () && qf_title == # ' RunLogs'
447
498
silent call setqflist ([])
448
499
silent call setqflist ([], ' a' , {' title' : ' RunLogs' })
@@ -478,9 +529,9 @@ function! run#cmd_input_finished(...)
478
529
silent exec win . ' wincmd w'
479
530
480
531
" keep only non-comment lines w/ text, join to one line
481
- let cmd_text = getline (1 , ' $' )
482
- \ - > filter ( ' v:val->trim( ) !~ "^#" && len(v:val->trim( )) > 0' )
483
- \ - > join ( " \n " )
532
+ let cmd_text = join ( filter ( getline (1 , ' $' ),
533
+ \ ' trim( v:val) !~ "^#" && len(trim( v:val)) > 0' ),
534
+ \ " \n " )
484
535
485
536
call extend (s: run_edit_options , {' is_from_editor' : 1 })
486
537
if ! get (options , ' send' )
@@ -499,7 +550,7 @@ function! run#get_current_buf_job(...)
499
550
let options = get (a: , 1 , {})
500
551
let curr = bufname (' %' )
501
552
502
- for job_info in s: run_jobs- > values ( )
553
+ for job_info in values ( s: run_jobs )
503
554
if job_info [' bufname' ] == # curr
504
555
return job_info [' job' ]
505
556
endif
@@ -508,28 +559,22 @@ endfunction
508
559
509
560
function ! run#update_run_jobs ()
510
561
let qf_output = []
511
- let run_jobs_sorted = reverse (sort (s: run_jobs- > values ( ), {
562
+ let run_jobs_sorted = reverse (sort (values ( s: run_jobs ), {
512
563
\ v1, v2 - > v1.timestamp == # v2.timestamp ? 0
513
564
\ : v1.timestamp > v2.timestamp ? 1 : -1
514
565
\ }))
515
566
for val in run_jobs_sorted
516
567
let qf_item = {}
517
- let status = job_status (val[' job' ])
518
568
let is_nostream = get (val[' options' ], ' nostream' )
519
569
520
570
" set the qf buffer / file to open
521
- if is_nostream || (status !=# ' run' && val[' save' ])
571
+ let status = val[' status' ]
572
+ if is_nostream || (status !=# ' RUNNING' && val[' save' ])
522
573
let qf_item[' filename' ] = val[' filename' ]
523
574
else
524
575
let qf_item[' bufnr' ] = bufnr (val[' bufname' ])
525
576
endif
526
577
" set the qf message (status)
527
- if status == # ' run'
528
- let status = ' RUNNING'
529
- else
530
- let exitval = job_info (val[' job' ])[' exitval' ]
531
- let status = exitval == # 0 ? ' DONE' : exitval == # -1 ? ' KILLED' : ' FAILED'
532
- endif
533
578
let qf_item[' text' ] = status . ' - ' . val[' command' ]
534
579
535
580
" update output and global jobs dict
@@ -556,22 +601,26 @@ function! run#alert_and_update(content, ...)
556
601
endfunction
557
602
558
603
function ! run#get_job_with_object (job)
559
- let pid = job_info (a: job )[' process' ]
560
- for job in s: run_jobs- > values ( )
604
+ let pid = has ( ' nvim ' ) ? a: job : job_info (a: job )[' process' ]
605
+ for job in values ( s: run_jobs )
561
606
if job[' pid' ] == # pid
562
607
return job
563
608
endif
564
609
endfor
565
610
endfunction
566
611
567
612
function ! run#list_running_jobs (... )
568
- return deepcopy (s: run_jobs )- >filter (' v:val.status ==# "RUNNING"' )
569
- \ - >keys ()- >join (" \n " )
613
+ return join (keys (
614
+ \ filter (deepcopy (s: run_jobs ),
615
+ \ ' v:val.status ==# "RUNNING"' )
616
+ \ ), " \n " )
570
617
endfunction
571
618
572
619
function ! run#list_unsaved_jobs (... )
573
- return deepcopy (s: run_jobs )- >filter (' v:val.save ==# 0 && v:val.status !=# "RUNNING"' )
574
- \ - >keys ()- >join (" \n " )
620
+ return join (keys (
621
+ \ filter (deepcopy (s: run_jobs ),
622
+ \ ' v:val.save ==# 0 && v:val.status !=# "RUNNING"' )
623
+ \ ), " \n " )
575
624
endfunction
576
625
577
626
function ! run#is_qf_open ()
@@ -589,17 +638,43 @@ endfunction
589
638
590
639
591
640
" callbacks
592
- function ! run#out_cb (channel, msg)
641
+ function ! run#out_cb (channel, msg, ... )
593
642
" write logs to output file while running
594
- let job = run#get_job_with_object (ch_getjob (a: channel ))
643
+ let job_obj = has (' nvim' ) ? a: channel : ch_getjob (a: channel )
644
+ let job = run#get_job_with_object (job_obj)
595
645
let fname = job[' filename' ]
596
- call writefile ([a: msg ], fname, " a" )
646
+ if has (' nvim' )
647
+ let output = a: msg
648
+ if empty (trim (output[-1 ]))
649
+ let output = output[:-2 ]
650
+ endif
651
+ else
652
+ let output = [a: msg ]
653
+ endif
654
+ call writefile (output, fname, " a" )
597
655
endfunction
598
656
599
- function ! run#close_cb (channel)
600
- let job = ch_getjob (a: channel )
601
- let info = run#get_job_with_object (job)
602
- let exitval = job_info (info[' job' ])[' exitval' ]
657
+ function ! run#close_cb (channel, ... )
658
+ if has (' nvim' )
659
+ let job = a: channel
660
+ let info = run#get_job_with_object (job)
661
+ " nvim exitval is unreliable
662
+ let kill_idx = index (s: run_jobs_to_kill_nvim , info[' timestamp' ])
663
+ let exitval = get (a: , 1 , 0 )
664
+ if kill_idx > -1
665
+ let exitval = -1
666
+ call remove (s: run_jobs_to_kill_nvim , kill_idx)
667
+ endif
668
+ else
669
+ let job = ch_getjob (a: channel )
670
+ let info = run#get_job_with_object (job)
671
+ let exitval = job_info (info[' job' ])[' exitval' ]
672
+ endif
673
+
674
+ " calculate status here
675
+ let status = (exitval == -1 ) ? ' KILLED' : (exitval == 0 ) ? ' DONE' : ' FAILED'
676
+ let s: run_jobs [info[' timestamp' ]][' exitval' ] = exitval
677
+ let s: run_jobs [info[' timestamp' ]][' status' ] = status
603
678
604
679
" if saved and window unfocused, wipe temp buffer
605
680
let bufexists = bufnr (info[' bufname' ]) !=# -1
@@ -617,8 +692,9 @@ function! run#close_cb(channel)
617
692
let s: run_killed_jobs += 1
618
693
619
694
" killall finished
620
- if s: run_killed_jobs == # s: run_killall_ongoing
695
+ if len ( run#list_running_jobs ()) == 0
621
696
let s: run_killall_ongoing = 0
697
+ let s: run_jobs_to_kill_nvim = []
622
698
let msg = s: run_killed_jobs .
623
699
\ (s: run_killed_jobs !=# 1 ? ' jobs killed.' : ' job killed.' )
624
700
call run#alert_and_update (msg, kill_options)
0 commit comments