Skip to content

Commit e0ba529

Browse files
committed
Merge branch 'type-hint' of git://github.com/letientai299/vim-pydocstring
2 parents b3d37f8 + c477aaa commit e0ba529

File tree

11 files changed

+318
-85
lines changed

11 files changed

+318
-85
lines changed

autoload/pydocstring.vim

Lines changed: 121 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ if !exists('g:pydocstring_ignore_args_pattern')
2424
endif
2525

2626
let s:regexs = {
27-
\ 'def': '^def\s\|^\s*def\s',
28-
\ 'class': '^class\s\|^\s*class\s',
29-
\ 'async': '^async\s*def\s\|^\s*async\sdef\s'
30-
\ }
27+
\ 'def': '^def\s\|^\s*def\s',
28+
\ 'class': '^class\s\|^\s*class\s',
29+
\ 'async': '^async\s*def\s\|^\s*async\sdef\s'
30+
\ }
3131

3232
function! s:readtmpl(type)
3333
let tmpldir = g:pydocstring_templates_dir
@@ -44,33 +44,54 @@ function! s:readtmpl(type)
4444
return tmpl
4545
endfunction
4646

47+
function! s:parseClass(line)
48+
" For class definition, we just simply need to extract the class name. We can
49+
" do that by just delete every white spaces and the whole parenthesics if
50+
" existed.
51+
let header = substitute(a:line, '\s\|(.*\|:', '', 'g')
52+
let parse = {'type': 'class', 'header': header, 'args': '', 'returnType': ''}
53+
return parse
54+
endfunction
55+
56+
function! s:parseFunc(type, line)
57+
let header = substitute(a:line, '\s\|(.*\|:', '', 'g')
58+
59+
let argsStr = substitute(a:line, '\s\|.*(\|).*', '', 'g')
60+
let args = split(argsStr, ',')
61+
62+
let arrowIndex = match(a:line, "->")
63+
if arrowIndex != -1
64+
let substring = strpart(a:line, arrowIndex+2)
65+
let returnType = substitute(substring, '\W*', '', 'g')
66+
else
67+
let returnType = ''
68+
endif
69+
70+
let parse = {'type': a:type, 'header': header, 'args': args, 'returnType': returnType}
71+
return parse
72+
endfunction
73+
4774
function! s:parse(line)
4875
let str = substitute(a:line, '\\', '', 'g')
76+
let str = substitute(a:line, '#.*$', '', 'g')
4977
let type = ''
78+
79+
if str =~ s:regexs['class']
80+
let str = substitute(str, s:regexs['class'], '', '')
81+
return s:parseClass(str)
82+
endif
83+
5084
if str =~ s:regexs['def']
5185
let str = substitute(str, s:regexs['def'], '', '')
5286
let type = 'def'
5387
elseif str =~ s:regexs['async']
5488
let str = substitute(str, s:regexs['async'], '', '')
5589
let type = 'def'
56-
elseif str =~ s:regexs['class']
57-
let str = substitute(str, s:regexs['class'], '', '')
58-
let type = 'class'
5990
else
6091
return 0
6192
endif
62-
let str = substitute(str, '\s\|):\|)\s:', '', 'g')
6393

64-
let strs = split(str, '(')
65-
let header = strs[0]
66-
let args = []
67-
if len(strs) > 1
68-
let args = split(strs[1], ',')
69-
end
70-
71-
let parse = {'type': type, 'header': header, 'args': args}
72-
73-
return parse
94+
return s:parseFunc(type, str)
7495
endfunction
7596

7697
" Vim Script does not support lambda function...
@@ -81,74 +102,101 @@ function! s:readoneline(indent, prefix)
81102
return tmpl
82103
endfunction
83104

