Skip to content

Instantly share code, notes, and snippets.

@lf-araujo
Last active September 11, 2023 01:54
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lf-araujo/4b9b69e6920f7efedfa28121ef013520 to your computer and use it in GitHub Desktop.
Save lf-araujo/4b9b69e6920f7efedfa28121ef013520 to your computer and use it in GitHub Desktop.
Switching from Rstudio to Neovim

Neovim R-IDE

This is my init.vim to make a stable neovim installation act as a IDE for R statistical analyses (not too much for package development).

The settings are not using neovim-lsp, so expect this is a temporary solution until someone comes up with a complete lsp configuration for R.

Why?

Because Rstudio Qt interface hangs with large data sets.

Vim? Too time consuming to set up, I won't bother.

This settings are tailored to new Neovim users (as myself) with several keybindings that simulates the usual Ctrl-C, V, etc that one finds in other editors. So this should ease transition to scientists outside of the computer sciences realm.

Ctrl-P all the things

Much inspired by Sublime Text, and not being a person who likes to memorise numerous bindings, I added Ctrl-P as a way of accessing options easily. So if you don't know how to do something in the editor, try hitting Ctrl-P, most common options were added there.

How do I install it?

Add the following (or parts of it) to your init.vim:

" Installation  {{{
call plug#begin('~/.vim/plugged')
Plug 'mbbill/desertex'
Plug 'tomasr/molokai'
  Plug 'yegappan/greplace'
  Plug 'imkmf/ctrlp-branches'
  Plug 'jistr/vim-nerdtree-tabs'
  Plug 'shaunsingh/solarized.nvim'
  Plug 'ctrlpvim/ctrlp.vim'
  Plug 'APZelos/blamer.nvim'
  Plug 'kassio/neoterm'
  Plug 'xianzhon/vim-code-runner'
  Plug 'joshdick/onedark.vim'
  Plug 'simplenote-vim/simplenote.vim'
  Plug 'pineapplegiant/spaceduck'
  Plug 'liuchengxu/vim-which-key'
  Plug 'dense-analysis/ale'
  Plug 'scrooloose/nerdtree'
  Plug 'jiangmiao/auto-pairs'
  Plug 'ryanoasis/vim-devicons'
  Plug 'metakirby5/codi.vim'
  Plug 'dbeniamine/cheat.sh-vim'
  Plug 'ncm2/ncm2'
  Plug 'roxma/nvim-yarp'
  Plug 'gaalcaras/ncm-R'
  Plug 'sirver/UltiSnips'
  Plug 'tacahiroy/ctrlp-funky'
  Plug 'ncm2/ncm2-ultisnips'
  Plug 'wsdjeg/Nvim-R'
  Plug 'ervandew/supertab'
  Plug 'itchyny/lightline.vim'
  Plug 'airblade/vim-gitgutter'
  Plug 'cideM/yui'
  Plug 'mhinz/vim-startify'
  Plug 'endel/ctrlp-filetype.vim'
  Plug 'ompugao/ctrlp-locate'
  Plug 'halkn/ripgrep.vim'
  Plug 'lokikl/vim-ctrlp-ag'
  Plug 'suy/vim-ctrlp-commandline'
  Plug 'dbeecham/ctrlp-commandpalette.vim'
  Plug 'tomtom/tcomment_vim'
  Plug 'raghur/fruzzy', {'do': { -> fruzzy#install()}}
  Plug 'tpope/vim-fugitive'
  Plug 'rhysd/vim-grammarous'
  Plug 'ntk148v/vim-horizon'
  Plug 'humanoid-colors/vim-humanoid-colorscheme'
  Plug 'hara/ctrlp-colorscheme'
  Plug 'alaviss/nim.nvim'
  Plug 'prabirshrestha/asyncomplete.vim'
  Plug 'itchyny/vim-gitbranch'
call plug#end()
" }}}

" General settings {{{
if exists('+termguicolors')
  let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
  let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
  set termguicolors
endif

colorscheme desertEx

let g:molokai_original=1
let g:blamer_enabled = 1
let g:webdevicons_enable_ctrlp = 1
let g:disco_nobright = 1
let g:disco_red_error_only = 1
set bg=dark
let g:yui_comments = "fade"
let g:mapleader = "\<Space>"
let maplocalleader = "\<Space>"
set sessionoptions-=blank " This fixes a problem with nerdtree and sessions

set modelines=1
" set spell
" set spelllang=en
set mouse=a                   " Enable mouse support in insert mode.
set clipboard+=unnamedplus    " Use clipboard
set guioptions+=a
set backspace=indent,eol,start  " To make backscape work in all conditions.
set ma                          " To set mark a at current cursor location.
" set number                      " To switch the line numbers on.
set expandtab                   " To enter spaces when tab is pressed.
set smarttab                    " To use smart tabs.
set tabstop=2                   " Two chars for a tab
set shiftwidth=2
set autoindent                  " To copy indentation from current line
set si                          " To switch on smart indentation.
set ignorecase                  " To ignore case when searching.
set smartcase                   " When searching try to be smart about cases.
set hlsearch                    " To highlight search results.
set incsearch                   " To make search act like search in modern browsers.
set magic                       " For regular expressions turn magic on.
set showmatch                   " To show matching brackets when text indicator
set mat=2                       " How many tenths of a second to blink
syntax enable                   " Enable syntax highlighting.
set encoding=utf-8 fileencodings=ucs-bom,utf-8,gbk,gb18030,latin1 termencoding=utf-8
set nobackup                     " Turn off backup.
set nowb                         " Don't backup before overwriting a file.
set noswapfile                   " Don't create a swap file.
"set ffs=unix,dos,mac             " Use Unix as the standard file type.
au! BufWritePost $MYVIMRC source %      " auto source when writing to init.vm alternatively you can run :source $MYVIMRC
" autocmd CursorHold,CursorHoldI * update " Saves when changing from insert mode

set undofile " Maintain undo history between sessions
set undodir=~/.vim/undodir


" Return to last edit position when opening files
au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif

" Reload vimrc on save
au BufWritePost ~/.config/nvim/*.{vim,lua} so $MYVIMRC
"map q :quit<CR>                 " Quit with q

" FIXME: (broken) ctrl s to save
noremap  <C-S> :update<CR>
vnoremap <C-S> <C-C>:update<CR>
inoremap <C-S> <Esc>:update<CR>

" exit insert mode
" inoremap <C-c> <Esc>

" Find
map <C-f> /

" indent / deindent after selecting the text with (⇧ v), (.) to repeat.
vnoremap <Tab> >
vnoremap <S-Tab> <

" Cut, Paste, Copy
vmap <C-x> d
vmap <C-v> p
vmap <C-c> y

" Undo, Redo (broken)
nnoremap <C-z>  :undo<CR>
inoremap <C-z>  <Esc>:undo<CR>
nnoremap <C-y>  :redo<CR>
inoremap <C-y>  <Esc>:redo<CR>


  " This mapping makes Ctrl-Tab switch between tabs.
  " Ctrl-Shift-Tab goes the other way.
  noremap <C-Tab> :tabnext<CR>
  noremap <C-S-Tab> :tabprev<CR>

  map <C-t> :tabnew<cr>

  " switch between tabs with cmd+1, cmd+2,..."
  map <C-1> 1gt
  map <C-2> 2gt
  map <C-3> 3gt
  map <C-4> 4gt
  map <C-5> 5gt
  map <C-6> 6gt
  map <C-7> 7gt
  map <C-8> 8gt
  map <C-9> 9gt

  " until we have default MacVim shortcuts this is the only way to use it in
  " insert mode
  imap <C-1> <esc>1gt
  imap <C-2> <esc>2gt
  imap <C-3> <esc>3gt
  imap <C-4> <esc>4gt
  imap <C-5> <esc>5gt
  imap <C-6> <esc>6gt
  imap <C-7> <esc>7gt
  imap <C-8> <esc>8gt
  imap <C-9> <esc>9gt

" }}}

" SuperTab {{{

let g:SuperTabDefaultCompletionType = "<c-n>"
" }}}

" Nerdtree {{{
nnoremap <C-n> :NERDTreeTabsToggle<CR>
" Start NERDTree when Vim starts with a directory argument.
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists('s:std_in') |
    \ execute 'NERDTree' argv()[0] | wincmd p | enew | execute 'cd '.argv()[0] | endif

"autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif
" Exit Vim if NERDTree is the only window left.
autocmd BufEnter * if tabpagenr('$') == 1 && winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() |
    \ quit | endif
let g:NERDTreeChDirMode       = 2
" If another buffer tries to replace NERDTree, put it in the other window, and bring back NERDTree.
autocmd BufEnter * if bufname('#') =~ 'NERD_tree_\d\+' && bufname('%') !~ 'NERD_tree_\d\+' && winnr('$') > 1 |
    \ let buf=bufnr() | buffer# | execute "normal! \<C-W>w" | execute 'buffer'.buf | endif
autocmd BufWinEnter * silent NERDTreeMirror " Open the existing NERDTree on each new tab.

" }}}

" Lightline {{{
set laststatus=2              " To tell Vim we want to see the statusline.
let g:lightline = {
      \ 'colorscheme': 'onedark',
      \ }

" }}}

" Startify {{{
function! GetUniqueSessionName()
  let path = fnamemodify(getcwd(), ':~:t')
  let path = empty(path) ? 'no-project' : path
  let branch = gitbranch#name()
  let branch = empty(branch) ? '' : '-' . branch
  return substitute(path . branch, '/', '-', 'g')
endfunction

autocmd VimLeavePre * silent execute 'SSave! ' . GetUniqueSessionName()

function! s:gitModified()
    let files = systemlist('git ls-files -m 2>/dev/null')
    return map(files, "{'line': v:val, 'path': v:val}")
endfunction

" same as above, but show untracked files, honouring .gitignore
function! s:gitUntracked()
    let files = systemlist('git ls-files -o --exclude-standard 2>/dev/null')
    return map(files, "{'line': v:val, 'path': v:val}")
endfunction

let g:startify_lists = [
        \ { 'type': 'sessions',  'header': ['   Sessions']       },
        \ { 'type': function('s:gitModified'),  'header': ['   git modified']},
        \ { 'type': function('s:gitUntracked'), 'header': ['   git untracked']},
        \ { 'type': 'dir',       'header': ['   MRU '. getcwd()] },
        \ { 'type': 'files',     'header': ['   MRU']            },
        \ { 'type': 'bookmarks', 'header': ['   Bookmarks']      },
        \ { 'type': 'commands',  'header': ['   Commands']       },
        \ ]
" }}}

" CtrlP interface {{{
let g:ctrlp_working_path_mode = 'rw'
let g:ctrlp_map = '<C-p>'
let g:ctrlp_cmd = 'CtrlPCommandPalette'
let g:ctrlp_extensions = ['mixed',  'line', 'filetype', 'commandline', 'colorscheme', 'funky', 'branches']
let g:ripgrep_options='--hidden
                      \ -g "!/cache/*"
                      \ -g "!/data/*"
                      \ -g "!/reports/*"
                      \ -g "!/.git/*"
                      \ -- '
let g:ctrlp_ag_ignores = '--ignore .git
    \ --ignore "deps/*"
    \ --ignore "_build/*"
    \ --ignore "node_modules/*"
    \ --ignore "reports/*"
    \ --ignore "data/*"
    \ --ignore "cache/*"
    \ --ignore ".git/*"'
let g:commandPalette = {
    \ 'Ignorecase: Toggle': 'set ignorecase!',
    \ 'File: save and close': 'wq',
    \ 'Start R':  'call StartR("R")',
    \ 'Start Object Browser': 'call RObjBrowser()',
    \ 'Start Inim':  'T inim',
    \ 'Search files, buffers, MRU': 'CtrlPMixed',
    \ 'Search within project': 'call feedkeys(":CtrlPagLocate ")',
    \ 'Search in this file': 'CtrlPLine',
    \ 'Commend lines': 'TComment',
    \ 'Check grammar': 'GrammarousCheck',
    \ 'Set filetype': 'CtrlPFiletype',
    \ 'Bye!': 'qa!',
    \ 'Command history': 'call ctrlp#init(ctrlp#commandline#id())',
    \ 'Find file anywhere in system': 'CtrlPLocate',
    \ 'User defined commands': 'call ctrlp#init(ctrlp#key#id())',
    \ 'Colorschemes': 'CtrlPColorscheme',
    \ 'Unfold all lines': 'call feedkeys("\<Space>zR\<CR>")',
    \ 'Fold all lines': 'call feedkeys("\<Space>zM\<CR>")',
    \ 'Unfold here': 'call feedkeys("\<Space>zo\<CR>")',
    \ 'Navigate sections of this file': 'CtrlPFunkyMulti',
    \ 'Run!': 'call feedkeys("\<Space>B\<CR>")',
    \ 'Branches': 'CtrlPBranches'}

" function BrightHighlightOn()
"   hi CursorLine guibg=darkred
" endfunction
"
" function BrightHighlightOff()
"   hi CursorLine guibg=#191919
" endfunction
" let g:ctrlp_buffer_func = { 'enter': 'BrightHighlightOn', 'exit':  'BrightHighlightOff', }
let g:fruzzy#usenative = 1 " optional - but recommended - see below
let g:ctrlp_match_func = {'match': 'fruzzy#ctrlp#matcher'} " tell CtrlP to use this matcher
let g:ctrlp_match_current_file = 1 " to include current file in matches

set wildignore+=*/.git/*,*/.hg/*,*/.svn/*
" }}}

" tComment {{{
" vmap <C-/> gc " comment / decomment & normal comment behavior
let g:tcomment#replacements_xml={} " Disable tComment to escape some entities
" }}}

" R configuration - Nvim-R {{{
let g:rout_follow_colorscheme = 1 " R output is highlighted with current colorscheme
let g:Rout_more_colors = 1 " R commands in R output are highlighted
let g:R_pdfviewer="evince"
let R_show_args = 1 " show the arguments for functions with autocompletion
let g:R_objbr_opendf = 0
let g:R_objbr_openlist = 0

autocmd VimLeave * if exists("g:SendCmdToR") && string(g:SendCmdToR) != "function('SendCmdToR_fake')" | call RQuit("nosave") | endif " exit R when you exit the vim
autocmd FileType rmd set foldmarker=```{,```
autocmd FileType rmd setlocal foldmethod=marker


vmap <Space><Space> <Plug>RDSendSelection
nmap <Space><Space> <Plug>RDSendLine

" }}}

" R configuration - NCM2 {{{
autocmd BufEnter * call ncm2#enable_for_buffer()    " To enable ncm2 for all buffers.
set completeopt=noselect,noinsert,menuone,preview
" }}}

" Snips - Ultisnips - ncm2 {{{
" First use tab and shift tab to browse the popup menu and use enter to expand:
inoremap ncm2_ultisnips#expand_or("<CR>”, 'n')
inoremap pumvisible() ? "<C-n>" : "<Tab>"
inoremap pumvisible() ? "<C-p>" : "<S-Tab>"
let g:UltiSnipsExpandTrigger="<c-0>"
au BufNewFile,BufRead *.Rmd set filetype=rmd

" c-j c-k for moving in snippet
let g:UltiSnipsExpandTrigger		= "<Plug>(ultisnips_expand)"
let g:UltiSnipsJumpForwardTrigger	= "<c-j>"
let g:UltiSnipsJumpBackwardTrigger	= "<c-k>"
let g:UltiSnipsRemoveSelectModeMappings = 0
" }}}

" ALE {{{
let g:ale_linters = {
\   'nim': ['nimlsp', 'nimcheck'],
\   'rmd': ['lintr'],
\   'sh': ['shellcheck']
\}

let g:ale_fixers = {
\   '*': ['remove_trailing_lines', 'trim_whitespace'],
\   'rmd': ['styler'],
\   'nim': ['nimpretty'],
\}

let g:ale_fix_on_save = 1
let g:ale_linters_explicit = 1
let g:ale_set_loclist = 0
let g:ale_set_quickfix = 1
let g:ale_lint_on_text_changed = 'never'
let g:ale_lint_on_insert_leave = 0
let g:ale_fix_on_save = 1
let g:ale_sign_error = '✖✖'
let g:ale_sign_warning = '⚠⚠'
highlight ALEErrorSign guifg=Red
highlight ALEWarningSign guifg=Yellow

" Workaround to get auto omni completion FIXME very buggy
" from so/q/35837990/
" function! OpenCompletion()
"     if ((v:char >= 'a' && v:char <= 'z') || (v:char >= 'A' && v:char <= 'Z'))
"         call feedkeys("\<C-x>\<C-o>", 'n')
"     endif
" endfunction
"
" autocmd FileType rmd autocmd InsertCharPre * call OpenCompletion()
" autocmd FileType r autocmd InsertCharPre * call OpenCompletion()

" }}}

" Nim configuration - asyncomplete {{{
au User asyncomplete_setup call asyncomplete#register_source({
    \ 'name': 'nim',
    \ 'whitelist': ['nim'],
    \ 'completor': {opt, ctx -> nim#suggest#sug#GetAllCandidates({start, candidates -> asyncomplete#complete(opt['name'], ctx, start, candidates)})}
    \ })
" }}}

" Nim configuration - CodeRunner and TREPL {{{

let g:CodeRunnerCommandMap = {
      \ 'nim' : 'nim c -r $fileName'
      \}


let g:code_runner_save_before_execute = 1

let g:neoterm_callbacks = {}
function! g:neoterm_callbacks.before_new()
  if winwidth('.') > 100
    let g:neoterm_default_mod = 'botright vertical'
  else
    let g:neoterm_default_mod = 'botright'
  end
endfunction



nmap <silent><leader>B <plug>CodeRunner
autocmd FileType nim nmap <leader>d :TREPLSendLine<CR>

" }}}


" vim:foldmethod=marker:foldlevel=0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment