DEV Community

Cover image for Boost Your Productivity with Terraform Autocompletion in Vim
RoseSecurity
RoseSecurity

Posted on

Boost Your Productivity with Terraform Autocompletion in Vim

Pure Vim

Every so often, when the struggle of jumping between IDE windows, tabs, and extensions catches up to me, I step back and settle into a terminal window with a beautiful, yet simple Vim configuration for my daily DevOps development. In this guide, I will illustrate the process of configuring autocompletion for Terraform code in Vim. This walkthrough uses Vim Plug for plugin installations, so ensure this is downloaded before continuing (or use another plugin manager).

Configuring Terraform's Language Server

What is an LSP?

For us to take advantage of Terraform's auto-completion features, we need to make use of a Language Server Protocol (LSP), which defines the protocol used between an editor or IDE and a language server. This provides language features like auto-complete, go to the definition, find all references, etc. By harnessing a few plugins, we can streamline our Terraform development efforts in pure Vim.

Installing the Terraform LSP

To install the Terraform LSP, we can either utilize Homebrew to download the releases or reference Hashicorp's Official Packaging Guide for further installation instructions. If you choose to use Homebrew, here is the command!

brew install hashicorp/tap/terraform-ls
Enter fullscreen mode Exit fullscreen mode

Installing Vim Plugins

Now that we have the Terraform LSP installed, we need another LSP for language-specific autocompletion. This is where Conquer of Completion (CoC) shines. Before installing CoC, you will need to make sure that you have the necessary dependencies on your system, namely Vim 8 and above and node version 14.14 and above.

To install CoC, simply include the following line in your vimrc and give the command :PlugInstall

Plug 'neoclide/coc.nvim'
Enter fullscreen mode Exit fullscreen mode

For CoC's autocompletion to work, there are numerous configurations. While discussing all of them is beyond this guide's scope, my preferred vimrc is provided below:

"CoC Settings
" Use tab for trigger completion with characters ahead and navigate.
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
" other plugin before putting this into your config.
inoremap <silent><expr> <TAB>
      \ pumvisible() ? "\<C-n>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"

function! s:check_back_space() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

" Make <CR> to accept selected completion item or notify coc.nvim to format
" <C-g>u breaks current undo, please make your own choice.
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
                              \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
"Ultisnips Settings
let g:UltiSnipsExpandTrigger="<tab>"
let g:UltiSnipsJumpForwardTrigger="<c-b>"
let g:UltiSnipsJumpBackwardTrigger="<c-z>"

" If you want :UltiSnipsEdit to split your window.
let g:UltiSnipsEditSplit="vertical"

"coc-snippets Settings
"inoremap <silent><expr> <TAB>
"      \ coc#pum#visible() ? coc#_select_confirm() :
"      \ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
"      \ CheckBackspace() ? "\<TAB>" :
"      \ coc#refresh()
"
"function! CheckBackspace() abort
"  let col = col('.') - 1
"  return !col || getline('.')[col - 1]  =~# '\s'
"endfunction
"
"let g:coc_snippet_next = '<tab>'
Enter fullscreen mode Exit fullscreen mode

To edit CoC's settings after installation, enter Vim and type the command :CoCConfig or configure ~/.vim/coc-settings.json as follows:

{
    "languageserver": {
        "terraform": {
            "command": "terraform-ls",
            "args": ["serve"],
            "filetypes": [
                "terraform",
                "tf"
            ],
            "initializationOptions": {},
            "settings": {}
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

With Terraform and CoC LSPs installed, let's move on to Terraform's plugins: vim-terraform for file types, syntactic for linting, and vim-terraform-completion for auto-completion.

To install these plugins, add the following lines to your vimrc before running :PlugInstall:

Plug 'hashivim/vim-terraform'
Plug 'vim-syntastic/syntastic'
Plug 'juliosueiras/vim-terraform-completion'
Enter fullscreen mode Exit fullscreen mode

Final vimrc

Now that our plugins are installed, let's add the following to create our final vimrc:

""""""""""""""""""""""""""""""
" => Terraform 
""""""""""""""""""""""""""""""
" Set filetype to HCL for files with .hcl extension
autocmd BufRead,BufNewFile *.hcl set filetype=hcl

" Set filetype to Terraform for files with .tf and .tfvars extensions
autocmd BufRead,BufNewFile *.tf,*.tfvars set filetype=terraform

" Set filetype to JSON for files with .tfstate and .tfstate.backup extensions
autocmd BufRead,BufNewFile *.tfstate,*.tfstate.backup set filetype=json

" Allow vim-terraform to automatically format *.tf and *.tfvars files with terraform fmt
let g:terraform_fmt_on_save=1

" Allow vim-terraform to align settings automatically with Tabularize
let g:terraform_align=1

" Install plugins
call plug#begin('~/.vim/plugged')
Plug 'neoclide/coc.nvim', {'branch': 'release'}
Plug 'hashivim/vim-terraform'
Plug 'vim-syntastic/syntastic'
Plug 'juliosueiras/vim-terraform-completion'
call plug#end()

" Syntastic Config
set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*

let g:syntastic_always_populate_loc_list = 1
let g:syntastic_auto_loc_list = 1
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0

" (Optional)Remove Info(Preview) window
set completeopt-=preview

" (Optional)Hide Info(Preview) window after completions
autocmd CursorMovedI * if pumvisible() == 0|pclose|endif
autocmd InsertLeave * if pumvisible() == 0|pclose|endif

" (Optional) Enable terraform plan to be include in filter
let g:syntastic_terraform_tffilter_plan = 1

" (Optional) Default: 0, enable(1)/disable(0) plugin's keymapping
let g:terraform_completion_keys = 1

" (Optional) Default: 1, enable(1)/disable(0) terraform module registry completion
let g:terraform_registry_module_completion = 0

"CoC Settings
" Use tab for trigger completion with characters ahead and navigate.
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
" other plugin before putting this into your config.
inoremap <silent><expr> <TAB>
      \ pumvisible() ? "\<C-n>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"

function! s:check_back_space() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

" Make <CR> to accept selected completion item or notify coc.nvim to format
" <C-g>u breaks current undo, please make your own choice.
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
                              \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
"Ultisnips Settings
let g:UltiSnipsExpandTrigger="<tab>"
let g:UltiSnipsJumpForwardTrigger="<c-b>"
let g:UltiSnipsJumpBackwardTrigger="<c-z>"

" If you want :UltiSnipsEdit to split your window.
let g:UltiSnipsEditSplit="vertical"

"coc-snippets Settings
"inoremap <silent><expr> <TAB>
"      \ coc#pum#visible() ? coc#_select_confirm() :
"      \ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
"      \ CheckBackspace() ? "\<TAB>" :
"      \ coc#refresh()
"
"function! CheckBackspace() abort
"  let col = col('.') - 1
"  return !col || getline('.')[col - 1]  =~# '\s'
"endfunction
"
"let g:coc_snippet_next = '<tab>'
Enter fullscreen mode Exit fullscreen mode

Test it Out

Conclusion

I hope that this guide was an informative journey to improving your DevOps development workflow. If you have any questions, enjoyed the content, or would like to check out more of my work, feel free to drop a comment below and visit my GitHub.



Top comments (0)