105+
" Check if we should show args in the docstring. We won't do that in case:
106+
" - There's no args.
107+
" - There's only one arg that match with g:pydocstring_ignore_args_pattern
108+
function! s:shouldIncludeArgs(args)
109+
if len(a:args) == 0
110+
return 0
111+
endif
112+
113+
if len(a:args) == 1 && a:args[0] =~ g:pydocstring_ignore_args_pattern
114+
return 0
115+
endif
116+
117+
return 1
118+
endfunction
119+
120+
" Check if we should use one line docstring.
121+
" There's several cases:
122+
" - Type is `class`
123+
" - No return type and no args.
124+
" - No return type and the only one args is `self` or `cls` (defined by
125+
" g:pydocstring_ignore_args_pattern
126+
"
127+
" Return 1 for True, and 0 for False
128+
function! s:shouldUseOneLineDocString(type, args, returnType)
129+
if a:type != 'def'
130+
return 1
131+
endif
132+
133+
if a:returnType != ''
134+
return 0
135+
endif
136+
137+
return !s:shouldIncludeArgs(a:args)
138+
endfunction
139+
84140
function! s:builddocstring(strs, indent, nested_indent)
85141
let type = a:strs['type']
86142
let prefix = a:strs['header']
87143
let args = a:strs['args']
144+
let returnType = a:strs['returnType']
145+
146+
if s:shouldUseOneLineDocString(type, args, returnType)
147+
return s:readoneline(a:indent, prefix)
148+
endif
149+
88150
let tmpl = ''
89-
if len(args) > 0 && type == 'def'
90-
let docstrings = []
91-
let lines = s:readtmpl('multi')
92-
for line in lines
93-
if line =~ '{{_header_}}'
94-
let header = substitute(line, '{{_header_}}', prefix, '')
95-
call add(docstrings, a:indent . header)
96-
elseif line =~ '{{_arg_}}'
97-
if len(args) == 0
98-
let tmpl = s:readoneline(a:indent, prefix)
99-
return tmpl
100-
endif
101-
102-
if args[0] =~ g:pydocstring_ignore_args_pattern && len(args) == 1
103-
let tmpl = s:readoneline(a:indent, prefix)
104-
return tmpl
105-
endif
106-
107-
let arglist = []
151+
let docstrings = []
152+
let lines = s:readtmpl('multi')
153+
for line in lines
154+
if line =~ '{{_header_}}'
155+
let header = substitute(line, '{{_header_}}', prefix, '')
156+
call add(docstrings, a:indent . header)
157+
call add(docstrings, '' )
158+
elseif line =~ '{{_args_}}'
159+
if len(args) != 0
108160
for arg in args
109161
let arg = substitute(arg, '=.*$', '', '')
110162
if arg =~ g:pydocstring_ignore_args_pattern
111163
continue
112164
endif
113-
let arg = substitute(line, '{{_arg_}}', arg, 'g')
114-
let arg = substitute(arg, '{{_lf_}}', "\n", '')
115-
let arg = substitute(arg, '{{_indent_}}', a:indent, 'g')
116-
let arg = substitute(arg, '{{_nested_indent_}}', a:nested_indent, 'g')
117-
call add(docstrings, a:indent . arg)
118-
endfor
119-
elseif line =~ '{{_indent_}}'
120-
let arg = substitute(line, '{{_indent_}}', a:indent, 'g')
121-
call add(docstrings, arg)
122-
elseif line =~ '{{_args_}}'
123-
if len(args) == 0
124-
let tmpl = s:readoneline(a:indent, prefix)
125-
return tmpl
126-
endif
127-
128-
if args[0] =~ g:pydocstring_ignore_args_pattern && len(args) == 1
129-
let tmpl = s:readoneline(a:indent, prefix)
130-
return tmpl
131-
endif
132-
133-
let arglist = []
134-
for arg in args
135-
let arg = substitute(arg, '=.*$', '', '')
136-
if arg =~ g:pydocstring_ignore_args_pattern
137-
continue
165+
let template = line
166+
167+
if match(arg, ':') != -1
168+
let argTemplate = s:readtmpl('arg')
169+
let argTemplate = join(s:readtmpl('arg'), '')
170+
let argParts = split(arg, ':')
171+
let argTemplate = substitute(argTemplate, '{{_name_}}', argParts[0], '')
172+
let arg = substitute(argTemplate, '{{_type_}}', argParts[1], '')
138173
endif
139-
let arg = substitute(line, '{{_args_}}', arg, '')
140-
call add(docstrings, a:indent . arg)
174+
175+
let template = substitute(template, '{{_args_}}', arg, 'g')
176+
let template = substitute(template, '{{_lf_}}', '\n', '')
177+
let template = substitute(template, '{{_indent_}}', a:indent, 'g')
178+
let template = substitute(template, '{{_nested_indent_}}', a:nested_indent, 'g')
179+
call add(docstrings, a:indent . template)
141180
endfor
142-
elseif line == '"""'
143-
call add(docstrings, a:indent . line)
181+
call add(docstrings, '' )
182+
endif
183+
elseif line =~ '{{_indent_}}'
184+
let arg = substitute(line, '{{_indent_}}', a:indent, 'g')
185+
call add(docstrings, arg)
186+
elseif line =~ '{{_returnType_}}'
187+
if strlen(returnType) != 0
188+
let rt = substitute(line, '{{_returnType_}}', returnType, '')
189+
call add(docstrings, a:indent . rt)
144190
else
145-
call add(docstrings, line)
191+
call remove(docstrings, -1)
146192
endif
147-
endfor
148-
let tmpl = substitute(join(docstrings, "\n"), "\n$", '', '')
149-
else
150-
let tmpl = s:readoneline(a:indent, prefix)
151-
endif
193+
elseif line == '"""'
194+
call add(docstrings, a:indent . line)
195+
else
196+
call add(docstrings, line)
197+
endif
198+
endfor
199+
let tmpl = substitute(join(docstrings, "\n"), "\n$", '', '')
152200

