diff --git a/README.md b/README.md index 7449981..f865c81 100644 --- a/README.md +++ b/README.md @@ -1,111 +1,65 @@ -vim-rmarkdown +quarto-vim ============= -[RMarkdown](http://rmarkdown.rstudio.com/) support for vim. +[Quarto](https://quarto.org) support for vim. -## Setup +quarto-vim is a fork of the [vim-rmarkdown](https://github.com/vim-pandoc/vim-rmarkdown) plugin. + +quarto-vim currently only handles syntax highlighthing for qmd +files, however we'd very much like to add more of the features +available in the excellent [vim-pandoc](https://githhub.com/vim-pandoc/viv-pandoc) +plugin. If you are interested in contributing please get in +touch by filing an issue or sending a pull request! -vim-rmarkdown requires +## Setup -* the [vim-pandoc](https://github.com/vim-pandoc/vim-pandoc) and -[vim-pandoc-syntax](https://github.com/vim-pandoc/vim-pandoc-syntax) vim plugins. +quarto-vim requires the [vim-pandoc-syntax](https://github.com/vim-pandoc/vim-pandoc-syntax) vim plugin. -* the [rmarkdown standalone package](https://github.com/rstudio/rmarkdown) -vim-rmarkdown's repo uses the typical bundle layout, so it's very simple to +quarto-vim's repo uses the typical bundle layout, so it's very simple to install using some plugin manager such as [pathogen](https://github.com/tpope/vim-pathogen), [Vundle](https://github.com/VundleVim/Vundle.vim) or [NeoBundle](https://github.com/Shougo/neobundle.vim). For example, using Vundle you should add - Plugin 'vim-pandoc/vim-rmarkdown' +```viml +Plugin 'vim-pandoc/vim-pandoc-syntax' +Plugin 'quarto-dev/quarto-vim' +``` to your .vimrc, source it, and execute `:PluginInstall`. -## Screenshot +Using [packer.nvim](https://github.com/wbthomason/packer.nvim), you should add -![screenshot](http://i.imgur.com/mwr6O5t.png) +```lua +use({ + "quarto-dev/quarto-vim", + requires = { + {"vim-pandoc/vim-pandoc-syntax"}, + }, + ft = {"quarto"}, +}) +``` +to your `.vimrc` (or `init.lua` in Neovim). ## Usage -Files with the .Rmd extension are automatically detected as RMarkdown files. -vim-rmarkdown loads vim-pandoc and pandoc's markdown syntax, and adds some -extra functionality specific to rmarkdown. +Files with the .qmd extension are automatically detected as Quarto files and use highlithing rules from vim-pandoc-syntax (in addition to some special rules for Quarto executable code). ### Syntax -vim-rmarkdown extends pandoc's markdown syntax so +quarto-vim extends pandoc's markdown syntax so that: - ```{r qplot, fig.width=4, message=FALSE} - library(ggplot2) + ```{python} + import numpy as np + np.arange(15).reshape(3, 5) + ``` + + ```{r} summary(cars) - qplot(speed, dist, data=cars) + - geom_smooth() ``` +are recognized as Python and R code cells. -is recognized as an R code chunk, and +Inline R is also handled for the knitr engine: inline unformatted text like `r 1 + 2` -as inline R. - -R syntax is used within such fenced codeblocks and inline spans. - -### Command - -To render the file using rmarkdown, the user can execute the `|:RMarkdown|` -command. Its syntax is - -`:RMarkdown[!] [OUTPUT_TYPE] [- RENDER_ARGS[ -]] [OUTPUT_TYPE_ARGS]` - -OUTPUT_TYPE is one of "pdf", "word", "html", "md", "beamer", "ioslides", -"revealjs", "all", or a combination thereof (e.g., "pdf+html"). Command -completion is provided for defining this variable. - -RENDER_ARGS are arguments passed to rmarkdown::render(...), and -OUTPUT_TYPE_ARGS are passed to output objects such as rmarkdown::pdf_document(...) -and rmarkdown::word_document(...). (Refer to RMarkdown's documentation). -Note RENDER_ARGS MUST be surrounded by '- ' and ' -'. - -The bang (!) version opens the created file on successful execution. If the -execution fails, a message will be shown and a buffer will open with Rscript's -output (can be dismissed by pressing q in normal mode). - -:RMarkdown builds a R expression that executes rmarkdown. For example, if the -current file is "input.Rmd", - - :RMarkdown pdf - -executes - - Rscript -e 'library(rmarkdown);render("input.Rmd", "pdf_document")' - -If OUTPUT_TYPE is ommited, RMarkdown produces an html document. - -Some more examples: - - :RMarkdown pdf latex_engine="xelatex", toc=TRUE - -> - Rscript -e 'library(rmarkdown);render("input.Rmd", pdf_document(latex_engine="xelatex", toc=TRUE) - - :RMarkdown html - quiet=FALSE - toc=FALSE - -> - Rscript -e 'library(rmarkdown);render("input.Rmd", html_document(toc=TRUE), quiet=FALSE) - - :RMarkdown word - quiet=FALSE - -> - Rscript -e 'library(rmarkdown);render("input.Rmd", "word_document", quiet=FALSE) - -Note `|:RMarkdown|` doesn't parse the arguments itself, so the user must type them -exactly as they should be used in R (for example, commas should separate -arguments). For example, - - :RMarkdown latex_engine="lualatex" bibliography="input.bib" - -will cause rmarkdown to fail. - -## NrrwRgn - -If the NrrwRgn plugin is available, vim-rmarkdown will register an extra -command, |:RNrrw|, which "narrows" the current R chunk in a separate buffer. -This command is also mapped to "ccn" in normal mode. - -`" vim: set ft=help :` +R and Python syntax is used within such fenced codeblocks and inline spans. diff --git a/autoload/rmarkdown/command.vim b/autoload/rmarkdown/command.vim deleted file mode 100644 index f03c8c2..0000000 --- a/autoload/rmarkdown/command.vim +++ /dev/null @@ -1,161 +0,0 @@ -let s:exexec = expand(":h") . "/exexec.R" - -function! s:MapOT(ot) - let ot = tolower(a:ot) - if ot == "" || ot == "pdf" || ot == "html" || ot == "word" || ot == "md" - if ot == "" - let output_type = "html_document" - else - let output_type = ot . "_document" - endif - elseif ot == "beamer" || ot == "revealjs" || ot == "ioslides" || ot == "slidy" - let output_type = ot . "_presentation" - elseif ot == "all" - let output_type = ot - elseif ot =~ '+' - let formats = split(ot, '+') - let output_type = map(formats, 's:MapOT(v:val)') - else - throw "rmarkdown:E1" - endif - return output_type -endfunction - -function! s:MapExt(ot) - let ot = tolower(a:ot) - if ot == "" || ot == "html" || ot == "md" || ot == "pdf" - let ext = ot - elseif ot == "word" - let ext = "docx" - elseif ot == "beamer" - let ext = "pdf" - elseif ot == "revealjs" || ot == "ioslides" || ot == "slidy" - let ext = "html" - elseif ot == "all" - let ext = "html" - elseif ot =~ '+' - let ext = map(split(ot, '+'), 's:MapOT(v:val)')[0] - else - throw "rmarkdown:E1" - endif - return ext -endfunction - -function! rmarkdown#command#Command(bang, args) - let args_data = split(a:args, " ", 1) - try - let output_type = s:MapOT(args_data[0]) - if type(output_type) == type("") - let output_type_arg = '\"' . output_type . '\"' - elseif type(output_type) == type([]) - let output_types = map(output_type, '"\\\"".v:val."\\\""') - let output_type_arg = 'c(' . join(output_types, ",").')' - endif - catch /rmarkdown:E1/ - echohl errormsg - echom "vim-rmarkdown: output type not recognized" - echohl none - return - endtry - - " we support passing arguments to rmarkdown::render and output objects, - " but only for single formats (i.e., "pdf", but not "pdf+html") - if type(output_type) == type("") - let opts_data = matchlist(a:args, '\(-\s\)\@<=\(.*\)\(\s-\)\@=\(\(.*-\s\)\(.*$\)\)*') - if opts_data != [] - let render_opts = ', '. substitute(opts_data[2], '\"', '\\\"', 'g') - let object_opts = opts_data[6] - if object_opts != '' - let output_type_arg = substitute(output_type . "(".object_opts.")", '\"', '\\\"', 'g') - endif - else - let render_opts_data = matchstr(a:args, '\(-\s\)\@<=.*') - if render_opts_data != '' - let render_opts = ', ' .render_opts_data - else - let render_opts = '' - let object_opts = join(args_data[1:], ' ') - if object_opts != '' - let output_type_arg = substitute(output_type . "(" . object_opts . ")" , '\"', '\\\"', 'g') - endif - endif - endif - else - let render_opts = '' - endif - - if output_type == "revealjs_presentation" - let invocation = 'Rscript -e "library(rmarkdown);library(revealjs);render(\"'. - \ expand("%:p") . '\", '. - \ 'revealjs_presentation()' . - \ render_opts.')"' - else - let invocation = 'Rscript -e "library(rmarkdown);render(\"'. - \ expand("%:p") . '\", '. - \ output_type_arg . - \ render_opts.')"' - endif - let s:output_file = expand("%:p:r"). '.' .s:MapExt(args_data[0]) - if has('clientserver') && - \v:servername != '' && - \executable(s:exexec) - if a:bang == "!" - let open_arg = "--open" - else - let open_arg = "--noopen" - endif - silent exe "!".s:exexec." --servername ".v:servername . " ". open_arg. " " .invocation . "&" - "Replace the line above with this to debug - "exe "!".s:exexec." --servername ".v:servername . " ". open_arg. " " .invocation - else - let r_output = systemlist(invocation) - if v:shell_error - botright 10new - call append(line('$'), r_output) - norm dd - call s:RmarkdownFailure() - else - call s:RmarkdownSuccess(a:bang == "!") - endif - endif -endfunction - -function! rmarkdown#command#Callback(open) - if filereadable("rmarkdown.out") - botright 10split rmarkdown.out - silent exe "!rm rmarkdown.out" - call s:RmarkdownFailure() - else - call s:RmarkdownSuccess(a:open) - endif -endfunction - -function! s:RmarkdownSuccess(open) - echom "vim:rmarkdown: ran succesfully" - call rmarkdown#command#OpenFile(a:open) -endfunction - -function! s:RmarkdownFailure() - echohl errormsg - echom "vim-rmarkdown: rmarkdown failed" - echohl none - setlocal buftype=nofile - setlocal bufhidden=wipe - setlocal nomodifiable - noremap q :close - redraw! -endfunction - -function! rmarkdown#command#OpenFile(open) - if a:open == 1 - call system('xdg-open '. s:output_file) - endif -endfunction - -function! rmarkdown#command#CommandComplete(a, c, p) - if len(split(a:c, " ", 1)) < 3 - return join(["pdf", "html", "word", "md", "beamer", "revealjs", "ioslides", "slidy"], "\n") - else - return "" - endif -endfunction diff --git a/autoload/rmarkdown/exexec.R b/autoload/rmarkdown/exexec.R deleted file mode 100755 index de1bb82..0000000 --- a/autoload/rmarkdown/exexec.R +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env Rscript - -args <- commandArgs(trailingOnly = TRUE) -rmarkdown_invocation <- paste(c(args[4:5], paste(c("'", args[6], "'"), collapse=""), '2>&1'), collapse=" ") -output <- system(rmarkdown_invocation, intern=TRUE) -# have we failed? -if (!is.null(attr(output, "status"))) -{ - writeLines(output, 'rmarkdown.out') -} - -servername <- args[2] -if (args[3] == "--open") -{ - should_open <- '1' -} else if (args[3] == "--noopen") -{ - should_open <- '0' -} -func_call <- paste(c("'rmarkdown#command#Callback(", should_open, ")'"), collapse="") -vim_invocation <- paste(c("vim", "--servername", servername, "--remote-expr", func_call), collapse=" ") -system(vim_invocation) diff --git a/autoload/rmarkdown/nrrwrgn.vim b/autoload/rmarkdown/nrrwrgn.vim deleted file mode 100644 index b61d461..0000000 --- a/autoload/rmarkdown/nrrwrgn.vim +++ /dev/null @@ -1,64 +0,0 @@ -function! rmarkdown#nrrwrgn#NarrowRChunk() - if rmarkdown#nrrwrgn#InsideRChunk() == 1 - if exists("b:nrrw_aucmd_create") - let old_hook = b:nrrw_aucmd_create - endif - let b:nrrw_aucmd_create = 'set ft=r' - let range = rmarkdown#nrrwrgn#ChunkRange() - exe range[0].','.range[1].'NR' - if exists("old_hook") - let b:nrrw_aucmd_create = old_hook - endif - endif -endfunction - -function! rmarkdown#nrrwrgn#InsideRChunk(...) - let origin_pos = getpos(".") - if a:0 > 0 - let source_pos = a:1 - else - let source_pos = line(".") - endif - call cursor(source_pos, 1) - if synIDattr(synID(source_pos, 1, 0), "name") =~? "pandocdelimitedcodeblock" - return 1 - endif - let prev_delim = searchpair('^[~`]\{3}{r', '', '^[~`]\{3}', 'bnW') - let next_delim = search('^[~`]\{3}', 'nW') - call cursor(origin_pos[1], origin_pos[2]) - if prev_delim > 0 - if source_pos > prev_delim && source_pos < next_delim - return 1 - endif - endif -endfunction - -function! rmarkdown#nrrwrgn#ChunkRange(...) - let l:range = [] - let origin_pos = getpos(".") - if a:0 > 0 - let source_pos = a:1 - else - let source_pos = line(".") - endif - echom source_pos - call cursor(source_pos, 1) - if rmarkdown#nrrwrgn#InsideRChunk(source_pos) == 1 - let start_delim = searchpair('^[~`]\{3}{r', '', '^[~`]\{3}', 'cnbW') - let end_delim = search('^[~`]\{3}', 'cnW') - if start_delim != line(".") - let l:range = [start_delim+1, end_delim-1] - else - " we are at the starting delimiter - if rmarkdown#nrrwrgn#InsideRChunk(source_pos-1) == 0 - - let l:range = [start_delim + 1, search('^[~`]\{3}', 'nW') -1] - " we are at the ending delimiter - else - let l:range = [search('^[~`]\{3}{r', 'bnW') + 1, end_delim - 1] - endif - endif - endif - call cursor(origin_pos[1], origin_pos[2]) - return l:range -endfunction diff --git a/doc/quarto.txt b/doc/quarto.txt new file mode 100644 index 0000000..5ef390e --- /dev/null +++ b/doc/quarto.txt @@ -0,0 +1,50 @@ +*quarto-vim* + + QUARTO-VIM + +Adds support for Quarto syntax highlighting to vim. + https://quarto.org + +- SETUP *quarto-vim-setup* + +quarto-vim requires + +1) the |vim-pandoc-syntax| plugin. + See https://github.com/vim-pandoc/vim-pandoc-syntax +2) the quarto publishing system + https://quarto.org + +quarto-vim's repo uses the typical bundle layout, so it's very simple to +install using some plugin manager such as pathogen, Vundle or NeoBundle. For +example, using Vundle you should add + + Plugin 'vim-pandoc/vim-pandoc-syntax' + Plugin 'quarto-dev/quarto-vim' + +to your .vimrc, source it, and execute |:PluginInstall|. + + +- USAGE *quarto-vim-usage* + +Files with the .qmd extension are automatically detected as Quarto files, +and quarto-vim loads vim-pandoc-syntax for .qmd files. + +- SYNTAX *vim-rmarkdown-syntax* + +quarto-vim extends pandoc's markdown syntax so that: + + ```{python} + import numpy as np + np.arange(15).reshape(3, 5) + ``` + + ```{r} + summary(cars) + ``` +are recognized as Python and R code cells. + +Inline R is also handled for the knitr engine: + + inline unformatted text like `r 1 + 2` + +R and Python syntax is used within such fenced codeblocks and inline spans. diff --git a/doc/rmarkdown.txt b/doc/rmarkdown.txt deleted file mode 100644 index 8b888d9..0000000 --- a/doc/rmarkdown.txt +++ /dev/null @@ -1,115 +0,0 @@ -*vim-rmarkdown* - - VIM-RMARKDOWN - -Adds support for R Markdown to vim. - http://rmarkdown.rstudio.com/ - -- SETUP *vim-rmarkdown-setup* - -vim-rmarkdown requires - -1) the |vim-pandoc| and |vim-pandoc-syntax| plugins. - See https://github.com/vim-pandoc/ -2) the rmarkdown standalone package - https://github.com/rstudio/rmarkdown -3) the revealjs standalone package (if you want to make revealjs -presentations) - https://github.com/rstudio/revealjs - -Optionally, vim-rmarkdown can use |vim-pandoc-after| and |NrrwRgn| -(https://github.com/chrisbra/NrrwRgn) (see |:RNrrw|). - -vim-rmarkdown's repo uses the typical bundle layout, so it's very simple to -install using some plugin manager such as pathogen, Vundle or NeoBundle. For -example, using Vundle you should add - - Plugin 'vim-pandoc/vim-rmarkdown' - -to your .vimrc, source it, and execute |:PluginInstall|. - - -- USAGE *vim-rmarkdown-usage* - -Files with the .Rmd extension are automatically detected as RMarkdown files. -vim-rmarkdown loads vim-pandoc and pandoc's markdown syntax, and adds some -extra functionality specific to rmarkdown. - -- SYNTAX *vim-rmarkdown-syntax* - -vim-rmarkdown extends pandoc's markdown syntax so - - ``` {r qplot, fig.width=4, message=FALSE} - library(ggplot2) - summary(cars) - qplot(speed, dist, data=cars) + - geom_smooth() - ``` -is recognized as an R code chunk, and - - inline unformatted text like `r 1 + 2` - -as inline R. - -R syntax is used within such fenced codeblocks and inline spans. - -- COMMAND *:RMarkdown* - -To render the file using rmarkdown, the user can execute the |:RMarkdown| -command. Its syntax is - - :RMarkdown[!] [OUTPUT_TYPE] [- RENDER_ARGS[ -]] [OUTPUT_TYPE_ARGS] - -OUTPUT_TYPE is one of "pdf", "word", "html", "md", "beamer", "ioslides", -"revealjs", "slidy", "all", or a combination thereof (e.g., "pdf+html"). -Command completion is provided for defining this variable. - -RENDER_ARGS are arguments passed to rmarkdown::render(...), and -OUTPUT_TYPE_ARGS are passed to output objects such as rmarkdown::pdf_document(...) -and rmarkdown::word_document(...). (Refer to RMarkdown's documentation). -Note RENDER_ARGS MUST be surrounded by '- ' and ' -'. - -The bang (!) version opens the created file on succesful execution. If the -execution fails, a message will be shown and a buffer will open with Rscript's -output (can be dismissed by pressing q in normal mode). - -:RMarkdown builds a R expression that executes rmarkdown. For example, if the -current file is "input.Rmd", - - :RMarkdown pdf - -executes - - Rscript -e 'library(rmarkdown);render("input.Rmd", "pdf_document")' - -If OUTPUT_TYPE is ommited, RMarkdown produces an html document. - -Some more examples: - - :RMarkdown pdf latex_engine="xelatex", toc=TRUE - -> - Rscript -e 'library(rmarkdown);render("input.Rmd", pdf_document(latex_engine="xelatex", toc=TRUE) - - :RMarkdown html - quiet=FALSE - toc=FALSE - -> - Rscript -e 'library(rmarkdown);render("input.Rmd", html_document(toc=TRUE), quiet=FALSE) - - :RMarkdown word - quiet=FALSE - -> - Rscript -e 'library(rmarkdown);render("input.Rmd", "word_document", quiet=FALSE) - -Note |:RMarkdown| doesn't parse the arguments itself, so the user must type them -exactly as they should be used in R (for example, commas should separate -arguments). For example, - - :RMarkdown latex_engine="lualatex" bibliography="input.bib" - -will cause rmarkdown to fail. - - *:RNrrw* - -If the NrrwRgn plugin is available, vim-rmarkdown will register an extra -command, |:RNrrw|, which "narrows" the current R chunk in a separate buffer. -This command is also mapped to "ccn" in normal mode. - -" vim: set ft=help : diff --git a/ftdetect/quarto.vim b/ftdetect/quarto.vim new file mode 100644 index 0000000..e08bb8d --- /dev/null +++ b/ftdetect/quarto.vim @@ -0,0 +1,3 @@ +augroup quarto + au! BufRead,BufNewFile *.qmd set filetype=quarto +augroup END diff --git a/ftdetect/rmarkdown.vim b/ftdetect/rmarkdown.vim deleted file mode 100644 index 195922d..0000000 --- a/ftdetect/rmarkdown.vim +++ /dev/null @@ -1,4 +0,0 @@ -augroup rmarkdown - au! BufRead,BufNewFile *.Rmd set filetype=rmarkdown - au! BufRead,BufNewFile *.Rpres set filetype=rmarkdown -augroup END diff --git a/ftplugin/rmarkdown.vim b/ftplugin/rmarkdown.vim deleted file mode 100644 index 8f241f3..0000000 --- a/ftplugin/rmarkdown.vim +++ /dev/null @@ -1,21 +0,0 @@ -" vim: set fdm=marker: - -" Pandoc: {{{1 -" load vim-pandoc {{{2 -runtime ftplugin/pandoc.vim - -" init vim-pandoc-after, if present {{{2 -try - call pandoc#after#Init() -catch /E117/ -endtry - -" Rmarkdown: {{{1 -command! -buffer -bang -nargs=* - \-complete=custom,rmarkdown#command#CommandComplete - \RMarkdown call rmarkdown#command#Command('', '') - -if exists(":NR") == 2 - command! -buffer RNrrw call rmarkdown#nrrwrgn#NarrowRChunk() - noremap ccn :RNrrw -endif diff --git a/syntax/rmarkdown.vim b/syntax/quarto.vim similarity index 85% rename from syntax/rmarkdown.vim rename to syntax/quarto.vim index fde79c2..2ef8eb1 100644 --- a/syntax/rmarkdown.vim +++ b/syntax/quarto.vim @@ -1,6 +1,6 @@ runtime syntax/pandoc.vim PandocHighlight r -" rmarkdown recognizes embedded R differently than regular pandoc +" quarto recognizes embedded R differently than regular pandoc exe 'syn region pandocRChunk '. \'start=/\(```\s*{\s*r.*\n\)\@<=\_^/ ' . \'end=/\_$\n\(\(\s\{4,}\)\=\(`\{3,}`*\|\~\{3,}\~*\)\_$\n\_$\)\@=/ '. @@ -9,7 +9,7 @@ exe 'syn region pandocRChunk '. syn region pandocInlineR matchgroup=Operator start=/`r\s/ end=/`/ contains=@R concealends PandocHighlight python -" rmarkdown recognizes embedded R differently than regular pandoc +" quarto recognizes embedded Python differently than regular pandoc exe 'syn region pandocPythonChunk '. \'start=/\(```\s*{\s*python.*\n\)\@<=\_^/ ' . \'end=/\_$\n\(\(\s\{4,}\)\=\(`\{3,}`*\|\~\{3,}\~*\)\_$\n\_$\)\@=/ '.