How to use Ansible to configure Vim
In the article Top five Vim plugins for sysadmins, I covered five plugins plus a bonus that make life easier for sysadmins when using Vim. This article will expand on that by developing an Ansible playbook to configure an initial Vim environment using those plugins.
This playbook works on the Fedora Linux system but should work similarly with other distributions by making small modifications. In each of the following sections, we'll discuss the changes required to make it work on other systems.
Note: This playbook overwrites an existing .vimrc
configuration file, so it's more useful to set up a new system that does not have Vim configured yet. If you have an existing Vim configuration file, back it up before running this playbook.
To run this playbook, you have to install Ansible. In Fedora, you can install Ansible using dnf
, like this:
$ sudo dnf install -y ansible
For more details about Ansible installation options, check the Ansible Installation Guide.
1. Starting the playbook
Create your Ansible playbook file vim-config.yaml
and edit it using your favorite text editor. If you are new to Ansible, check this playbook link to learn more about it.
$ vi vim-config.yaml
[ You might also like: An introduction to the vi editor ]
Now, start your playbook definition by providing a name and the list of target hosts. In this case, we'll target only the localhost
to configure Vim locally.
- name: Config Vim with plugins
hosts: localhost
Next, set the gather_facts: yes
option to collect facts about your system. You'll need that to access the environment variables in the next step:
gather_facts: yes
Finally, set the global option become: no
to indicate that, in general, these tasks do not require privilege escalation. We'll set privilege escalation locally for individual tasks that require it, such as installing system packages.
become: no
Next, define some useful variables.
2. Defining variables
Configuring Vim and Vim plugins requires adding content to the $HOME/.vim
directory and to the $HOME/.vimrc
configuration file. To ensure that we use these values consistently and avoid retyping them many times, let's define two variables to store their values:
vars:
vim_dir: "{{ ansible_env.HOME }}/.vim"
vimrc: "{{ ansible_env.HOME }}/.vimrc"
Notice that we're using the ansible_env.HOME
fact variable to retrieve the value of the $HOME
environment variable. For more information about obtaining environment variables, consult the documentation.
Now, let's start defining the tasks the playbook executes.
3. Installing required packages
The next step in creating a playbook is defining the tasks the playbook will run. Start by providing the tasks:
playbook parameter:
tasks:
As the first task is to install system packages required by some of the Vim plugins we'll install later. Use the package module to install them and provide the parameter become: yes
to enable privilege escalation, which is required to install system packages:
- name: Install required packages
package:
name:
- vim-enhanced
- git
- powerline-fonts
- fzf
state: installed
become: yes
The package
module works across different distributions, but the package names are different. These values are valid for Fedora 32. If you're running this playbook in a different distribution, change the package names according to your distribution requirements.
Next, create the .vim
directory structure.
4. Creating directories
Use the file module with the parameter state: directory
to create the required directories. Since there are three directories, execute this module in a loop to create all of them with a single task:
- name: Ensure .vim/{autoload,bundle} directory exists
file:
path: "{{ item }}"
state: directory
recurse: no
mode: 0750
loop:
- "{{ vim_dir }}"
- "{{ vim_dir }}/autoload"
- "{{ vim_dir }}/bundle"
Notice that we're using the vim_dir
variable we defined earlier to represent the .vim
directory. We are using the Jinja2 syntax {{ vim_dir }}
.
Now that the directories are in place, you need to download Pathogen.
5. Downloading Pathogen
For this example, let's use Vim-Pathogen as the Vim plugin manager. To install it using Ansible, apply the get_url module to download the plugin file directly to its destination directory:
- name: Ensure Pathogen is in place
get_url:
dest: "{{ vim_dir }}/autoload/pathogen.vim"
url: https://tpo.pe/pathogen.vim
Next, deploy the required plugins.
6. Deploying plugins from Git
Once Pathogen is installed, let's use the git module to deploy the required plugins by cloning their GitHub repository into the destination directory. Similar to creating directories, use a loop to clone all repositories with a single task:
- name: Deploy plugins
git:
dest: "{{ vim_dir }}/bundle/{{ item.name }}"
repo: "{{ item.url }}"
clone: yes
update: yes
recursive: no
loop:
- name: vim-airline
url: https://github.com/vim-airline/vim-airline
- name: nerdtree
url: https://github.com/preservim/nerdtree
- name: fzf-vim
url: https://github.com/junegunn/fzf.vim
- name: vim-gitgutter
url: https://github.com/airblade/vim-gitgutter
- name: vim-fugitive
url: https://github.com/tpope/vim-fugitive
- name: vim-floaterm
url: https://github.com/voldikss/vim-floaterm
Notice that we're using a list of dictionaries as input for the loop and using their values with the syntax {{ item.KEY }}
where required as input for the module parameters.
Next, copy a basic configuration file for Vim.
7. Copying the initial configuration file
As the final task, use the copy module to copy a basic configuration file for Vim. First, create the configuration file under a sub-directory files
:
$ mkdir files
$ vim files/vimrc
execute pathogen#infect()
syntax on
filetype plugin indent on
colo darkblue
" Configuration vim Airline
set laststatus=2
let g:airline#extensions#tabline#enabled=1
let g:airline_powerline_fonts=1
" Configuration NERDTree
map <F5> :NERDTreeToggle<CR>
" Configuration floaterm
let g:floaterm_keymap_toggle = '<F12>'
let g:floaterm_width = 0.9
let g:floaterm_height = 0.9
" Configuration Vim.FZF
let g:fzf_preview_window = 'right:50%'
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
Then, use the copy
module to copy the file to the target destination:
- name: Ensure .vimrc config in place
copy:
src: vimrc
dest: "{{ vimrc }}"
backup: yes
mode: 0640
Notice that you don't need to specify the directory files
in the src
path. By default, Ansible looks for files to copy in this sub-directory.
Finally, execute the playbook.
8. Putting it all together
Your playbook is done. For reference, here's the complete playbook:
- name: Config Vim with plugins
hosts: localhost
gather_facts: yes
become: no
vars:
vim_dir: "{{ ansible_env.HOME }}/.vim"
vimrc: "{{ ansible_env.HOME }}/.vimrc"
tasks:
- name: Install required packages
package:
name:
- vim-enhanced
- git
- powerline-fonts
- fzf
state: installed
become: yes
tags:
- install_packages
- name: Ensure .vim/{autoload,bundle} directory exists
file:
path: "{{ item }}"
state: directory
recurse: no
mode: 0750
loop:
- "{{ vim_dir }}"
- "{{ vim_dir }}/autoload"
- "{{ vim_dir }}/bundle"
- name: Ensure Pathogen is in place
get_url:
dest: "{{ vim_dir }}/autoload/pathogen.vim"
url: https://tpo.pe/pathogen.vim
- name: Deploy plugins
git:
dest: "{{ vim_dir }}/bundle/{{ item.name }}"
repo: "{{ item.url }}"
clone: yes
update: yes
recursive: no
loop:
- name: vim-airline
url: https://github.com/vim-airline/vim-airline
- name: nerdtree
url: https://github.com/preservim/nerdtree
- name: fzf-vim
url: https://github.com/junegunn/fzf.vim
- name: vim-gitgutter
url: https://github.com/airblade/vim-gitgutter
- name: vim-fugitive
url: https://github.com/tpope/vim-fugitive
- name: vim-floaterm
url: https://github.com/voldikss/vim-floaterm
- name: Ensure .vimrc config in place
copy:
src: vimrc
dest: "{{ vimrc }}"
backup: yes
mode: 0640
Now, save your file, and then close the text editor.
Execute the playbook using the ansible-playbook
command and the playbook name. Since this playbook targets the localhost
only, an inventory is not strictly required. You can still create one. Also, because one of the tasks requires privilege escalation, provide the parameter -K
to type your sudo
password, allowing Ansible to execute those tasks.
Note: Backup an existing .vimrc
configuration file before running this playbook.
$ ansible-playbook -K vim-config.yaml
BECOME password:
PLAY [Config Vim with plugins] *************************************
TASK [Gathering Facts] *********************************************
ok: [localhost]
TASK [Install required packages] ***********************************
changed: [localhost]
TASK [Ensure .vim/{autoload,bundle} directory exists] **************
changed: [localhost] => (item=/home/ricardo/.vim)
changed: [localhost] => (item=/home/ricardo/.vim/autoload)
changed: [localhost] => (item=/home/ricardo/.vim/bundle)
TASK [Ensure Pathogen is in place] *********************************
changed: [localhost]
TASK [Deploy plugins] **********************************************
changed: [localhost] => (item={'name': 'vim-airline', 'url': 'https://github.com/vim-airline/vim-airline'})
changed: [localhost] => (item={'name': 'nerdtree', 'url': 'https://github.com/preservim/nerdtree'})
changed: [localhost] => (item={'name': 'fzf-vim', 'url': 'https://github.com/junegunn/fzf.vim'})
changed: [localhost] => (item={'name': 'vim-gitgutter', 'url': 'https://github.c
changed: [localhost] => (item={'name': 'vim-fugitive', 'url': 'https://github.com/tpope/vim-fugitive'})
changed: [localhost] => (item={'name': 'vim-floaterm', 'url': 'https://github.com/voldikss/vim-floaterm'})
TASK [Ensure .vimrc config in place] *******************************
changed: [localhost]
PLAY RECAP *********************************************************
localhost : ok=5 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can now test your new Vim configuration by running vim
:
[ Need more on Ansible? Take a free technical overview course from Red Hat. Ansible Essentials: Simplicity in Automation Technical Overview. ]
What's next?
You created a playbook to automate deploying a basic Vim configuration with six useful plugins for sysadmins. If you want to use the same playbook to deploy additional plugins, add them to the loop list in the Deploy plugins
tasks. Also, add any required system packages to the Install required packages
tasks.
Using this playbook, you can quickly deploy and update your Vim configuration using Infrastructure as Code principles.
For more information about Ansible, consult its official documentation.
Ricardo Gerardi
Ricardo Gerardi is Technical Community Advocate for Enable Sysadmin and Enable Architect. He was previously a senior consultant at Red Hat Canada, where he specialized in IT automation with Ansible and OpenShift. More about me