Git Product home page Git Product logo

asynctasks.vim's Introduction

asynctasks.vim - modern task system

The generic way to handle building/running/testing/deploying tasks by imitating vscode's task system.

GitHub license Maintenance Join the chat at https://gitter.im/skywind3000/asynctasks.vim

This readme is also available in:

Introduction

As vim 8.0 was released in 2017, we have got many wonderful plugins like LSP, DAP, and asynchronous linters. Even things like vimspector, which could only be imagined in emacs in the past, now become a reality in vim.

However, vim still lack an elegant task system to speed up your inner software development cycle (edit, compile, test). Many people are still dealing with those building, testing, and deploying tasks in such a primitive or flaky way. Therefore, I decided to create this plugin and introduce vscode's task-like mechanisms to vim.

Vscode creates a .vscode folder in your project root directory and uses a .vscode/tasks.json file to define project-specific tasks. Similar, asynctasks.vim uses a .tasks file in your project folders for local tasks and uses ~/.vim/tasks.ini to define global tasks for generic projects.

This is very simple, but most good designs always start from simple concepts. You will benefit a lot from the productivity and possibility of this task system.

Get Started

Installation

Install with vim-plug:

Plug 'skywind3000/asynctasks.vim'
Plug 'skywind3000/asyncrun.vim'

It requires asyncrun.vim 2.4.0 or above. Don't forget to setup:

let g:asyncrun_open = 6

And quickfix window can be opened automatically, otherwise you can't see the task output unless using :copen manually.

Build and run a single file

It's convenient for me to build and run a single file directly without creating a new project for that if I want to try some small and new ideas. In this circumstance, we can use :AsyncTaskEdit command to edit the .tasks configuration file in your current project root directory:

[file-build]
# macros in the "$(...)" form will be substituted, 
# shell command, use quotation for filenames containing spaces
command=gcc -O2 "$(VIM_FILEPATH)" -o "$(VIM_FILEDIR)/$(VIM_FILENOEXT)"
# working directory
cwd=$(VIM_FILEDIR)

[file-run]
command="$(VIM_FILEDIR)/$(VIM_FILENOEXT)"
cwd=$(VIM_FILEDIR)
# output mode: run in a terminal
output=terminal

There are two tasks file-build and file-run defined in this .tasks file. Then from the directory where this .tasks reside and its child directories, you can use:

:AsyncTask file-build
:AsyncTask file-run

To build and run the current file:

This is the result of :AsyncTask file-build, the command output displays in the quickfix window and errors are matched with errorformat. You can navigate the command output in the quickfix window or use :cnext/:cprev to jump between errors.

There are many macros can be used in the command field and will be expanded and replaced when task starts. Having a fast, low-friction Edit/Build/Test cycle is one of the best and easiest ways to increase developer productivity, so we will map them to F5 and F9:

noremap <silent><f5> :AsyncTask file-run<cr>
noremap <silent><f9> :AsyncTask file-build<cr>

Put the code above in your vimrc and you can have F9 to compile current file and F5 to run it. And you may ask, this is for C/C++ only, what if you want to run a python script, should you create a new task file-run-python ? Totally unnecessary, commands can match with file types:

[file-run]
command="$(VIM_FILEPATH)"
command:c,cpp="$(VIM_PATHNOEXT)"
command:go="$(VIM_PATHNOEXT)"
command:python=python "$(VIM_FILENAME)"
command:javascript=node "$(VIM_FILENAME)"
command:sh=sh "$(VIM_FILENAME)"
command:lua=lua "$(VIM_FILENAME)"
command:perl=perl "$(VIM_FILENAME)"
command:ruby=ruby "$(VIM_FILENAME)"
output=terminal
cwd=$(VIM_FILEDIR)
save=2

The command followed by a colon accepts file type list separated by comma. If the current file type cannot be matched, the default command will be used. The -save=2 represents to save all modified buffers before running the task.

At this point, you can have your F5 to run all type of files. And plugins like quickrun can be obsoleted immediately, they can't do better than this. Then we continue to polish file-build to support more file types:

[file-build]
command:c,cpp=gcc -O2 -Wall "$(VIM_FILEPATH)" -o "$(VIM_PATHNOEXT)" -lstdc++ -lm -msse3
command:go=go build -o "$(VIM_PATHNOEXT)" "$(VIM_FILEPATH)"
command:make=make -f "$(VIM_FILEPATH)"
output=quickfix
cwd=$(VIM_FILEDIR)
save=2

Again, F9 can be used to compile many file types, same keybind, different command. This two tasks can be defined in local .tasks and work for the project scope or in the ~/.vim/tasks.ini and work for all project. Much more elegant than using the old &makeprg or calling asyncrun/neomake with a lot if/else in your vimrc.

Tasks for running compilers or grep may set output=quickfix (default), because the output can use errorformat to match errors in the quickfix window, while tasks for running your file/project may set output=terminal.

When you set output to terminal, you can further specify what type of terminal do you want to use exactly, like: a simulated terminal in quickfix window (without matching the errorformat)? the triditional ! command in vim? the internal terminal ? an external terminal window ? or in a tmux split window ?? The detail will be discussed later.

Build and run a project

If you want to do something with a project, you must figure out where the project locates. asynctasks.vim and its backend asyncrun.vim choose a widely used method called root markers to indentify the project root directory. The project root is one of the nearest parent directory containing these markers:

let g:asyncrun_rootmarks = ['.git', '.svn', '.root', '.project', '.hg']

If none of the parent directories contains these root markers, the directory of the current file is used as the project root.

There is a corner case: if current buffer is not a normal file buffer (eg. a tool window) or is an unnamed new buffer, vim's current working directory (which :pwd returns) will be used as the project root.

Once we got the project location, the macro $(VIM_ROOT), or its alias <root>, can be used to represent the project root:

