Skip to main content

How to use Ansible to configure Vim

Using this playbook, you can quickly deploy and update your Vim configuration using Infrastructure as Code principles.
Image
Use Ansible to Configure Vim in Fedora

Photo by Collis from Pexels

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:

Image
Vim opening page

[ 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.

Topics:   Linux   Automation   Ansible  
Author’s photo

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

Try Red Hat Enterprise Linux

Download it at no charge from the Red Hat Developer program.