1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 10:40:03 +08:00
SpaceVim/bundle/vim-pydocstring/autoload/pydocstring.vim
2024-07-07 10:54:57 +08:00

242 lines
6.3 KiB
VimL
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

" 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