What if your current project is not in any git/subversion repository ? How to find out where is my project root ? The solution is very simple, just put an empty .root file in your project root, it has been defined in g:asyncrun_rootmarks before.

Tasks related to projects can be defined by using this:

[project-build]
command=make
# set the working directory to the project root.
cwd=$(VIM_ROOT)

[project-run]
command=make run
# <root> is an alias to `$(VIM_ROOT)`, a little easier to type.
cwd=<root>
output=terminal

We assign F6 and F7 for them:

noremap <silent><f6> :AsyncTask project-run<cr>
noremap <silent><f7> :AsyncTask project-build<cr>

Now, F7 can be used to build your project and F6 can be used run your project. You may ask again, this is for gnu-make only, but there are a lot of build tools like cmake, ninja and bazel, should you define new tasks as project-build-cmake or project-build-ninja and assign different keymaps for them ?

Task priority

No, you don't have to. The easiest way is to put previous project-build and project-run in your ~/.vim/tasks.ini as the default and global tasks, you can use them directly for generic projects using make.

For other type of projects, for example, I am using msbuild in my project A. And I can define a new project-build task in the local .tasks file residing in project A:

[project-build]
command=vcvars32 > nul && msbuild build/StreamNet.vcxproj /property:Configuration=Debug /nologo /verbosity:quiet
cwd=<root>
errorformat=%f(%l):%m

[project-run]
command=build/Debug/StreamNet.exe
cwd=<root>
output=terminal

The .tasks configuration file are read top to bottom and the most recent tasks found take precedence. and local tasks always have higher priority than the global tasks.

Task defined in .tasks will always override the task with the same name in ~/.vim/tasks.ini. So, in project A, our two old friends project-build and project-run have been replaced with the local methods.

Firstly, the new project-build task will call vcvars32.bat to setup environment variables, then, use a && to concatenate msbuild command. errorformat is initialized to %f(%l):%m for matching Visual C++ errors in this task.

We can still use F7 to build this project and F6 to run it. We don't have to change our habit if we are working in a different type of project. Unified workflow can be used in different type of projects. This is the power of local/global tasks combination.

Bonus: use :AsyncTaskEdit to edit local tasks, and :AsyncTaskEdit! to edit global tasks.

Query available tasks

What tasks do you have in current project ? Where are they defined ? Has one global task been overrided by a local one ? We use :AsyncTaskList command to answer these questions:

It will display task name, command and where it has been defined.

Bonus: tasks starting with a dot "." will be hidden (eg. ".file-test-temp1"), use :AsyncTaskList! to see them all.

Macro variable substitution

asynctasks.vim supports macro variable substitution in command and cwd fileds, available macros are:

$(VIM_FILEPATH)    # File name of current buffer with full path.
$(VIM_FILENAME)    # File name of current buffer without path.
$(VIM_FILEDIR)     # Full path of current buffer without the file name.
$(VIM_FILEEXT)     # File extension of current buffer.
$(VIM_FILETYPE)    # File type (value of &ft in vim)
$(VIM_FILENOEXT)   # File name of current buffer without path and extension.
$(VIM_PATHNOEXT)   # Current file name with full path but without extension.
$(VIM_CWD)         # Current directory (which :pwd returns).
$(VIM_RELDIR)      # File path relativize to current directory.
$(VIM_RELNAME)     # File name relativize to current directory.
$(VIM_ROOT)        # Project root directory.
$(VIM_CWORD)       # Word under cursor.
$(VIM_CFILE)       # File name under cursor.
$(VIM_CLINE)       # Cursor line number in current buffer
$(VIM_GUI)         # has('gui_runnin')?
$(VIM_VERSION)     # Value of v:version.
$(VIM_COLUMNS)     # Current screen width.
$(VIM_LINES)       # Current screen height.
$(VIM_SVRNAME)     # Value of v:servername.
$(VIM_PRONAME)     # Name of current project root directory
$(VIM_DIRNAME)     # Name of current directory
$(VIM_INIFILE)     # Full path name of current ini (.tasks) file.
$(VIM_INIHOME)     # Where the ini file locates.

They will be expanded and replaced in the command and cwd fields. System environment variables with same names are also initialized as the same value. If one of your task has many complex shell commands, you can put the commands in a shell script and execute it in the task:

[project-build]
command=build/my-build-task.sh
cwd=<root>

In this case, you don't have to pass any argument to my-build-task.sh, because the shell script can read environment variable $VIM_FILENAME to access current file name. By utilizing system environment variables with external script file, you can describe many complex tasks in your project. And of course, much more powerful than defining some keymaps for ! command in your vimrc.

There is a :AsyncTaskMacro command for you to display macro help:

From left to right, is the macro name, what does it stand for and current value. You don't have to check the documentation when you are editing your task configuration.

Task running modes

There is an output field in each task's configuration, it can be one of:

  • quickfix: default mode, output to the quickfix window and match with errorformat.
  • terminal: run in a terminal.

Nothing to talk about output=quickfix, and if you set output to terminal your can further specify the terminal type by setting:

let g:asynctasks_term_pos = 'xxx'

to specify what terminal do you want to use, available options are:

Name Type Description
quickfix simulation Default, simulate a terminal in quickfix window (output will not match the errorformat)
vim - Use the old ! command to run your task, some people still like it
tab internal terminal open a new internal terminal in a new tab
TAB internal terminal similar to tab but open in the left side (easy to return to the previous tab)
top internal terminal open a reusable internal terminal above current window
bottom internal terminal open a reusable internal terminal under current window
left internal terminal open a reusable internal terminal on the left
right internal terminal open a reusable internal terminal on the right
external external terminal use a new system terminal to run your task
hide hidden run in the background

You can set a pos field in a task to override global g:asynctasks_term_pos value in the given task.

Almost all the possible methods are here, choose your favorite one.

When output is terminal, and if you set:

let g:asynctasks_term_pos = 'bottom'

Command :AsyncTask file-run will open an internal terminal under your current window:

If the previous terminal session has finished, the window will be resused. When you set g:asynctasks_term_pos to one of top, bottom, left and right, these two options below can allow you change the terminal size:

let g:asynctasks_term_rows = 10    " set height for the horizontal terminal split
let g:asynctasks_term_cols = 80    " set width for vertical terminal split

If a terminal split window is too small for you, you can setup:

let g:asynctasks_term_pos = 'tab'

A whole tab can be used to display the internal terminal:

Almost all the vim screen are occupied, is it big enough to fit your need ? This is my most favorite one.

The default quickfix can also be used to run your task, but it is not capable to handle user input, and if your program will interact with user, you may choose a real terminal.

Bonus:

  • tab terminal can also be reusable if you set g:asynctasks_term_reuse to 1.
  • you can prevent focus changing if you set g:asynctasks_term_focus to 0 (split terminals only).

(When you are using internal terminal, asynctasks.vim encourage you to setup ALT+HJKL to jump around windows and ALT+q to exit to terminal normal mode).

Run in an external terminal

Many desktop developer using Visual Studio on Windows prefer to run their programs in a new cmd window, we can use external for this:

let g:asynctasks_term_pos = 'external'

Then, every task with output=terminal will open a new cmd window:

Familiar feeling like you are working in Visual Studio.

asynctasks.vim provide you all the possible ways to run a command in vim with no compromise. Choose one you like.

Extra runners

Powered by AsyncRun's customizable runners, tasks can be executed in any way you want. Here is a list of pre-included runners:

Runner Description Requirement Link
gnome run in a new gnome terminal GNOME gnome.vim
gnome_tab run in a new gnome terminal tab GNOME gnome_tab.vim
xterm run in a xterm window xterm xterm.vim
tmux run in a separated tmux pane Vimux tmux.vim
floaterm run in a new floaterm window floaterm floaterm.vim
floaterm_reuse run in a reusable floaterm window floaterm floaterm_reuse.vim
quickui run in a quickui window vim-quickui quickui.vim
toggleterm run in a toggleterm window toggleterm.nvim toggleterm.vim
termhelp run in terminal help vim-terminal-help termhelp.vim
xfce run in a new xfce terminal xfce4-terminal xfce.vim
konsole run in a new konsole terminal KDE konsole.vim
macos run in a macOS system terminal macos macos.vim
iterm run in a new iterm2 tab macos + iTerm2 iterm.vim

When a runner is defined for AsyncRun, it can be used by providing a pos option:

[file-run]
command=python "$(VIM_FILEPATH)"
cwd=$(VIM_FILEDIR)
output=terminal
pos=gnome

Then use:

:AsyncTask file-run

The task will be executed in the gnome-terminal:

If you have many tasks need this pos option, no need to specify them one-by-one, the global settings may be helpful:

let g:asynctasks_term_pos = 'gnome'

After that, every task with output=terminal option could be executed in the gnome-terminal.

Remember, the output option must be terminal and the local option pos has higher priority and can override global option g:asynctasks_term_pos.

It is quite easy to create a new runner, see the customize-runner.

Advanced Topics

Continue hacking in asynctasks.vim:

Ask for user input

Some tasks, eg finding strings in current project, may need to ask user to input some keywords before start.

If command field contains macros in the $(-...) pattern:

[task1]
command=echo hello $(-name), you are a $(-gender).
output=terminal

When you start the task by:

:AsyncTask task1

You are required to input the values of $(-name) and $(-gender) in the prompt area:

There are two variable you need to provide, input them one by one, press ESC to give up and ENTER to confirm. The task will start when you finished:

As you see, $(-name) has been substituted with the value you just provided.

Input value can also be provided as command arguments of AsyncTask {name}:

:AsyncTask task1 -name=Batman -gender=boy

If the value is present in the arguments, AsyncTask will not ask you repeatly.

Hint: use $(-prompt:default) to provide a default value, $(-prompt:) to remember input history. and $(-gender:&male,&female) to provide multiple choices.

Real example used by myself:

[grep]
command=rg -n --no-heading --color never "$(-word)" "<root>" -tcpp -tc -tpy -tvim -tgo -tasm
cwd=$(VIM_ROOT)
errorformat=%f:%l:%m

Here is my global grep task. Each time I use :AsyncTask grep in any of my project, it prompts me to input word before searching, I can use <C-r><C-w> to pickup word under cursor or input something new.

The value of word can also be provided in the arguments:

:AsyncTask grep -word=hello

If I need other filetypes to search in certain project, I can redifine a new grep with different parameters for this project.

But most of time, a global grep task is enough, rg supports .ignore files for different files, I can use them to prevent searching in unnecessary files. Check rg documentation for --ignore-file.

Internal variables

Internal variables can be used in many ways, e.g., to manage multiple building targets. They are defined in the [+] section of .tasks files:

[+]
build_target=build_x86
test_target=test_x86

[project-build]
command=make $(+build_target)
cwd=<root>

[project-test]
command=make $(+test_target)
cwd=<root>

Patterns which match $(+var_name) in the command field will be substituted with the corresponding value defined in the [+] section.

Which means, the new command in "project-build" will become:

make build_x86

It is a efficient way to switch current building target by changing the variable values in the [+] section without modifying the command option every time.

Internal variables can be provided in the argument list as +varname=value:

:AsyncTask project-test  +test_target=mytest

Default values can be defined as $(+varname:default) form, it will be used if variables are absent in both [+] section and :AsyncTask xxx arguments.

[project-test]
command=make $(+test_target:testall)
cwd=<root>

The global dictionary g:asynctasks_environ is the third way to define a variable, it's a convenient place for vimscript:

let g:asynctasks_environ = {'foo': '100', 'bar': '200' }

