2

F# the Vim way

 3 years ago
source link: https://www.codesuji.com/2021/04/10/F-Vim/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

F# the Vim way

Read Time: 5 minutes

When developing F#, there is a nice selection of quality development environments to choose from. One option that is often overlooked is Vim. IDEs have some really nice functionality, but often I just need a good editor with the right plug-ins. When it comes down to it, I’ll use whatever tools are necessary to get the job done. But all things being equal, the more I can live in Vim, generally the happier I am. The Vim muscle-memory built up over time has a strong pull toward a level of efficiency. So for anyone who falls into that category, this is for you.

Like most vim-addicts, I have my beloved set of plug-ins and customizations to enhance my general working environment. Although I can drone on about those, today I want to focus on a couple plug-ins that are specific to F#. The first, and most obvious is Ionide-Vim. It is a sibling of the VSCode Ionide extension for F# (which is awesome btw). Like it’s relative, this leverages FSAutoComplete for a backend to provide the typical intellisense and context aware code navigation that most developers are acustom to. Currently it leverages an LSP plug-in for integration into Vim. Not to dig into configuration too much, but I use Plug, and I added some mappings I do to better leverage Ionide and LSP functionality. The relative parts of my vim config looks like below.

Plug 'autozimu/LanguageClient-neovim', {
\ 'branch': 'next',
\ 'do': 'bash install.sh',
\ }
Plug 'ionide/Ionide-vim', {
\ 'do': 'make fsautocomplete',
\ }

...

function LC_maps()
if has_key(g:LanguageClient_serverCommands, &filetype)
nnoremap <F5> :call LanguageClient_contextMenu()<CR>
nnoremap <silent> K :call LanguageClient#textDocument_hover()<CR>
nnoremap <silent> gd :call LanguageClient#textDocument_definition()<CR>
nnoremap <silent> <F2> :call LanguageClient#textDocument_rename()<CR>
command! Symbols :call LanguageClient_textDocument_documentSymbol()
command! Fix :call LanguageClient_textDocument_codeAction()

nnoremap <leader>ld :call LanguageClient#textDocument_definition()<CR>
nnoremap <leader>lr :call LanguageClient#textDocument_rename()<CR>
nnoremap <leader>lf :call LanguageClient#textDocument_formatting()<CR>
nnoremap <leader>lt :call LanguageClient#textDocument_typeDefinition()<CR>
nnoremap <leader>lx :call LanguageClient#textDocument_references()<CR>
nnoremap <leader>la :call LanguageClient_workspace_applyEdit()<CR>
nnoremap <leader>lc :call LanguageClient#textDocument_completion()<CR>
nnoremap <leader>lh :call LanguageClient#textDocument_hover()<CR>
nnoremap <leader>ls :call LanguageClient_textDocument_documentSymbol()<CR>
nnoremap <leader>lm :call LanguageClient_contextMenu()<CR>
endif
endfunction

autocmd FileType * call LC_maps()

if has('nvim') && exists('*nvim_open_win')
augroup FSharpShowTooltip
autocmd!
autocmd CursorHold *.fs,*.fsi,*.fsx call fsharp#showTooltip()
augroup END
endif

Additionally, snipmate and snippets are great for some simple snippet expansion. If you’re not familiar with snippets, they are predefined code blocks (sometimes templated) that allow for quick expansion based on keywords. It’s a small optimization, but it reduces some tedious typing. The solution here is two parts. One, snipmate provides the funationality of snippet expansion. Two, snippets is a aggregation of user-provided language-specific snippets. You can write your own (and I do), but the repo provides a strong jumping-off point if you just want to get started.

Plug 'tomtom/tlib_vim'
Plug 'MarcWeber/vim-addon-mw-utils'
Plug 'garbas/vim-snipmate'
Plug 'honza/vim-snippets'

Sometimes I need to whip up a quick .fsx script. There is some typical boiler-plate I like to include. I could copy a file, but I found it’s a lot easier to leverage vim templates. Below is my current template, vim takes care of the rest. The way it works is if you open a new file in vim and a template exists for the filetype, vim will populate the buffer with the template file. If I open a new file, like foo.fsx, instead of being empty, it’s populated with the template file. Again, it is one of these small optimizations that helps me get into the code I care about faster. File: ~/.vim-templates/template.fsx

#!/usr/bin/env -S dotnet fsi

// Purpose:

#r "nuget: Argu"

open System
open Argu

/// CLI Argument - command
type CliCommand =
| Query

/// CLI Arguments available
type CliArguments =
| [<MainCommand; ExactlyOnce; Mandatory>] Command of command:CliCommand
| DryRun

interface IArgParserTemplate with
member this.Usage =
match this with
| Command _ -> "Command to execute [Query]"
| DryRun _ -> "Dry run only"

/// CLI Argument exit handler
type Exiter() =
interface IExiter with
member __.Name = ""
member __.Exit (msg, _) =
printfn "%s" msg
exit 1

/// CLI arguments (raw)
let argv = fsi.CommandLineArgs |> Array.skip 1
/// CLI arguments (structured)
let arguments :ParseResults<CliArguments> =
ArgumentParser
.Create<CliArguments>(programName = "", checkStructure = false, errorHandler = Exiter())
.Parse(argv)

// Perform command
match arguments.TryGetResult Command with
| Some(Query) -> printfn "querying..."
| _ -> printfn "Error: Command not supported."

Along with my other vim plug-ins and customizations, these F#-specific addtitions go a long way to making F# development in Vim a enjoyable experience. Hopefully you found something useful to make your experience better as well. Thanks, and happy vimming!
:wq


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK