├── .editorconfig
├── README.md
├── autoload
└── devtools.vim
├── ftplugin
├── r.vim
├── rmd.vim
└── rnoweb.vim
└── plugin
└── devtools.vim
/.editorconfig:
--------------------------------------------------------------------------------
1 | # See http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf8
6 | end_of_line = lf
7 | insert_final_newline = true
8 | indent_style = space
9 | trim_trailing_whitespace = true
10 |
11 | [*.{vim}]
12 | indent_size = 4
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vim-devtools-plugin
2 |
3 | Extension for the vim plugins [Vim-R-Plugin](https://github.com/jcfaria/Vim-R-plugin) and [Nvim-r](https://github.com/jalvesaq/Nvim-R) to support the [devtools R package](https://github.com/hadley/devtools).
4 |
5 | ## Installation
6 | Use your favourite bundle manager to install this script, e.g.:
7 | ```vim
8 | " Vundle
9 | Plugin 'mllg/vim-devtools-plugin'
10 |
11 | " Neobundle with lazy load
12 | NeoBundleLazy 'mllg/vim-devtools-plugin',
13 | \ {'autoload' : {'filetypes' : ['r','rmd','rnoweb']}}
14 |
15 | " dein with lazy load
16 | call dein#add('mllg/vim-devtools-plugin', {'on_ft' : ['r', 'rmd', 'rdoc', 'rnoweb']})
17 |
18 | " Vim-Plug with lazy load
19 | Plug 'mllg/vim-devtools-plugin', { 'for': ['r', 'rmd', 'rnoweb']}
20 |
21 | " packer
22 | use { 'mllg/vim-devtools-plugin', ft = {'r', 'rmd', 'rnoweb'}}
23 | ```
24 |
25 | ## Available commands
26 |
27 | * `RInstallPackage
`: Runs `devtools::install`.
28 | * `RLoadPackage `: Runs `devtools::load_all`.
29 | * `RUnloadPackage `: Runs `devtools::unload`.
30 | * `RBuildPackage `: Runs `devtools::build`.
31 | * `RCheckPackage `: Runs `devtools::check`.
32 | * `RClean `: Runs `devtools::clean_dll`
33 | * `RTestPackage `: Runs `devtools::test` using specified filter (default `''`).
34 | * `RDocumentPackage `: Runs `devtools::document`
35 | * `RMake `: Runs `devtools::document`, then `devtools::install`.
36 | * `RSetupTest `: Loads "testthat" and invisibly sources all files matching pattern `^helper` in the test directory.
37 | * `RSourceFile `: Sources the given file. If argument is omitted, either the master file (if set, see below) or the current buffer gets sourced.
38 | * `RBuildPackgeTags `: Builds a tag file for the package and stores it in `g:devtools_rtags_dir` (default is "~/.rtags"). All tag files in this directory will automatically added to &tags for file types `r`, `rnoweb` and `rmd`.
39 | * `RUsage `: Loads the package and calls `codetools::checkUsagePackage()`. Reported problems are send to the quickfix window.
40 | * `RSetMaster `: Declare as the master file. Used in `:RSourceFile`. If is omitted, the current buffer is declared as master.
41 | Note that this choice is not persistent between vim sessions.
42 |
43 | The DESCRIPTION file is searched in `` and all its parents.
44 | Default for `` is the directory of the current buffer.
45 |
46 | The command `RTestFile` has been removed to simplify command completion with the much more frequently used `RTestFile`.
47 | If you liked it, you can restore it by defining the command in your `.vimrc`:
48 | ```vim
49 | command! -nargs=0 RTestFile :call devtools#test_file()
50 | ```
51 |
52 | If you do not want any of these commands to be defined, set the option `devtools_commands`:
53 | ```vim
54 | let g:devtools_commands = 0
55 | ```
56 |
57 |
58 | ## Support for FZF
59 |
60 | If you are a user of [FZF](https://github.com/junegunn/fzf.vim), you can grep your R history file with the following setup:
61 |
62 | ### Make R history persistent across sessions
63 |
64 | Put the following code in your `.Rprofile`, preferably inside the `.First` function:
65 |
66 | ```r
67 | if (interactive()) {
68 | history_file = normalizePath("~/.Rhistory", mustWork = FALSE)
69 | ok = try(utils::loadhistory(history_file))
70 | if (inherits(ok, "try-error")) {
71 | message("History could not be loaded: ", history_file)
72 | } else {
73 | message("Loaded history: ", history_file)
74 | .Last <<- function() try(utils::savehistory(history_file))
75 | }
76 | }
77 | ```
78 |
79 | ### Create new command
80 | ```vim
81 | function! s:fzf_r_history()
82 | let l:history_file = expand('~/.Rhistory')
83 | call g:devtools#send_cmd('utils::savehistory("' . l:history_file . '")')
84 | call fzf#run({
85 | \ 'source': 'cat ' . l:history_file . ' | grep -v "# \\[history skip\\]$" | uniq',
86 | \ 'sink' : g:SendCmdToR,
87 | \ 'options': '--no-sort --tac',
88 | \ 'down' : '40%' })
89 | endfunction
90 |
91 | command! RHistory call s:fzf_r_history()
92 | ```
93 | Map to a key as you find appropiate.
94 |
--------------------------------------------------------------------------------
/autoload/devtools.vim:
--------------------------------------------------------------------------------
1 | function! devtools#escape(path)
2 | return substitute(a:path, '\', '/', 'g')
3 | endfunction
4 |
5 | function! devtools#send_cmd(line)
6 | call g:SendCmdToR(a:line . ' # [history skip]')
7 | endfunction
8 |
9 | function! devtools#find_description(path)
10 | if len(a:path) == 0
11 | let l:desc = findfile('DESCRIPTION', '.;')
12 | else
13 | let l:desc = findfile('DESCRIPTION', expand(a:path[0]) . ';')
14 | endif
15 |
16 | if l:desc == ''
17 | call RWarningMsg('DESCRIPTION file not found.')
18 | return ""
19 | endif
20 |
21 | let l:path = fnamemodify(l:desc, ':p:h')
22 | echo 'Using package DESCRIPTION in "' . l:path . '".'
23 | return devtools#escape(l:path)
24 | endfunction
25 |
26 |
27 | function devtools#simple_cmd(cmd, ...)
28 | let l:desc = devtools#find_description(a:000)
29 | if (l:desc != '')
30 | call devtools#send_cmd('devtools::' . a:cmd . '("' . l:desc . '")')
31 | endif
32 | endfunction
33 |
34 |
35 | function! devtools#test(...)
36 | if a:0 == 2
37 | let l:filter = a:2
38 | let l:desc = devtools#find_description([a:1])
39 | else
40 | if a:0 == 1
41 | let l:filter = '"' . substitute(a:1, '"', '', 'g') . '"'
42 | else
43 | let l:filter = 'NULL'
44 | endif
45 | let l:desc = devtools#find_description([])
46 | endif
47 | if (l:desc != '')
48 | if filereadable(l:desc . '/tests/tinytest.R')
49 | let l:line = 'tinytest::run_test_dir(file.path("' . l:desc . '", "inst", "tinytest"))'
50 | else
51 | let l:line = ' testthat::test_local("' . l:desc . '", filter = ' . l:filter . ')'
52 | endif
53 | call devtools#send_cmd(l:line)
54 | endif
55 | endfunction
56 |
57 |
58 | function! devtools#test_file()
59 | let l:filter = '"' . substitute(expand('%:t:r'), '^test[-_]', '', '') . '"'
60 | call devtools#test(l:filter)
61 | endfunction
62 |
63 |
64 | function! devtools#make(...)
65 | let l:desc = devtools#find_description(a:000)
66 | if (l:desc != '')
67 | let l:line = 'devtools::document("' . l:desc . '")'
68 | let l:line .= '; devtools::install("' . l:desc . '")'
69 | call devtools#send_cmd(l:line)
70 | endif
71 | call devtools#build_tags(l:desc)
72 | call devtools#use_r_tags()
73 | endfunction
74 |
75 |
76 | function! devtools#setup_test(...)
77 | let l:desc = devtools#find_description(a:000)
78 | if (l:desc != '')
79 | let l:line = 'library("testthat"); devtools::load_all("' . l:desc . '")'
80 | let l:line .= '; invisible(lapply(list.files(file.path("' . l:desc . '", "tests", "testthat"),'
81 | let l:line .= ' pattern="^helper", full.names=TRUE), source, chdir=TRUE, verbose=FALSE))'
82 | call devtools#send_cmd(l:line)
83 | endif
84 | endfunction
85 |
86 |
87 | function! devtools#build_tags(...)
88 | let l:rtags = fnamemodify(g:devtools_rtags_dir, ':p')
89 | if !isdirectory(l:rtags)
90 | call mkdir(l:rtags)
91 | endif
92 | let l:desc = devtools#find_description(a:000)
93 | if (l:desc != '')
94 | let l:line = 'local({ '
95 | let l:line .= printf('etagsfile = tempfile(); utils::rtags(path=file.path("%s", "R"), ofile= etagsfile)', l:desc)
96 | let l:line .= printf('; etags2ctags(etagsfile, file.path("%s", sprintf("%%s.ctags", devtools::as.package("%s")$package)))', devtools#escape(l:rtags), l:desc)
97 | let l:line .= ' })'
98 | call devtools#send_cmd(l:line)
99 | call devtools#use_r_tags()
100 | endif
101 | endfunction
102 |
103 | function! devtools#source_file(...)
104 | if a:0 == 0
105 | if exists("s:devtools_master_file")
106 | let l:file = s:devtools_master_file
107 | else
108 | let l:file = devtools#escape(expand('%:p'))
109 | endif
110 | else
111 | let l:file = a:1
112 | endif
113 | call devtools#send_cmd(printf('source("%s")', l:file))
114 | endfunction
115 |
116 |
117 | function! devtools#usage(...)
118 | let l:desc = devtools#find_description(a:000)
119 | if (l:desc != '')
120 | let l:tmp = tempname()
121 | let l:line = 'devtools::load_all("' . l:desc . '")'
122 | let l:line .= '; local({ tmp = capture.output(codetools::checkUsagePackage(devtools::as.package("' . l:desc . '")$package)); writeLines(tmp, "' . devtools#escape(l:tmp) . '")})'
123 | call devtools#send_cmd(l:line)
124 | setlocal efm+=%m\ (%f:%l%.%#)
125 |
126 | while !filereadable(l:tmp)
127 | sleep 100m
128 | endwhile
129 | sleep 50m
130 | execute ":cfile " . l:tmp
131 | call delete(l:tmp)
132 | endif
133 | endfunction
134 |
135 | function! devtools#set_master(...)
136 | if a:0 == 0
137 | let s:devtools_master_file = devtools#escape(expand('%:p'))
138 | else
139 | let s:devtools_master_file = a:1
140 | endif
141 | endfunction
142 |
143 | function! devtools#use_r_tags()
144 | let l:rtags = fnamemodify(g:devtools_rtags_dir, ':p')
145 | if isdirectory(l:rtags)
146 | let l:tags = extend(split(&tags, ','), split(glob(l:rtags . '*.ctags'), '\n'))
147 | let &tags = join(filter(l:tags, 'count(l:tags, v:val) == 1'), ',')
148 | endif
149 | endfunction
150 |
--------------------------------------------------------------------------------
/ftplugin/r.vim:
--------------------------------------------------------------------------------
1 | call devtools#use_r_tags()
2 |
--------------------------------------------------------------------------------
/ftplugin/rmd.vim:
--------------------------------------------------------------------------------
1 | call devtools#use_r_tags()
2 |
--------------------------------------------------------------------------------
/ftplugin/rnoweb.vim:
--------------------------------------------------------------------------------
1 | call devtools#use_r_tags()
2 |
--------------------------------------------------------------------------------
/plugin/devtools.vim:
--------------------------------------------------------------------------------
1 | if exists("g:loaded_vim_devtools_plugin") || &cpo
2 | finish
3 | endif
4 |
5 | let g:loaded_vim_devtools_plugin=1
6 | let s:keepcpo=&cpo
7 | set cpo&vim
8 |
9 | if !exists('g:devtools_commands') || g:devtools_commands
10 | command! -complete=dir -nargs=? RInstallPackage :call devtools#simple_cmd('install', )
11 | command! -complete=dir -nargs=? RLoadPackage :call devtools#simple_cmd('load_all', )
12 | command! -complete=dir -nargs=? RUnloadPackage :call devtools#simple_cmd('unload', )
13 | command! -complete=dir -nargs=? RBuildPackage :call devtools#simple_cmd('build', )
14 | command! -complete=dir -nargs=? RCheckPackage :call devtools#simple_cmd('check', )
15 | command! -complete=dir -nargs=? RDocumentPackage :call devtools#simple_cmd('document', )
16 | command! -complete=dir -nargs=? RClean :call devtools#simple_cmd('clean_dll', )
17 | command! -complete=dir -nargs=* RTestPackage :call devtools#test()
18 | command! -complete=dir -nargs=? RMake :call devtools#make()
19 | command! -complete=dir -nargs=? RSetupTest :call devtools#setup_test()
20 | command! -complete=dir -nargs=? RBuildPackageTags :call devtools#build_tags()
21 | command! -complete=file -nargs=? RSourceFile :call devtools#source_file()
22 | command! -complete=file -nargs=? RSetMaster :call devtools#set_master()
23 | command! -complete=file -nargs=? RUsage :call devtools#usage()
24 | endif
25 |
26 | let g:devtools_rtags_dir = get(g:, 'devtools_rtags_dir', expand('~/.rtags'))
27 |
28 | let &cpo=s:keepcpo
29 | unlet s:keepcpo
30 |
--------------------------------------------------------------------------------