Same variable can be defined in the different places, priorities are:

  • Low priority: global [+] section.
  • Normal priority: local [+] section.
  • High priority: vimscript object g:asynctasks_environ.
  • The highest priority: +varname=value arguments of :AsyncTask command.

The one with higher priority will overshadow the lower one. By utilizing this feature, we can simplify most similar tasks.

e.g. we have two tasks file-build and project-find in the global config ~/.vim/tasks.ini:

[file-build]
command=gcc -O2 -Wall "$(VIM_FILEPATH)" -o "$(VIM_PATHNOEXT)" $(+cflags:) 
cwd=$(VIM_FILEDIR)

[project-find]
command=rg -n --no-heading --color never "$(-word)" "<root>" $(+findargs:)
cwd=$(VIM_ROOT)
errorformat=%f:%l:%m

Both of them have introduced a variable with a default value of empty string. Sometimes, we don't need to redefine the tasks, just init the two variables in the local .tasks:

[+]
clags=-g -gprof
findargs=-tcpp

It's more flexable if we have the same local tasks with similar arguments.

Task with different profiles

One task can have many different profiles:

[task1:release]
command=gcc -O2 "$(VIM_FILEPATH)" -o "$(VIM_PATHNOEXT)"
cwd=$(VIM_FILEDIR)

[task1:debug]
command=gcc -g "$(VIM_FILEPATH)" -o "$(VIM_PATHNOEXT)"
cwd=$(VIM_FILEDIR)

Here we have task1 with two different profiles release and debug. The default profile is debug, change it to release by:

:AsyncTaskProfile release

or

let g:asynctasks_profile = 'release'

Then, :AsyncTask task1 will run tasks1 with profile release.

Bonus: When using AsyncTaskProfile command with more than one arguments:

:AsyncTaskProfile debug release

A dialog will popup to allow you pick between debug and release, and previous selected item is remembered.

Different system with different commands

This plugin can select command for given system:

[task1]
command=echo default
command/win32=echo win32 default
command/linux=echo linux default
command:c,cpp/win32=echo c/c++ for win32
command:c,cpp/linux=echo c/c++ for linux

Both filetype and system can be used as filter. Default command (the first one) will be chosen if mismatch.

Change this option to specify your system:

let g:asynctasks_system = 'macos'

Then command ending with /macos will be selected.

Data source for fuzzy finders

A fuzzy finder can help you pick a task easily:

This plugin have some apis to fetch task information, which makes integration very easy:

let current_tasks = asynctasks#list("")

It returns a list of items, each item represents a task. And it can be used as the data source for fuzzy finders like fzf.vim or Leaderf.

Here is an instruction to integrate with fzf, leaderf, coc-list and fzf-lua.

Extensions

Existing UI extensions for fuzzy-finders:

Extension Author Description
fzf-lua-asynctasks Yaroslav Mazuryk fzf-lua integration
telescope-asynctasks.nvim Gustavo Sampaio telescope integration
coc-tasks voldikss coc integration

Run last task

There is a command to run last task without typing its name again:

:AsyncTaskLast

Can be binded to a hotkey for repeatedly running task.

Options

The g:asynctasks_config_name option

Don't like the .tasks file name ? Rename it as you want:

let g:asynctasks_config_name = '.asynctask'
let g:asynctasks_config_name = '.git/tasks.ini'

When you get multiple local configurations to load, a comma separated list (or just a list) can also be accepted:

let g:asynctasks_config_name = '.tasks,.git/tasks.ini,.svn/tasks.ini'
let g:asynctasks_config_name = ['.tasks', '.git/tasks.ini', '.svn/tasks.ini']
The g:asynctasks_rtp_config option

Don't like the global tasks.ini file name in your ~/.vim ? Change it to:

let g:asynctasks_rtp_config = "asynctasks.ini"
The g:asynctasks_extra_config option

A list of additional global task configuration files, you can indicate other global configurations:

let g:asynctasks_extra_config = [
    \ '~/github/my_dotfiles/my_tasks.ini',
    \ '~/.config/tasks/local_tasks.ini',
    \ ]

Then, these two additional globla configurations will be loaded after reading ~/.vim/tasks.ini.

The g:asynctasks_term_pos option

What terminal do you want to run your task. see Task running modes.

The g:asynctasks_term_cols option

Internal terminal width when using vertical split.

The g:asynctasks_term_rows option

Internal terminal height when using horizontal split.

The g:asynctasks_term_focus option

Set to zero to keep focus when using an internal terminal in a new split.

The g:asynctasks_term_reuse option

Set to 1 to reuse internal terminal when open it in a new tab.

The g:asynctasks_term_hidden option

If it is set to 1, the internal terminal buffers will set bufhidden to hide.

The g:asynctasks_term_listed option

Set to zero to hide terminal buffer from buffer list (set nolisted).

The g:asynctasks_term_close option

Set to 1 to close the terminal window when task finished.

The g:asynctasks_confirm option

Set to zero to skip filename confirmation in :AsyncTaskEdit.

The g:asynctasks_filetype option

The filetype of the task configuration file, default to "taskini".

The g:asynctasks_template option

Command :AsyncTaskEdit accept a template file name, the content of template will be used if you are creating a new task config file:

let g:asynctask_template = '~/.vim/task_template.ini'

And templates can be defined in your ~/.vim/task_template.ini like:

{cmake}

[project-init]
command=mkdir build && cd build && cmake ..
cwd=<root>
[project-build]
command=cmake --build build
cwd=<root>
errorformat=%. %#--> %f:%l:%c
[project-run]
command=build/$(VIM_PRONAME)
cwd=<root>
output=terminal

{cargo}

[project-init]
command=cargo update
cwd=<root>
[project-build]
command=cargo build
cwd=<root>
[project-run]
command=cargo run
cwd=<root>
output=terminal

Command:

:AsyncTaskEdit cargo

Will create a new file with the template "cargo", if the file doesn't exist.

Specification

A full configuration specification can be found here:

And there are many examples about: cmake, grep, ninja, wsl and more:

Command Line Tool

This plugin provides you an asynctask.py script (in the bin folder) when you want to run tasks right in your shell:

# run tasks in any child directory of your project 
# no need to go back to project root directory, because "cwd=<root>".
$ asynctask project-build

# compile a file
$ asynctask file-build hello.c

# run a file
$ asynctask file-run hello.c

Use fzf to select task:

For more information, please visit:

Frequently Asked Questions

See the:

Credit

Like asynctasks.vim ? Star this repository on GitHub, this is really helpful. And if you're feeling especially charitable, follow skywind3000 on Twitter and GitHub.

asynctasks.vim's People

Contributors

cstsunfu avatar gitter-badger avatar roachsinai avatar shatur avatar skywind3000 avatar webdavis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

asynctasks.vim's Issues

CLITool Error: not find asynctask.py

Ubuntu 18.04LTS

Error: not find asynctask.py
这个怎么解决啊?谢谢

我的 asynctasj.vim 放在 /home/myname/ 下面
按照作者大大的文档 把 /home/myname/asynctask.vim/bin/asynctask
软链接到 /usr/myname/bin下面
然后 把/usr/myname/bin 加入到用户的 .bashrc的PATH里
export PATH=~/bin:$PATH

这时候 在 /home/myname/bin 执行task 一切正常
但是在 /目录执行就报错了
Error: not find asynctask.py

尝试了以下解决方案 都不行

在 /home/myname/bin 目录增加了一个软链接 asynctask.py 连接到/home/myname/asynctask.vim/bin/asynctask.py
同样报错

把整个asynctask.vim全部复制到 /home/myname/bin目录
同样报错

在 /etc/profile 增加配置
export PATH=~/bin:$PATH
使用 $PATH命令 是可以看到PATH目录包含 /home/myname/bin的
但是在 /目录 执行task 还是报错
Error: not find asynctask.py

在 /home/myname/bin 目录就可以正确执行

CWD subdirectory ignored

I am using the following config:

[debugging]
command=pwd && ls -a
cwd=$(VIM_ROOT)/debug
output=terminal

Unless the debug folder contains a Makefile, pwd prints the project root directory. Is this the desired behaviour? Thank you!

Add the ability to create an empty tasks file

Hi! Thank you for your plugin.
Currently command :AsyncTaskEdit will create an example tasks file if it does not exists. I suggest to add a configuration parameter that will allow to create an empty file in this case. It may be very useful with snippets. For example, I can create snippet for regular CMake project, open tasks file and use my custom template.

Running tasks sequentially

Is it possible to run tasks sequentially? For example, in most IDEs, when a project starts, compilation occurs first. It would be convenient to assign build + run to a single key.

P.S. Sorry for a lot of issues :)

Floaterm position

[test1]
command=ls
cwd=
output=terminal
pos=floaterm_reuse
position=bottomright
focus=0

when I use above settings.I can't work right.Can realize 'position' and 'focus' when 'pos = floaterm_reuse'?
By the way, 'Asyncrun -term=mode -pos=floaterm_reuse -position=bottomright ls' works right.

Unable to get errorformat to work with CMake

Hi! I trying to configure errorformat for CMake.
Here is the example project with few files.
Here is my configuration taken from the wiki:

[project-build:debug]
command=cd ../build-$(VIM_PRONAME)-debug && cmake --build .
cwd=<root>
errorformat=%f:%m:%l
notify=echo

If I remove, for example, ; after KeyboardDaemon daemon in main.cpp I have the following error:

|| [cd ../build-akd-debug && cmake --build .]
|| [1/2] Building CXX object CMakeFiles/akd.dir/src/main.cpp.o
|| FAILED: CMakeFiles/akd.dir/src/main.cpp.o 
|| /usr/bin/c++    -std=gnu++17 -MD -MT CMakeFiles/akd.dir/src/main.cpp.o -MF CMakeFiles/akd.dir/src/main.cpp.o.d -o CMakeFiles/akd.dir/src/main.cpp.o -c /mnt/Files/Git/akd/src/main.cpp
|| /mnt/Files/Git/akd/src/main.cpp: В функции «int main()»:
|| /mnt/Files/Git/akd/src/main.cpp:31:9: ошибка: expected initializer before «daemon»
||    31 |         daemon.exec();
||       |         ^~~~~~
|| ninja: build stopped: subcommand failed.
|| [Finished in 1 seconds with code 1]

But :cnext/:cprev not works to jump between errors. Is this a bug or am I doing something wrong?

can async task work with visual selection?

I checked out the macro section and don't see anything specifying visual selection, is there anyway to invoke a task and pass the current visual selection to it? for example, to search it on some website or invoke some script with it. VIM_CWORD is the closest I can find, but it's much less flexible than visual selection. async task seems heavily file oriented, I think it can be more useful by working with other vim elements, such as visual selection. thanks.

How to escape '[' and ']'?

I have a task with:

errorformat=%f:%l:%c:\ %m,%-G%.%#errors\ generated.,%-Gmake%m,%-G[%[0-9\ ]%\\\{\\,3}%%]%m

And this part: %-G[%[0-9\ ]%\\\{\\,3}%%]%m does not work because the [ ] characters are there I think.

How do I escape them so that nvim will see:
errorformat=%f:%l:%c:\ %m,%-G%.%#errors\ generated.,%-Gmake%m,%-G[%[0-9\ ]%\\\{\\,3}%%]%m

Feature request: Dropdown when asking for user input

Any way to get a dropdown when asking for user input?

[task1]  
command=echo hello $(?your name), you are a $(?gender[male,female]).  
output=terminal

