Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
gabenespoli committed Nov 8, 2019
0 parents commit 730951a
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# vim-jupycent

Plugin for editing [Jupyter notebook][1] (ipynb) files via the [jupytext][2]
percent format.

[jupytext.vim][3] is an excellent plugin, but it loads the result of the
jupytext conversion into the ipynb buffer, which causes issues with other
plugins for version control (e.g., gitgutter) and linting (e.g., coc.nvim).
[jupytext.vim][3] is also a more flexible wrapper of jupytext, whereas
vim-jupycent only converts to the python percent format, and adds some
highlighting and folding based on this format.

## Installation

1. Make sure that you have the `jupytext` CLI program installed (`pip install jupytext`).
2. Install this plugin with your favourite method, like vim-plug (`Plug 'gabenespoli/vim-jupycent'`).

## Usage

When you open a Jupyter Notebook (`*.ipynb`) file, it is automatically
converted from json to markdown or python through the [`jupytext` utility][2],
and the result is loaded into the buffer. Upon saving, the `ipynb` file is
updated with any modifications.

In more detail, opening a file `notebook.ipynb` in vim will create a temporary
file `notebook.py`. This file is the result of calling e.g.

jupytext --to=py:percent --output notebook.md notebook.ipynb

The file `notebook.py` is opened, and the original `notebook.ipynb` is wiped
from vim. When saving the buffer, its contents is first written to
`notebook.py`, and then the original `notebook.ipynb` is updated with a call to

jupytext --from=py:percent --to=ipynb --update --output notebook.ipynb notebook.py

The `--update` flag ensures the output for any cell whose corresponding input
in `notebook.py` is unchanged will be preserved.

On closing the buffer, the temporary `notebook.py` will be deleted. If
`notebook.py` already existed when opening `notebook.ipynb`, the existing file
will be used (instead of being generated by `jupytext`), and it will be
preserved when closing the buffer.

## Configuration

The plugin has the following settings. If you want to override the default values shown below, you can define the corresponding variables in your `~/.vimrc`.

* `let g:jupytext_enable = 1`

You may disable the automatic conversion of `ipynb` files (i.e., deactivate this plugin) by setting this to 0.

* `let g:jupytext_command = 'jupytext'`

The CLI `jupytext` command to use. You may include the full path to point to a specific `jupytext` executable not in your default `$PATH`.

* `let g:jupytext_to_ipynb_opts = '--to=ipynb --update'`

Command line options for the conversion from `g:jupytext_fmt` back to the notebook format

## Acknowledgements

This plugin takes some inspiration, code, and documentation from [jupytext.vim][3]. vim-jupycent is basically a fork of [jupytext.vim][3], but is probably too different to call it a fork.

[1]: http://jupyter.org
[2]: https://github.com/mwouts/jupytext
[3]: https://github.com/goerz/jupytext.vim
93 changes: 93 additions & 0 deletions plugin/jupycent.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
if exists("loaded_jupycent")
finish
endif

if !exists('g:jupycent_command')
let g:jupycent_command = 'jupytext'
endif

if !exists('g:jupycent_enable')
let g:jupycent_enable = 1
endif

if !exists('g:jupycent_to_ipynb_opts')
let g:jupycent_to_ipynb_opts = '--to=ipynb --update'
endif

if !g:jupycent_enable
finish
endif

augroup jupycent_ipynb
au!
autocmd BufReadPost *.ipynb call s:read_from_ipynb()
augroup END

function! s:read_from_ipynb()
if expand("<afile>:e") != "ipynb"
echo "Not an ipynb file."
return
endif
let l:filename = expand("%:p")
let l:jupycent_file = fnamemodify(l:filename, ":r") . ".py"
let l:jupycent_file_exists = filereadable(l:jupycent_file)
if !filereadable(l:jupycent_file)
let l:output = system(g:jupycent_command . " --to=py:percent "
\ . "--output=" . shellescape(l:jupycent_file) . " "
\ . shellescape(l:filename))
endif

" open the jupytext py:percent file, wipe the ipynb file
let l:bufnr = bufnr("%")
execute "edit " . l:jupycent_file
execute "bwipeout" . l:bufnr

" set properties of the jupycent file buffer
let b:jupycent_ipynb_file = l:filename
set filetype=python
setlocal foldmethod=expr
setlocal foldexpr=JupycentFold(v:lnum)
setlocal foldtext=getline(v:foldstart+1)
syntax match JupycentCell /^#\ %%/
hi link JupycentCell FoldColumn
execute "autocmd jupycent_ipynb BufWritePost,FileWritePost <buffer> call s:write_to_ipynb()"
if !l:jupycent_file_exists
execute "autocmd jupycent_ipynb BufUnload <buffer> call s:cleanup()"
endif
endfunction

function! s:write_to_ipynb() abort
if !exists("b:jupycent_ipynb_file")
echo "Not a jupycent py file."
return
endif
let l:jupycent_file = expand("<afile>:p")
let l:output = system(g:jupycent_command . " --from=py:percent "
\ . g:jupycent_to_ipynb_opts . " "
\ . "--output " . shellescape(b:jupycent_ipynb_file) . " "
\ . shellescape(l:jupycent_file))
echo b:jupycent_ipynb_file . " updated."
endfunction

function! s:cleanup()
if !exists("b:jupycent_ipynb_file")
echo "Not a jupycent py file."
return
endif
call delete(expand("<afile>:p"))
endfunction

function! JupycentFold(lnum)
let l:line = getline(a:lnum)
if a:lnum <= 2 && l:line =~# '^#\ ---$'
return '>1'
elseif l:line =~# '^#\ %%$'
return '>1'
elseif l:line =~# '^#\ %% [markdown]$'
return '>1'
else
return '='
endif
endfunction

let loaded_jupycent = 1

0 comments on commit 730951a

Please sign in to comment.