1
1
" Insert Docstring.
2
2
" Author: Shinya Ohyanagi <[email protected] >
3
- " Version: 0.2 .0
3
+ " Version: 0.3 .0
4
4
" WebPage: http://github.com/heavenshell/vim-pydocstriong/
5
5
" Description: Generate Python docstring to your Python script file.
6
6
" License: BSD, see LICENSE for more details.
25
25
let s: regexs = {
26
26
\ ' def' : ' ^def\s\|^\s*def\s' ,
27
27
\ ' class' : ' ^class\s\|^\s*class\s' ,
28
- \ ' async' : ' ^async\s*def\s\|^\s*async\sdef\s'
28
+ \ ' async' : ' ^async\s*def\s\|^\s*async\sdef\s' ,
29
+ \ ' typed_args' : ' \([0-9A-Za-z_.]\+:[0-9A-Za-z_.]\+\|[0-9A-Za-z_.]\+\)\(,\|$\)' ,
29
30
\ }
30
31
31
32
function ! s: readtmpl (type )
@@ -43,7 +44,7 @@ function! s:readtmpl(type)
43
44
return tmpl
44
45
endfunction
45
46
46
- function ! s: parseClass (line )
47
+ function ! s: parse_class (line )
47
48
" For class definition, we just simply need to extract the class name. We can
48
49
" do that by just delete every white spaces and the whole parenthesics if
49
50
" existed.
@@ -52,22 +53,129 @@ function! s:parseClass(line)
52
53
return parse
53
54
endfunction
54
55
56
+ function ! s: compare (lhs, rhs)
57
+ return a: lhs [' start' ] - a: rhs [' start' ]
58
+ endfunction
59
+
60
+ function ! s: parse_args (args_str)
61
+ let primitive_pos = 0
62
+ let nested = 0
63
+ let start_pos = 0
64
+ let end_pos = 0
65
+ let args = []
66
+ let primitives = []
67
+
68
+ " Extract none typed arguments or primitive arguments first.
69
+ while 1
70
+ let primitives = matchstrpos (a: args_str , s: regexs [' typed_args' ], primitive_pos)
71
+ if primitives[1 ] == -1
72
+ break
73
+ endif
74
+
75
+ if match (primitives[0 ], ' [0-9A-Za-z_.]\+:[0-9A-Za-z_.]\+' ) == -1
76
+ let separator_pos = strridx (a: args_str , ' :' , primitives[1 ])
77
+ if a: args_str [primitives[1 ] - 1 : primitives[1 ] - 1 ] == ' ['
78
+ " If `[` exist right before argument, current argument is inner of
79
+ " braket. So this argument is not standalone argument.
80
+ let primitive_pos = primitives[2 ]
81
+ continue
82
+ endif
83
+ let braket_start_pos = stridx (a: args_str , ' [' , separator_pos)
84
+ let next_separator_pos = stridx (a: args_str , ' :' , primitives[2 ])
85
+ let braket_end_pos = strridx (a: args_str , ' ]' , next_separator_pos)
86
+ if next_separator_pos == -1
87
+ if braket_start_pos == -1 && braket_end_pos == -1
88
+ \ && a: args_str [primitives[1 ] : ] == primitives[0 ]
89
+ " Current argument is last argument.
90
+ else
91
+ " Arguments are still remains.
92
+ let primitive_pos = primitives[2 ]
93
+ continue
94
+ endif
95
+ endif
96
+
97
+ if braket_start_pos < primitives[1 ] && primitives[1 ] < braket_end_pos
98
+ " Current argument is inner of braket,
99
+ " such as `List[str, str, str]`'s second `str`.
100
+ let primitive_pos = primitives[2 ]
101
+ continue
102
+ endif
103
+ endif
104
+
105
+ " `[: -1] trims `,`.
106
+ let arg = primitives[0 ][: -1 ]
107
+ let arg = substitute (arg, ' ,$' , ' ' , ' ' )
108
+
109
+ call add (args , {' val' : arg, ' start' : primitives[1 ]})
110
+ " Move current position.
111
+ let primitive_pos = primitives[2 ]
112
+ endwhile
113
+
114
+ " Parse nested typed args.
115
+ while 1
116
+ let start_idx = match (a: args_str , ' \[' , start_pos)
117
+ let end_idx = match (a: args_str , ' \]' , end_pos)
118
+
119
+ if start_idx == -1 && end_idx == -1
120
+ break
121
+ endif
122
+
123
+ if end_pos > start_idx
124
+ " For nested. e.g. `arg: List[List[List[int, int], List[List[int, int]]]`.
125
+ let idx = strridx (a: args_str , ' ,' , nested)
126
+ if idx == -1
127
+ let idx = strridx (a: args_str , ' (' , nested)
128
+ endif
129
+ let arg = a: args_str [idx + 1 : end_idx]
130
+ " Override previous arg by complete one.
131
+ let args [-1 ] = {' val' : arg, ' start' : idx + 1 }
132
+ else
133
+ let idx = strridx (a: args_str , ' ,' , start_idx)
134
+ if idx == -1
135
+ let idx = strridx (a: args_str , ' (' , start_idx)
136
+ endif
137
+
138
+ let arg = a: args_str [idx + 1 : end_idx]
139
+ call add (args , {' val' : arg, ' start' : idx + 1 })
140
+ let nested = start_idx
141
+ endif
142
+
143
+ let start_pos = start_idx + 1
144
+ let end_pos = end_idx + 1
145
+ endwhile
146
+
147
+ " Sort by argument start position.
148
+ call sort (args , ' s:compare' )
149
+ return map (args , {i , v - > substitute (v [' val' ], ' ,' , ' , ' , ' g' )})
150
+ endfunction
151
+
55
152
function ! s: parse_func (type , line )
56
153
let header = substitute (a: line , ' \s\|(.*\|:' , ' ' , ' g' )
57
154
58
155
let args_str = substitute (a: line , ' \s\|.*(\|).*' , ' ' , ' g' )
59
- let args = split (args_str, ' ,' )
156
+ if args_str = ~ ' :'
157
+ let args = s: parse_args (args_str)
158
+ else
159
+ " No typed args.
160
+ let args = split (args_str, ' ,' )
161
+ endif
60
162
61
- let arrow_index = match (a: line , " ->" )
163
+ let arrow_index = match (a: line , ' ->' )
164
+ let return_type = ' '
62
165
if arrow_index != -1
63
166
let substring = strpart (a: line , arrow_index + 2 )
64
167
" issue #28 `\W*` would deleted `.`.
65
- let return_type = substitute (substring, ' [^0-9A-Za-z_.]*' , ' ' , ' g' )
66
- else
67
- let return_type = ' '
168
+ let return_type = substitute (substring, ' [^0-9A-Za-z_.,\[\] ]*' , ' ' , ' g' )
169
+ " Add space after `,` such as `List[int, str]`.
170
+ let return_type = substitute (return_type, ' , ' , ' , ' , ' ' )
68
171
endif
69
172
70
- let parse = {' type' : a: type , ' header' : header, ' args' : args , ' return_type' : return_type}
173
+ let parse = {
174
+ \ ' type' : a: type ,
175
+ \ ' header' : header,
176
+ \ ' args' : args ,
177
+ \ ' return_type' : return_type
178
+ \ }
71
179
return parse
72
180
endfunction
73
181
@@ -77,7 +185,7 @@ function! s:parse(line)
77
185
78
186
if str = ~ s: regexs [' class' ]
79
187
let str = substitute (str, s: regexs [' class' ], ' ' , ' ' )
80
- return s: parseClass (str)
188
+ return s: parse_class (str)
81
189
endif
82
190
83
191
if str = ~ s: regexs [' def' ]
@@ -136,7 +244,7 @@ function! s:should_use_one_line_docstring(type, args, return_type)
136
244
return ! s: should_include_args (a: args )
137
245
endfunction
138
246
139
- function ! s: builddocstring (strs, indent , nested_indent)
247
+ function ! s: build_docstring (strs, indent , nested_indent)
140
248
let type = a: strs [' type' ]
141
249
let prefix = a: strs [' header' ]
142
250
let args = a: strs [' args' ]
@@ -242,7 +350,7 @@ function! pydocstring#insert()
242
350
let indent = indent . space
243
351
endif
244
352
try
245
- let result = s: builddocstring (docstring, indent , nested_indent)
353
+ let result = s: build_docstring (docstring, indent , nested_indent)
246
354
call s: insert (insertpos + 1 , result)
247
355
catch /^Template/
248
356
echomsg v: exception
@@ -257,9 +365,9 @@ function! s:insert(pos, docstring)
257
365
let paste = &g: paste
258
366
let &g: paste = 1
259
367
silent ! execute ' normal! ' . a: pos . ' G$'
260
- let currentpos = line (' .' )
368
+ let current_pos = line (' .' )
261
369
" If current position is bottom, add docstring below.
262
- if a: pos == currentpos
370
+ if a: pos == current_pos
263
371
silent ! execute ' normal! O' . a: docstring
264
372
else
265
373
silent ! execute ' normal! o' . a: docstring
0 commit comments