Not sure if we can use the default vim autocomplete or we would expose a way to use fzf.

How to use cwd setting?

Regardless of what I set for cwd under a file-run task, it seems like the task always runs with the current vim directory (not the cwd I set).

Here's my .tasks file, located in the project root (next to the .git folder):

[file-run]
command=make test
# working directory
cwd="$(VIM_FILEDIR)/.."
output=terminal

Here's the project structure:

root
├── .tasks
└── c
    └── hello-world
        ├── README.md
        ├── makefile
        ├── src
        │   ├── hello_world.c
        │   └── hello_world.h
        ├── test
        │   └── test_hello_world.c
        └──── tests.out

If I launch vim in the hello-world dir, then run the file-run task, it works fine (correctly calling make with the makefile). But if I launch vim in any other directory, it fails, as make cannot find the makefile.

I also tried using an absolute path for cwd, but it didn't work either. As a workaround, this is what I'm doing now:

command=cd "$(VIM_FILEDIR)/.." && make test

How can I set the cwd to be used for the command? I tried searching the codebase for opt.cwd, but couldn't find where it was used, so I'd be grateful if you had any ideas.

AsyncTasks seems like a really useful plugin, thanks for all your work on it!

:AsyncTasksEdit allows to open split several times

If I execute :AsyncTasksEdit it will open configuration in split. But If I execute this command More than once - I will have another splits of the same window:
asciicast

Is this expected behavior? As for me it would be nice to just focus previously opened configuration split (as in figitive) or toggle it.

Change local task file location

I would like to have the option to change the locatio nof the local .task file.
personaly I would like to put it in $(VIM_ROOT)/.vim/tasks.json

In the same place as the local coc config file.

maybe add an option like this.

let g:asynctasks_local_tasks_config_prefix='.vim'

链接一个任务名到另一个任务

在开发的时候,我经常会需要在一段时间执行某一个task,并在不同时间进行任务切换。
因此我希望定义一系列任务,并设置一个默认的任务,比如说[run],并将这个任务与vim的快捷键绑定。切换任务时,只需要修改[run]链接到的任务即可,类似如下的配置:

[run]
link=train-peta

[train-peta]
command=python "tools/train.py" "configs/peta.yaml"
cwd=$(VIM_ROOT)
output=terminal
save=1

[train-wider]
command=python "tools/train.py" "configs/wider.yaml"
cwd=$(VIM_ROOT)
output=terminal

请问能否实现?

win7下tasks.ini全局配置不起作用,必须文件名是.tasks才能起作用

windows7系统,tasks.ini和_vimrc在同一目录,目录结构如下:

D:\Program Files (x86)\Vim
|------_vimrc
|------tasks.ini
|------vimfiles
|------vim82(vim程序目录)----gvim.exe

文件名是tasks.ini时完全不起作用,改成.tasks只有VIM目录起作用,VIM以外的其他目录均不起作用。

请大神看看是什么原因,谢谢!

提一个小小的建议🤣

