diff --git a/.SpaceVim.d/tasks.toml b/.SpaceVim.d/tasks.toml index f4affcbb5..493ea9574 100644 --- a/.SpaceVim.d/tasks.toml +++ b/.SpaceVim.d/tasks.toml @@ -3,4 +3,3 @@ isBackground = false [file-run.options] cwd = '${workspaceFolder}bin/' - diff --git a/autoload/SpaceVim/layers/core.vim b/autoload/SpaceVim/layers/core.vim index 29aac5656..e41b63af0 100644 --- a/autoload/SpaceVim/layers/core.vim +++ b/autoload/SpaceVim/layers/core.vim @@ -264,6 +264,7 @@ function! SpaceVim#layers#core#config() abort " call SpaceVim#mapping#space#def('nnoremap', ['p', 't'], 'call SpaceVim#plugins#projectmanager#current_root()', 'find-project-root', 1) let g:_spacevim_mappings_space.p.t = {'name' : '+Tasks'} call SpaceVim#mapping#space#def('nnoremap', ['p', 't', 'e'], 'call SpaceVim#plugins#tasks#edit()', 'edit-project-task', 1) + call SpaceVim#mapping#space#def('nnoremap', ['p', 't', 'l'], 'call SpaceVim#plugins#tasks#list()', 'list-tasks', 1) call SpaceVim#mapping#space#def('nnoremap', ['p', 't', 'r'], \ 'call SpaceVim#plugins#runner#run_task(SpaceVim#plugins#tasks#get())', 'pick-task-to-run', 1) call SpaceVim#mapping#space#def('nnoremap', ['p', 'k'], 'call SpaceVim#plugins#projectmanager#kill_project()', 'kill-all-project-buffers', 1) diff --git a/autoload/SpaceVim/layers/core/statusline.vim b/autoload/SpaceVim/layers/core/statusline.vim index ab8010218..2400151ef 100644 --- a/autoload/SpaceVim/layers/core/statusline.vim +++ b/autoload/SpaceVim/layers/core/statusline.vim @@ -487,6 +487,8 @@ function! SpaceVim#layers#core#statusline#get(...) abort return '%#SpaceVim_statusline_a# WinDisk %#SpaceVim_statusline_a_SpaceVim_statusline_b#' . s:lsep elseif &filetype ==# 'SpaceVimTodoManager' return '%#SpaceVim_statusline_a# TODO manager %#SpaceVim_statusline_a_SpaceVim_statusline_b#' . s:lsep + elseif &filetype ==# 'SpaceVimTasksInfo' + return '%#SpaceVim_statusline_a# Tasks manager %#SpaceVim_statusline_a_SpaceVim_statusline_b#' . s:lsep elseif &filetype ==# 'SpaceVimGitBranchManager' return '%#SpaceVim_statusline_a# Branch manager %#SpaceVim_statusline_a_SpaceVim_statusline_b#' . s:lsep elseif &filetype ==# 'SpaceVimPlugManager' diff --git a/autoload/SpaceVim/plugins/repl.vim b/autoload/SpaceVim/plugins/repl.vim index fb23f7b07..7ce95f253 100644 --- a/autoload/SpaceVim/plugins/repl.vim +++ b/autoload/SpaceVim/plugins/repl.vim @@ -140,6 +140,14 @@ function! s:close() abort endif endfunction +function! s:close_repl() abort + " stop the job if it is running. + if exists('s:job_id') && s:job_id > 0 + call s:JOB.stop(s:job_id) + let s:job_id = 0 + endif +endfunction + let s:exes = {} function! SpaceVim#plugins#repl#reg(ft, execute) abort @@ -171,7 +179,7 @@ function! s:open_windows() abort nnoremap q :call close() augroup spacevim_repl autocmd! - autocmd BufWipeout call close() + autocmd BufWipeout call close_repl() augroup END let s:bufnr = bufnr('%') let s:winid = win_getid(winnr()) diff --git a/autoload/SpaceVim/plugins/runner.vim b/autoload/SpaceVim/plugins/runner.vim index 465a2d07e..a0d99d428 100644 --- a/autoload/SpaceVim/plugins/runner.vim +++ b/autoload/SpaceVim/plugins/runner.vim @@ -19,6 +19,13 @@ let s:runners = {} let s:bufnr = 0 let s:winid = -1 +let s:job_id = 0 +let s:status = { + \ 'is_running' : 0, + \ 'is_exit' : 0, + \ 'has_errors' : 0, + \ 'exit_code' : 0 + \ } function! s:open_win() abort if s:bufnr != 0 && bufexists(s:bufnr) @@ -27,18 +34,14 @@ function! s:open_win() abort botright split __runner__ let lines = &lines * 30 / 100 exe 'resize ' . lines - setlocal buftype=nofile bufhidden=wipe nobuflisted nolist nomodifiable - \ noswapfile - \ nowrap - \ cursorline - \ nospell - \ nonu - \ norelativenumber - \ winfixheight - \ nomodifiable + setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline nospell nonu norelativenumber winfixheight nomodifiable set filetype=SpaceVimRunner - nnoremap q :call SpaceVim#plugins#runner#close() + nnoremap q :call close() nnoremap i :call insert() + augroup spacevim_runner + autocmd! + autocmd BufWipeout call stop_runner() + augroup END let s:bufnr = bufnr('%') let s:winid = win_getid(winnr()) wincmd p @@ -57,6 +60,7 @@ endfunction let s:target = '' function! s:async_run(runner, ...) abort + call s:stop_runner() if type(a:runner) == type('') " the runner is a string, the %s will be replaced as a file name. try @@ -236,89 +240,50 @@ endfunction " @vimlint(EVL103, 1, a:job_id) " @vimlint(EVL103, 1, a:data) " @vimlint(EVL103, 1, a:event) -if has('nvim') && exists('*chanclose') - " remoet at the end of each - let s:_out_data = [''] - function! s:on_stdout(job_id, data, event) abort - let s:_out_data[-1] .= a:data[0] - call extend(s:_out_data, a:data[1:]) - if s:_out_data[-1] ==# '' - call remove(s:_out_data, -1) - let lines = s:_out_data - else - let lines = s:_out_data - endif - " if s:SYS.isWindows - " let lines = map(lines, 's:ICONV.iconv(v:val, "cp936", "utf-8")') - " endif - if !empty(lines) - let lines = map(lines, "substitute(v:val, ' $', '', 'g')") - if bufexists(s:bufnr) - call s:BUFFER.buf_set_lines(s:bufnr, s:lines , s:lines + 1, 0, lines) - endif - call s:VIM.win_set_cursor(s:winid, [s:VIM.buf_line_count(s:bufnr), 1]) - endif - let s:lines += len(lines) - let s:_out_data = [''] - call s:update_statusline() - endfunction +function! s:on_stdout(job_id, data, event) abort + if a:job_id !=# s:job_id + " that means, a new runner has been opennd + " this is previous runner exit_callback + return + endif + if bufexists(s:bufnr) + call s:BUFFER.buf_set_lines(s:bufnr, s:lines , s:lines + 1, 0, a:data) + endif + let s:lines += len(a:data) + call s:VIM.win_set_cursor(s:winid, [s:VIM.buf_line_count(s:bufnr), 1]) + call s:update_statusline() +endfunction - let s:_err_data = [''] - function! s:on_stderr(job_id, data, event) abort - let s:_out_data[-1] .= a:data[0] - call extend(s:_out_data, a:data[1:]) - if s:_out_data[-1] ==# '' - call remove(s:_out_data, -1) - let lines = s:_out_data - else - let lines = s:_out_data - endif - if s:SYS.isWindows - let lines = map(lines, 's:ICONV.iconv(v:val, "cp936", "utf-8")') - endif - if !empty(lines) - let lines = map(lines, "substitute(v:val, ' $', '', 'g')") - if bufexists(s:bufnr) - call s:BUFFER.buf_set_lines(s:bufnr, s:lines , s:lines + 1, 0, lines) - endif - call s:VIM.win_set_cursor(s:winid, [s:VIM.buf_line_count(s:bufnr), 1]) - endif - let s:lines += len(lines) - let s:_out_data = [''] - call s:update_statusline() - endfunction -else - function! s:on_stdout(job_id, data, event) abort - if bufexists(s:bufnr) - call s:BUFFER.buf_set_lines(s:bufnr, s:lines , s:lines + 1, 0, a:data) - endif - let s:lines += len(a:data) - call s:VIM.win_set_cursor(s:winid, [s:VIM.buf_line_count(s:bufnr), 1]) - call s:update_statusline() - endfunction - - function! s:on_stderr(job_id, data, event) abort - let s:status.has_errors = 1 - if bufexists(s:bufnr) - call s:BUFFER.buf_set_lines(s:bufnr, s:lines , s:lines + 1, 0, a:data) - endif - let s:lines += len(a:data) - call s:VIM.win_set_cursor(s:winid, [s:VIM.buf_line_count(s:bufnr), 1]) - call s:update_statusline() - endfunction -endif +function! s:on_stderr(job_id, data, event) abort + if a:job_id !=# s:job_id + " that means, a new runner has been opennd + " this is previous runner exit_callback + return + endif + let s:status.has_errors = 1 + if bufexists(s:bufnr) + call s:BUFFER.buf_set_lines(s:bufnr, s:lines , s:lines + 1, 0, a:data) + endif + let s:lines += len(a:data) + call s:VIM.win_set_cursor(s:winid, [s:VIM.buf_line_count(s:bufnr), 1]) + call s:update_statusline() +endfunction function! s:on_exit(job_id, data, event) abort + if a:job_id !=# s:job_id + " that means, a new runner has been opennd + " this is previous runner exit_callback + return + endif let s:end_time = reltime(s:start_time) let s:status.is_exit = 1 let s:status.exit_code = a:data let done = ['', '[Done] exited with code=' . a:data . ' in ' . s:STRING.trim(reltimestr(s:end_time)) . ' seconds'] if bufexists(s:bufnr) call s:BUFFER.buf_set_lines(s:bufnr, s:lines , s:lines + 1, 0, done) + call s:VIM.win_set_cursor(s:winid, [s:VIM.buf_line_count(s:bufnr), 1]) + call s:update_statusline() endif - call s:VIM.win_set_cursor(s:winid, [s:VIM.buf_line_count(s:bufnr), 1]) - call s:update_statusline() - endfunction " @vimlint(EVL103, 0, a:job_id) " @vimlint(EVL103, 0, a:data) @@ -339,11 +304,21 @@ function! SpaceVim#plugins#runner#status() abort return '' endfunction -function! SpaceVim#plugins#runner#close() abort +function! s:close() abort if s:status.is_exit == 0 && s:job_id > 0 call s:JOB.stop(s:job_id) + let s:job_id = 0 + endif + if s:bufnr != 0 && bufexists(s:bufnr) + exe 'bd ' s:bufnr + endif +endfunction + +function! s:stop_runner() abort + if s:status.is_exit == 0 && s:job_id > 0 + call s:JOB.stop(s:job_id) + let s:job_id = 0 endif - exe 'bd ' s:bufnr endfunction function! SpaceVim#plugins#runner#select_file() abort diff --git a/autoload/SpaceVim/plugins/tasks.vim b/autoload/SpaceVim/plugins/tasks.vim index 8174109bd..e248a1e09 100644 --- a/autoload/SpaceVim/plugins/tasks.vim +++ b/autoload/SpaceVim/plugins/tasks.vim @@ -21,6 +21,7 @@ let s:CMP = SpaceVim#api#import('vim#compatible') let s:SYS = SpaceVim#api#import('system') let s:MENU = SpaceVim#api#import('cmdlinemenu') let s:VIM = SpaceVim#api#import('vim') +let s:BUF = SpaceVim#api#import('vim#buffer') " task object @@ -90,13 +91,8 @@ function! s:replace_variables(str) abort return str endfunction -function! SpaceVim#plugins#tasks#get() - call s:load() - for Provider in s:providers - call extend(s:conf, call(Provider, [])) - endfor - call s:init_variables() - let task = s:pick() +function! s:expand_task(task) abort + let task = a:task if has_key(task, 'windows') && s:SYS.isWindows let task = task.windows elseif has_key(task, 'osx') && s:SYS.isOSX @@ -118,21 +114,33 @@ function! SpaceVim#plugins#tasks#get() return task endfunction +function! SpaceVim#plugins#tasks#get() abort + call s:load() + for Provider in s:providers + call extend(s:conf, call(Provider, [])) + endfor + call s:init_variables() + let task = s:expand_task(s:pick()) + return task +endfunction + """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " list all the tasks """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -function! SpaceVim#plugins#tasks#list() +function! SpaceVim#plugins#tasks#list() abort call s:load() + for Provider in s:providers + call extend(s:conf, call(Provider, [])) + endfor call s:init_variables() call s:open_tasks_list_win() - - + call s:update_tasks_win_context() endfunction -function! SpaceVim#plugins#tasks#complete(...) +function! SpaceVim#plugins#tasks#complete(...) abort @@ -157,9 +165,44 @@ function! s:open_tasks_list_win() abort \ nomodifiable set filetype=SpaceVimTasksInfo let s:bufnr = bufnr('%') + nnoremap :call open_task() endfunction -function! SpaceVim#plugins#tasks#edit(...) +function! s:open_task() abort + let line = getline('.') + if line =~# '^\[.*\]' + let task = matchstr(line, '^\[.*\]')[1:-2] + if line =~# '^\[.*\]\s\+detected' + let task = split(task, ':')[1] + endif + let task = s:expand_task(s:conf[task]) + call SpaceVim#mapping#SmartClose() + call SpaceVim#plugins#runner#run_task(task) + else + " not on a task + endif +endfunction + +function! s:update_tasks_win_context() abort + let lines = ['Task Type Description'] + for task in keys(s:conf) + if has_key(s:conf[task], 'isGlobal') && s:conf[task].isGlobal ==# 1 + let line = '[' . task . ']' . repeat(' ', 22 - strlen(task)) + let line .= 'global ' + elseif has_key(s:conf[task], 'isDetected') && s:conf[task].isDetected ==# 1 + let line = '[' . s:conf[task].detectedName . task . ']' . repeat(' ', 22 - strlen(task . s:conf[task].detectedName)) + let line .= 'detected ' + else + let line = '[' . task . ']' . repeat(' ', 22 - strlen(task)) + let line .= 'local ' + endif + let line .= get(s:conf[task], 'description', s:conf[task].command . ' ' . join(get(s:conf[task], 'args', []), ' ')) + call add(lines, line) + endfor + call s:BUF.buf_set_lines(s:bufnr, 0, -1, 0, sort(lines)) +endfunction + +function! SpaceVim#plugins#tasks#edit(...) abort if get(a:000, 0, 0) exe 'e ~/.SpaceVim.d/tasks.toml' else @@ -183,7 +226,7 @@ function! s:detect_npm_tasks() abort return detect_task endfunction -function! SpaceVim#plugins#tasks#reg_provider(provider) +function! SpaceVim#plugins#tasks#reg_provider(provider) abort call add(s:providers, a:provider) endfunction diff --git a/docs/cn/documentation.md b/docs/cn/documentation.md index acb4a9504..025273cbd 100644 --- a/docs/cn/documentation.md +++ b/docs/cn/documentation.md @@ -1874,6 +1874,9 @@ endfunction | ----------- | ---------------- | | `SPC p t e` | 编辑任务配置文件 | | `SPC p t r` | 选定任务并执行 | +| `SPC p t l` | 列出所有任务 | + +![task_manager](https://user-images.githubusercontent.com/13142418/94822603-69d0c700-0435-11eb-95a7-b0b4fef91be5.png) #### 自定义任务 @@ -1903,6 +1906,10 @@ endfunction - **options**: 设置命令运行的一些选项,比如 `cwd`,`env` 或者 `shell`。 - **isBackground**: 可设定的值为 `true` 或者 `false`, 默认是 `false`, 设置是否需要后台运行任务 +- **description**: 关于该任务的一段简短介绍 + +当启动一个任务时,默认会关闭前一个任务,如果需要让任务一直保持后台运行, +可以将 `isBackground` 设为 `true`。 在编辑任务配置文件时,可以使用一些预设定的变量,以下列出目前已经支持的预设定变量: @@ -1931,7 +1938,6 @@ endfunction - **\${fileExtname}**: - `.ext` - **\${lineNumber}**: - `10` - #### 任务自动识别 SpaceVim 目前支持自动识别以下构建系统的任务:npm。 diff --git a/docs/documentation.md b/docs/documentation.md index 9bd2333ba..5fa9c8ac6 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -1907,7 +1907,7 @@ endfunction To integrate with external tools, SpaceVim introduce a task manager system, which is similar to vscode tasks-manager. There are two kinds of task configuration -file: +file: - `~/.SpaceVim.d/tasks.toml`: global tasks configuration - `.SpaceVim.d/tasks.toml`: project local tasks configuration @@ -1919,7 +1919,9 @@ tasks configuration. | ------------ | ----------------------------- | | `SPC p t e` | edit tasks configuration file | | `SPC p t r` | select task to run | +| `SPC p t l` | list all available tasks | +![task_manager](https://user-images.githubusercontent.com/13142418/94822603-69d0c700-0435-11eb-95a7-b0b4fef91be5.png) #### Custom tasks @@ -1950,6 +1952,10 @@ The task's properties have the following semantic: - **options**: override the defaults for `cwd`,`env` or `shell`. - **isBackground**: `true` or `false`, specifies whether background running is required, by default, it is `false`. +- **description**: short description of the task + +When start a new task, it will kill the previous task. If you want to keep the task +run in background, set `isBackground` to `true`. SpaceVim supports variable substitution in task, The following predefined variables are supported: @@ -1984,7 +1990,7 @@ So you will have the following values for each variable: #### Task auto-detection -Currently, SpaceVim can auto-detect tasks for npm. +Currently, SpaceVim can auto-detect tasks for npm. the tasks manager will paser the `package.json` file for npm systems. If you have cloned the [eslint-starter](https://github.com/spicydonuts/eslint-starter) example, then pressing `SPC p t r` shows the following list: diff --git a/syntax/SpaceVimTasksInfo.vim b/syntax/SpaceVimTasksInfo.vim new file mode 100644 index 000000000..3b536c692 --- /dev/null +++ b/syntax/SpaceVimTasksInfo.vim @@ -0,0 +1,25 @@ +if exists('b:current_syntax') && b:current_syntax ==# 'SpaceVimTasksInfo' + finish +endif +let b:current_syntax = 'SpaceVimTasksInfo' +syntax case ignore + +syn match TaskName /^\[.*\]/ +syn match TaskTitle /^Task\s\+Type\s\+Command/ + +" @question Why \zs does not work in syntax file? +" ref: +" https://github.com/vim/vim/issues/598 +" https://stackoverflow.com/questions/49323753/vim-syntax-file-not-matching-with-zs +" https://stackoverflow.com/questions/64153655/why-taskinfo-syntax-file-does-not-work-as-expect +" syn match TaskType /^\[.*\]\s*\zs[a-z]*/ +" syn match TaskDescription /^\[.*\]\s*[a-z]*\s\+\zs.*/ + +syn match TaskType /\(^\[.\+\]\s\+\)\@<=[a-z]*/ +syn match TaskDescription /\(^\[.*\]\s\+[a-z]\+\s\+\)\@<=.*/ +hi def link TaskTitle Title +hi def link TaskName String +hi def link TaskType Todo +hi def link TaskDescription Comment + +