Package
The code described in the following section have now been made available in a separate package. Please see this repository for details: https://github.com/Xaldew/yasnippet-radical-snippets.
Old Answer
I use the package called yasnippet for something similar to this. After some minor changes I adapted it to use the the Google docstring style instead:
Do note however that it requires some setup:
The snippet itself needs to execute some utility elisp code to generate the text. This is typically solved by creating a file called .yas-setup.el
with the code inside the python-mode
snippet directory. It is however also possible to place the code somewhere inside your .emacs
instead.
The code for the snippet is:
# -*- mode: snippet -*-
# Insert Google style docstring and function definition.
# name: Python Google style Docstring
# key: defg
# type: snippet
# contributor: Xaldew
# --
def ${1:name}($2):
\"\"\"$3
${2:$(python-args-to-google-docstring yas-text t)}
${5:Returns:
$6
}
\"\"\"
${0:$$(let ((beg yas-snippet-beg)
(end yas-snippet-end))
(yas-expand-snippet
(buffer-substring-no-properties beg end) beg end
(quote ((yas-indent-line nil) (yas-wrap-around-region nil))))
(delete-trailing-whitespace beg (- end 1)))}
The code for the .yas-setup.el
is:
(defun python-args-to-google-docstring (text &optional make-fields)
"Return a reST docstring format for the python arguments in yas-text."
(let* ((indent (concat "\n" (make-string (current-column) 32)))
(args (python-split-args text))
(nr 0)
(formatted-args
(mapconcat
(lambda (x)
(concat " " (nth 0 x)
(if make-fields (format " ${%d:arg%d}" (cl-incf nr) nr))
(if (nth 1 x) (concat " \(default " (nth 1 x) "\)"))))
args
indent)))
(unless (string= formatted-args "")
(concat
(mapconcat 'identity
(list "" "Args:" formatted-args)
indent)
"\n"))))
Note that python-split-args
is provided by the standard snippets. I.e.:
https://github.com/AndreaCrotti/yasnippet-snippets/tree/master You do however get those by default when you install the package through package.el
.
With everything setup properly, you should be able to write "defg" followed by Tab to expand the snippet (See the image for an example).
There is still an issue with using this inside nested indentation, e.g., within classes or as nested functions. In those cases the docstring is erroneously indented an extra time for some reason. I'll update this post if I manage to fix that.
The snippet should now work inside other scopes by forbidding yasnippet
from auto-indenting the second expansion.