如果可以添加上 job 的 dependency就好了。比如运行 A 命令,可以指定某些命令(自动在运行 A 前触发
就像makefile

Define custom variables

Is it possible to add the ability to define custom variables? For example, I have the following two tasks:

[project-build]
command=cmake --build . --target myawesomprogram
cwd=<root>/../build-$(VIM_PRONAME)-debug
errorformat=%f:%m:%l

[project-run]
command=myawesomprogram --argument example
cwd=<root>/../build-$(VIM_PRONAME)-debug
output=terminal

The first task builds the selected application from the entire project, and the second starts this application. If you need to change the application, then I need to replace its occurrences. It would be convenient to be able to set custom variable at the begging of the file for it.

Alternatively, this variable can be built-in and set from cmd like a profile.

Tasks not found in path with space

Hi,

AsyncTask doesn't seem able to find the tasks defined in ".tasks" when the absolute path contains a space. This will show itself when trying to run ":AsyncTask file-build".

perform task if file exist

How to perform a task : AsyncTask gulp-watch if gulpfile.js exist ?
I try in .vimrc

if filereadable("gulpfile.js")
	AsyncTask gulp-watch
endif

But I've an error :
error function AsyncRun_Job_OnTimer[11]

Conflict with vim-rooter

File tree:

[~/project]$ tree -a                                                     
.
├── .root
├── subdir
│   └── somefile.txt
└── .tasks.ini

1 directory, 3 files

.tasks.ini

[pwd-terminal]
command=pwd
cwd=/home/user/project/subdir
output=terminal

[pwd-quickfix]
command=pwd
cwd=/home/user/project/subdir
output=quickfix

The task pwd-terminal outputs /home/user/project, the task pwd-quickfix outputs /home/user/project/subdir. Cwd with the $(VIM_ROOT) macro behaves similarly.
I found out that the vim-rooter plugin causes this behavior. When I turn this plugin off pwd-terminal task starts printing the correct path /home/user/project/subdir. Correct behavior also happens when I remove .root file because of different pattern settings:

let g:asynctasks_config_name = '.tasks.ini'
let g:asyncrun_rootmarks = ['.tasks.ini', '.root']
let g:rooter_patterns = ['.root']

:echo asyncrun#get_root('%') prints /home/user/project

Arch Linux 5.11.9
NVIM v0.4.4
Build type: Release
LuaJIT 2.0.5

Make $(VIM_FILEDIR) valid in nofile buffer

elseif expand('%:p') == ''
for name in disable
for mode in ['$(VIM_', '$(WSL_']
let macro = mode . name . ')'
if stridx(a:command, macro) >= 0
let t = 'macro ' . macro . ' is empty'
call s:warning(t . ' in current buffer')
return 3
elseif stridx(a:cwd, macro) >= 0
let t = 'macro ' . macro . ' is empty'
call s:warning(t . ' in current buffer')
return 4
endif
endfor
endfor
endif

问题:

打开一个 buftype'nofile' 的 buffer,如果执行的命令里面带有 $(VIM_FILEDIR),会报错 Warning: macro $(VIM_FILEDIR) is empty in current buffer.

原因

对于 buftype'nofile' 的 buffer, expand("%:p") 为空字符串,但是 expand("%:p:h") 却返回该缓冲区所在的文件夹路径且不为空,并且在同样的 buffer 里面, $(VIM_FILEDIR) 这个宏在 asyncrun.vim 里也工作正常。

因此可不可以将 $(VIM_FILEDIR) 排除在 disable 之外呢?

External terminal on linux

When I run a task in an external terminal on Linux, it runs fine, but no terminal opens. Is the a option to customize this?

Pre-command

Is it possible to have a pre-command.

For example, if you run for the first time, then it sets up some variable or something (in my case, i want to use direnv).

So, it takes about 5 seconds to setup direnv and while it sets up it outputs. So i was wondering if i can use a pre-cmd so that it sets it up.

The way i do now is:

command= cd .. && cd $(VIM_ROOT) && cargo run

So basically, i go a dir up, then back to activate direnv. Because direnv is activated only on directory change (it acts as a bash/zsh daemon from .bashrc/.zshrc file). And since Asynctasks always opens in the same directory where VIM is open (or project root directory), direnv can't detect the dir change, thus the cd $(VIM_ROOT) of Asynctasks does not activate direnv.

Having a pre-cmd would be very useful not only for direnv, but other cases too.

my case would be:

pre-command= cd .. && cd $(VIM_ROOT)  # to be activated only once
command= cargo run					  # to ba activated everytime

Introduce a feature to automatically close the quickfix window after a configurable delay when there are no errors or warnings

For example, if I am editing a single-file project (C++ source code) and upon running Asyncrun on it, there are no errors or warnings and the build completed successfully, then after a certain user-configurable delay, I would like the quickfix window to disappear automatically.

I know I can do :ccl[ose], but it quickly becomes tedious. Instead, I just want the quickfix window to be open for just enough time to comfortably read that [finished in x seconds] and then just get out of my way.

Can asyncrun or asynctasks somehow incorporate this?

WIKI Command-Line-Tool Usage TYPO

Command-Line-Tool#Usage

You don't have to jump back to your project root manually, because profile-build has a cwd=<root>.

profile-build should be project-build.

AND

asynctask -profile=release project-build notice -profile=release setting, but no more description, when and where release take effect?

confusion about output=terminal

In vim 8.2.814 on linux, using output=terminal in the .tasks file doesn't seem to do anything special- the output still goes to the quickfix, as viewed with :copen. However, if I add pos=bottom it does open a :terminalas expected. It is not a big deal, but I am a bit confused about the meaning of the terminal option when pos is not specified. Is this the expected behavior?

[project-build]
command=cmake --build build
cwd=<root>
output=terminal
# pos=bottom         # without uncommenting this line, no terminal opens
errorformat=%f:%l:%m

asynctasks_term_pos = 'external' is the same as 'vim'

Arch Linux
Neovim 0.5.0

asynctasks_term_pos = 'external' does not open external terminal, instead it runs the same as asynctasks_term_pos = 'vim'

Task:

[file-run]
command=fish "$(VIM_FILENAME)"
cwd=$(VIM_FILEDIR)
output=terminal
save=1

Async settings:

let g:asyncrun_open = 6
let g:asynctasks_term_pos = 'external'

Setting the command variable prompt to utf-8 is not supported and entering utf-8 strings is not supported.

There are actually two problems.

Setting the command variable prompt to utf-8 is not supported

The following is my command profile

How to reproduce

 [test]
 command=echo $(?输入你的名字)
 cwd=<root>

Phenomenon

It will complain

Traceback (most recent call last):
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 1242, in <module>
    exit(main())
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 1170, in main
    tm.interactive(mode)
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 1080, in interactive
    return self.task_run(text)
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 918, in task_run
    command = self.command_input(command)
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 852, in command_input
    text = raw_input(prompt)  # noqa: F821
UnicodeEncodeError: 'ascii' codec can't encode characters in position 16-21: ordinal not in range(128)

entering utf-8 strings is not supported

How to reproduce

my command profile

 [test]
 command=echo $(?enter your name)
 cwd=<root>

and input

> $ task                                                             ⬡ 12.16.1 
Input argument (enter your name): 你好,世界

Phenomenon

it would complain

Traceback (most recent call last):
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 1242, in <module>
    exit(main())
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 1170, in main
    tm.interactive(mode)
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 1080, in interactive
    return self.task_run(text)
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 918, in task_run
    command = self.command_input(command)
  File "/Users/johnd/program/asynctasks.vim/bin/asynctask.py", line 860, in command_input
    command = command.replace(mark, text)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

Run detached tasks

I made the following global tasks:

[project-open-build]
command=xdg-open $(VIM_ROOT)/../build-$(VIM_PRONAME)-$(VIM_PROFILE)
silent=1

[project-open-source]
command=xdg-open $(VIM_ROOT)
silent=1

It allow me to quickly open build and source folders. But if I am running compilation or a compiled program, then I can not use the above tasks. Is it possible to just run such tasks without any callbacks and output even if the main task is currently running? Something like save=2 but silent=2.

windows下无法识别路径?

在windows下用neovim,用户名中有空格时,无法识别路径?报错如下:

'C:\Users\XXX' 不是内部或外部命令,也不是可运行的程序
或批处理文件。用户文件夹为XXX XX

bottom:内置终端,不可以复用内部终端

bottom:内置终端,不可以复用内部终端
每次运行都打开一个终端
vimrc配置:
noremap :AsyncTask file-run
noremap :AsyncTask file-build
let g:asyncrun_open = 6
let g:asynctasks_term_pos = 'bottom'
let g:asynctasks_term_rows = 5

tasks.ini配置:
[file-build]
command=gcc "$(VIM_FILEPATH)" -o "$(VIM_FILEDIR)/$(VIM_FILENOEXT)"
command:go=go build -o "$(VIM_PATHNOEXT)" "$(VIM_FILEPATH)"
cwd=$(VIM_FILEDIR)
output=quickfix
errorformat=%f:%l:%m
save=2

[file-run]
command="$(VIM_FILEPATH)"
command:c,cpp="$(VIM_PATHNOEXT)"
command:go=go run "$(VIM_FILEPATH)"
command:python=python "$(VIM_FILENAME)"
output=terminal
cmd=$(VIM_FILEDIR)
save=2

Add the ability to skip :AsyncTaskEdit confirmation

When executing the command :AsyncTaskEdit is proposed to confirm the path to the file with tasks with the possibility of changing it. Could you add an option to bypass this confirmation and always open the file?

[request] autocmd support for tasks

Working on a rust project, I am setting up:

autocmd BufWritePost * AsyncTask cargo-run

This is perfect to compile and run tiny programs every time I edit the file.
But I cannot set this in global .vimrc since this would be run for all files immaterial of the project (cwd).

Would it be possible to support auto triggering of AsyncTasks on BufWritePost events ?

I considered using localvimrc plugin to inject autocmds.
But that would be another file I need to maintain.
https://www.vim.org/scripts/script.php?script_id=3393

能不能支持下多个asynctasks_config_name?

一个名字里面搜索到配置文件后就可以不管别的名字了.
方便不同项目tasks放在不同的位置里. (自己的放.tasks, 别的不能改的项目放.git 或者.svn里)

let asynctasks_config_name= [
    \ '.tasks',
    \ '.root/.tasks',
    \ '.git/.tasks',
    \ '.svn/.tasks',
    \ ]

Can't recognized root directory when use terminal to output

Hello! It's a nice vim plugin and I get a lot of benefit from it!
But I meet a problem that I can't change to my root directory on terminal output mode. Here is my project tree.

.
├── .root
├── src
│   └── 1.cpp
└── .tasks

When I open 1.cpp in src directory, and run asynctasks configured like that:

[file-build]
command=pwd
cwd=$(VIM_ROOT)

output=terminal

It shows

/home/qsdrqs/test/src

[Process exited 0]

When I change output into quickfix, it shows

|| [pwd]
|| /home/qsdrqs/test
|| [Finished in 0 seconds]

In a word, the "terminal" mode may not works well in changing directory.

Add profile name variable

Could you add a variable for profile name (release, debug)?
The following actions

[project-run:release]
command=cd ../build-$(VIM_PRONAME)-release && ./$(VIM_PRONAME)
cwd=<root>
notify=echo

[project-run:debug]
command=cd ../build-$(VIM_PRONAME)-debug && ./$(VIM_PRONAME)
cwd=<root>
notify=echo

could be simplified to

[project-run]
command=cd ../build-$(VIM_PRONAME)-$(VIM_PROFILE) && ./$(VIM_PRONAME)
cwd=<root>
notify=echo

:AsyncTaskEdit not respect :vert

If I use :vert AsyncTaskEdit it still opens horizontal split. Is it possible to change this behavior? For example, fugitive allows to pass :vert to G command. Or maybe add an option where to open configuration buffer?

[error] Get an error when a command contains setting environment variable which has 'VERSION' as part of its name

If I set such a command in tasks.ini:

[hi]
command=MY_VERSION=1.2 echo hello

When I execute it in asynctask, I would get such an error:

Error: $(VIM_VERSION) is invalid in command line
from /XXX/XXX/.config/asynctask/tasks.ini:
command=MY_VERSION=1.2 echo hello

I've verified that so long as the variable's name contains 'VERSION' it would have this problem.
It seems that this env variable breaks VIM_VERSION, but they don't have the same name. Is there any fix for this?

AsyncTaskProfile not switching profiles

  • editor: nvim
  • editor-version:
NVIM v0.5.0-397-g96059d72e
Build type: RelWithDebInfo
LuaJIT 2.1.0-beta3
Compilation: /usr/bin/gcc-5 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -O2 -g -Og -g -Wall -Wextra -pedantic -Wno-unused-parameter -Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion -Wmissing-prototypes -Wvla -fstack-protector-strong -fno-common -fdiagnostics-color=auto -DINCLUDE_GENERATED_DECLARATIONS -D_GNU_SOURCE -DNVIM_MSGPACK_HAS_FLOAT32 -DNVIM_UNIBI_HAS_VAR_FROM -DMIN_LOG_LEVEL=3 -I/home/travis/build/neovim/bot-ci/build/neovim/build/config -I/home/travis/build/neovim/bot-ci/build/neovim/src -I/home/travis/build/neovim/bot-ci/build/neovim/.deps/usr/include -I/usr/include -I/home/travis/build/neovim/bot-ci/build/neovim/build/src/nvim/auto -I/home/travis/build/neovim/bot-ci/build/neovim/build/include
Compiled by travis@travis-job-13ebc8c2-4f6f-45b7-ad53-0dc3d8813d5f

Features: +acl +iconv +tui
See ":help feature-compile"

   system vimrc file: "$VIM/sysinit.vim"
  fall-back for $VIM: "/share/nvim"

Bug

I have defined the following two profiles in my ~/.vim/tasks.ini file:

[project-run:default]
command:java=mvn exec:java
cwd=<root>
output=quickfix
errorformat=%f:%l:%m
save=0


[project-run:io]
command:java=mvn exec:java
cwd=<root>
output=terminal
errorformat=%f:%l:%m
save=0

However, when I run AsyncTaskProfile io I get the message Current profile: default. The only way that I can change it is by running :let g:asynctasks_profile = 'io'.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.