mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-24 06:30:03 +08:00
242 lines
6.3 KiB
VimL
242 lines
6.3 KiB
VimL
|
" Insert Docstring.
|
|||
|
" Author: Shinya Ohyanagi <sohyanagi@gmail.com>
|
|||
|
" WebPage: http://github.com/heavenshell/vim-pydocstriong/
|
|||
|
" Description: Generate Python docstring to your Python script file.
|
|||
|
" License: BSD, see LICENSE for more details.
|
|||
|
" NOTE: This module is heavily inspired by php-doc.vim and
|
|||
|
" sonictemplate.vim
|
|||
|
let s:save_cpo = &cpo
|
|||
|
set cpo&vim
|
|||
|
|
|||
|
let g:pydocstring_templates_path = get(g:, 'pydocstring_templates_path', '')
|
|||
|
let g:pydocstring_formatter = get(g:, 'pydocstring_formatter', 'sphinx')
|
|||
|
let g:pydocstring_doq_path = get(
|
|||
|
\ g:,
|
|||
|
\ 'pydocstring_doq_path',
|
|||
|
\ printf('%s/lib/doq', expand('<sfile>:p:h:h'))
|
|||
|
\ )
|
|||
|
let g:pydocstring_ignore_init = get(g:, 'pydocstring_ignore_init', 0)
|
|||
|
|
|||
|
let s:results = []
|
|||
|
|
|||
|
function! s:get_indent_width() abort
|
|||
|
" Get indentation width
|
|||
|
return &smarttab ? &shiftwidth : &softtabstop
|
|||
|
endfunction
|
|||
|
|
|||
|
function! s:get_range() abort
|
|||
|
" Get visual mode selection.
|
|||
|
let mode = visualmode(1)
|
|||
|
if mode == 'v' || mode == 'V' || mode == ''
|
|||
|
let start_lineno = line("'<")
|
|||
|
let end_lineno = line("'>")
|
|||
|
return {'start_lineno': start_lineno, 'end_lineno': end_lineno}
|
|||
|
endif
|
|||
|
let current = line('.')
|
|||
|
return {'start_lineno': 0, 'end_lineno': '$'}
|
|||
|
endfunction
|
|||
|
|
|||
|
function! s:insert_docstring(docstrings, end_lineno) abort
|
|||
|
let paste = &g:paste
|
|||
|
let &g:paste = 1
|
|||
|
|
|||
|
silent! execute 'normal! ' . a:end_lineno . 'G$'
|
|||
|
let current_lineno = line('.')
|
|||
|
" If current position is bottom, add docstring below.
|
|||
|
if a:end_lineno == current_lineno
|
|||
|
silent! execute 'normal! O' . a:docstrings['docstring']
|
|||
|
else
|
|||
|
silent! execute 'normal! o' . a:docstrings['docstring']
|
|||
|
endif
|
|||
|
|
|||
|
let &g:paste = paste
|
|||
|
silent! execute 'normal! ' . a:end_lineno . 'G$'
|
|||
|
endfunction
|
|||
|
|
|||
|
function! s:callback(msg, indent, start_lineno) abort
|
|||
|
let msg = join(a:msg, '')
|
|||
|
" Check needed for Neovim
|
|||
|
if len(msg) == 0
|
|||
|
return
|
|||
|
endif
|
|||
|
|
|||
|
let docstrings = reverse(json_decode(msg))
|
|||
|
silent! execute 'normal! 0'
|
|||
|
let length = len(docstrings)
|
|||
|
for docstring in docstrings
|
|||
|
let lineno = 0
|
|||
|
if length > 1
|
|||
|
call cursor(a:start_lineno + docstring['start_lineno'] - 1, 1)
|
|||
|
let lineno = search('\:\(\s*#.*\)*$', 'n') + 1
|
|||
|
else
|
|||
|
let lineno = search('\:\(\s*#.*\)*$', 'n') + 1
|
|||
|
endif
|
|||
|
|
|||
|
call s:insert_docstring(docstring, lineno)
|
|||
|
endfor
|
|||
|
endfunction
|
|||
|
|
|||
|
function! s:format_callback(msg, indent, start_lineno) abort
|
|||
|
call extend(s:results, a:msg)
|
|||
|
endfunction
|
|||
|
|
|||
|
function! s:exit_callback(msg) abort
|
|||
|
unlet s:job " Needed for Neovim
|
|||
|
let length = len(s:results)
|
|||
|
if length
|
|||
|
if length == 1 && s:results[0] == ''
|
|||
|
let s:results = []
|
|||
|
return
|
|||
|
endif
|
|||
|
let view = winsaveview()
|
|||
|
silent execute '% delete'
|
|||
|
|
|||
|
" Hack for Neovima PydocstringFormat
|
|||
|
" Neovim add blank line to the end of list
|
|||
|
if has('nvim') && s:results[-1] == ''
|
|||
|
call remove(s:results, -1)
|
|||
|
endif
|
|||
|
call setline(1, s:results)
|
|||
|
call winrestview(view)
|
|||
|
let s:results = []
|
|||
|
endif
|
|||
|
endfunction
|
|||
|
|
|||
|
function! s:execute(cmd, lines, indent, start_lineno, cb, ex_cb) abort
|
|||
|
if !executable(expand(g:pydocstring_doq_path))
|
|||
|
redraw
|
|||
|
echohl Error
|
|||
|
echo '`doq` not found. Install `doq`.'
|
|||
|
echohl None
|
|||
|
return
|
|||
|
endif
|
|||
|
|
|||
|
let s:results = []
|
|||
|
if has('nvim')
|
|||
|
if exists('s:job')
|
|||
|
call jobstop(s:job)
|
|||
|
endif
|
|||
|
|
|||
|
let s:job = jobstart(a:cmd, {
|
|||
|
\ 'on_stdout': {_c, m, _e -> a:cb(m, a:indent, a:start_lineno)},
|
|||
|
\ 'on_exit': {_c, m, _e -> a:ex_cb(m)},
|
|||
|
\ 'stdout_buffered': v:true,
|
|||
|
\ })
|
|||
|
|
|||
|
if exists('*chansend')
|
|||
|
" Neovim >0.3.0
|
|||
|
call chansend(s:job, a:lines)
|
|||
|
call chanclose(s:job, 'stdin')
|
|||
|
else
|
|||
|
" Legacy API
|
|||
|
call jobsend(s:job, a:lines)
|
|||
|
call jobclose(s:job, 'stdin')
|
|||
|
endif
|
|||
|
|
|||
|
else
|
|||
|
if exists('s:job') && job_status(s:job) != 'stop'
|
|||
|
call job_stop(s:job)
|
|||
|
endif
|
|||
|
|
|||
|
let s:job = job_start(a:cmd, {
|
|||
|
\ 'callback': {_, m -> a:cb([m], a:indent, a:start_lineno)},
|
|||
|
\ 'exit_cb': {_, m -> a:ex_cb([m])},
|
|||
|
\ 'in_mode': 'nl',
|
|||
|
\ })
|
|||
|
|
|||
|
let channel = job_getchannel(s:job)
|
|||
|
if ch_status(channel) ==# 'open'
|
|||
|
call ch_sendraw(channel, a:lines)
|
|||
|
call ch_close_in(channel)
|
|||
|
endif
|
|||
|
endif
|
|||
|
endfunction
|
|||
|
|
|||
|
function! s:create_cmd(style, omissions) abort
|
|||
|
if a:omissions ==# ''
|
|||
|
let cmd = printf(
|
|||
|
\ '%s --style=%s --formatter=%s --indent=%s',
|
|||
|
\ expand(g:pydocstring_doq_path),
|
|||
|
\ a:style,
|
|||
|
\ g:pydocstring_formatter,
|
|||
|
\ s:get_indent_width()
|
|||
|
\ )
|
|||
|
else
|
|||
|
let cmd = printf(
|
|||
|
\ '%s --style=%s --formatter=%s --omit=%s --indent=%s',
|
|||
|
\ expand(g:pydocstring_doq_path),
|
|||
|
\ a:style,
|
|||
|
\ g:pydocstring_formatter,
|
|||
|
\ a:omissions,
|
|||
|
\ s:get_indent_width()
|
|||
|
\ )
|
|||
|
endif
|
|||
|
if g:pydocstring_templates_path !=# ''
|
|||
|
let cmd = printf('%s --template_path=%s', cmd, expand(g:pydocstring_templates_path))
|
|||
|
endif
|
|||
|
|
|||
|
return cmd
|
|||
|
endfunction
|
|||
|
|
|||
|
function! pydocstring#format() abort
|
|||
|
let lines = printf("%s\n", join(getbufline(bufnr('%'), 1, '$'), "\n"))
|
|||
|
let cmd = s:create_cmd('string', '')
|
|||
|
let cmd = g:pydocstring_ignore_init ? printf('%s --ignore_init', cmd) : cmd
|
|||
|
|
|||
|
let indent = s:get_indent_width()
|
|||
|
let end_lineno = line('.')
|
|||
|
call s:execute(
|
|||
|
\ cmd,
|
|||
|
\ lines,
|
|||
|
\ indent,
|
|||
|
\ end_lineno,
|
|||
|
\ function('s:format_callback'),
|
|||
|
\ function('s:exit_callback')
|
|||
|
\ )
|
|||
|
endfunction
|
|||
|
|
|||
|
function! pydocstring#insert(...) abort
|
|||
|
let range = s:get_range()
|
|||
|
let pos = getpos('.')
|
|||
|
|
|||
|
let line = getline('.')
|
|||
|
let indent = matchstr(line, '^\(\s*\)')
|
|||
|
|
|||
|
let space = repeat(' ', s:get_indent_width())
|
|||
|
let indent = indent . space
|
|||
|
if len(indent) == 0
|
|||
|
let indent = space
|
|||
|
endif
|
|||
|
|
|||
|
silent! execute 'normal! 0'
|
|||
|
|
|||
|
let is_not_range = range['start_lineno'] == 0 && range['end_lineno'] == '$'
|
|||
|
if is_not_range
|
|||
|
let start_lineno = line('.')
|
|||
|
let end_lineno = search('\:\(\s*#.*\)*$')
|
|||
|
else
|
|||
|
let start_lineno = range['start_lineno']
|
|||
|
let end_lineno = range['end_lineno']
|
|||
|
endif
|
|||
|
call setpos('.', pos)
|
|||
|
|
|||
|
let cmd = s:create_cmd('json', 'self,cls')
|
|||
|
let lines = join(getline(start_lineno, end_lineno), "\n")
|
|||
|
if is_not_range
|
|||
|
let lines = printf("%s\n%s%s", lines, indent, 'pass')
|
|||
|
let cmd = printf('%s --ignore_exception', cmd)
|
|||
|
endif
|
|||
|
|
|||
|
call s:execute(
|
|||
|
\ cmd,
|
|||
|
\ lines,
|
|||
|
\ indent,
|
|||
|
\ start_lineno,
|
|||
|
\ function('s:callback'),
|
|||
|
\ function('s:exit_callback')
|
|||
|
\ )
|
|||
|
endfunction
|
|||
|
|
|||
|
let &cpo = s:save_cpo
|
|||
|
unlet s:save_cpo
|