153201
return tmpl
154202
endfunction
@@ -159,7 +207,7 @@ function! pydocstring#insert()
159207
let indent = matchstr(line, '^\(\s*\)')
160208

161209
let startpos = line('.')
162-
let insertpos = search('\:\+$')
210+
let insertpos = search('\:\(\s*#.*\)*$')
163211
let lines = join(getline(startpos, insertpos))
164212

165213
let docstring = s:parse(lines)

doc/pydocstring.txt

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,23 +124,33 @@ TEMPLATE *pydocstring-vim-template*
124124

125125
If you don't like default docstring, You can modify docstring template.
126126
>
127-
let g:template_vim_template_dir = '/path/to/your/template/directory'
127+
let g:pydocstring_templates_dir = '/path/to/your/template/directory'
128128
<
129129
- comment.txt
130130
Comment.
131131
- oneline.txt
132132
One-line docstring.
133133
- multi.txt
134134
Multi-line docstring.
135+
- arg.txt
136+
Template for each argument.
135137

136138
Template variables.
137139
|{{_header_}}| Class, function or method name as a value.
138-
|{{_args_}}| Assign function or method's arguments.
139-
|{{_arg_}}| Assign function or method's argument.
140-
|{{_ln_}}| Assign line break.
140+
|{{_args_}}| Assign function or method's arguments.
141+
|{{_lf_}}| Assign line break.
141142
|{{_indent_}}| Assign indent.
142143
|{{_nested_indent_}}| Assign indent.
143-
144+
|{{_returnType_}}| Function or method return type.
145+
|{{_name_}}| Argument name, should only be used in `arg.txt`
146+
|{{_type_}}| Argument type, should only be used in `arg.txt`
147+
148+
There's some rules for parsing template:
149+
- `{{_header_}`, `{{_args}}` and `{{_returnType_}}` should be on their own
150+
line.
151+
- Pydocstring will insert a emmpty line between each parts, so you don't
152+
need to include empty line in your template. Please see the default template
153+
directory to have an example.
144154
==============================================================================
145155
VARIABLES *pydocstring-vim-variables*
146156

template/pydocstring/arg.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{_name_}} ({{_type_}})

template/pydocstring/multi.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""{{_header_}}
2-
32
:param {{_args_}}:
3+
return ({{_returnType_}}):
44
"""

test/basic.vader

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,23 @@ Expect python:
4545
"""
4646
pass
4747

48+
Given python (def foo with 2 params and a comment block):
49+
def foo(arg1, arg2): # Something fun (just, for, test)
50+
pass
51+
52+
Execute:
53+
Pydocstring
54+
55+
Expect python:
56+
def foo(arg1, arg2): # Something fun (just, for, test)
57+
"""foo
58+
59+
:param arg1:
60+
:param arg2:
61+
"""
62+
pass
63+
64+
4865
Given python (def foo with variadic params):
4966
def foo(*arg):
5067
pass
@@ -64,6 +81,31 @@ Expect python:
6481
#-------------------------------------------------------------------------------
6582

6683

84+
Given python (class Foo no extends):
85+
class Foo:
86+
pass
87+
88+
Execute:
89+
Pydocstring
90+
91+
Expect python:
92+
class Foo:
93+
"""Foo"""
94+
pass
95+
96+
Given python (class Foo extends multiple classes):
97+
class Foo(ClassA, ClassB, ClassC):
98+
pass
99+
100+
Execute:
101+
Pydocstring
102+
103+
Expect python:
104+
class Foo(ClassA, ClassB, ClassC):
105+
"""Foo"""
106+
pass
107+
108+
67109
Given python (class Foo):
68110
class Foo(object):
69111
def foo(self):

test/custom-template.vader

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Expect python:
2929
"""foo
3030

3131
arg1:
32-
arg1 is
32+
the ...
3333
"""
3434
pass
3535

@@ -46,9 +46,9 @@ Expect python:
4646
"""foo
4747

4848
arg1:
49-
arg1 is
49+
the ...
5050
arg2:
51-
arg2 is
51+
the ...
5252
"""
5353
pass
5454

test/nodemon.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"vader.vim"
77
],
88
"verbose": true,
9-
"ext": "vader vim",
9+
"ext": "txt vader vim",
1010
"execMap": {
1111
"vader": "./run-single-test-file.sh"
1212
}

test/test-template/arg.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{_type_}} {{_name_}}

test/test-template/multi.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""{{_header_}}
2-
3-
{{_arg_}}:{{_lf_}}{{_indent_}} {{_arg_}} is
2+
{{_args_}}:{{_lf_}}{{_indent_}} the ...
3+
return ({{_returnType_}}):
44
"""

0 commit comments

Comments
 (0)