When adding the docstring to a fuction
def func(): """|"""
RET I have this
def func(): """ """
Instead of this
def func(): """ | """
| is a cursor.
The problem stems from this check in
(defun electric-indent-post-self-insert-function () ... (when (and electric-indent-mode ... (let ((act (or (run-hook-with-args-until-success 'electric-indent-functions last-command-event) (memq last-command-event electric-indent-chars)))) (not (or (memq act '(nil no-indent)) ;; In a string or comment. (unless (eq act 'do-indent) (nth 8 (syntax-ppss))))))))
You can get around this by doing:
(defun always-do-indent (_char) 'do-indent) (defun my-python-mode-hook () (add-hook 'electric-indent-functions #'always-do-indent nil t)) (add-hook 'python-mode-hook #'my-python-mode-hook)
Which will result in:
def foo(): """ |"""
To get the extra newline in the middle that you want, (assuming you have
electric-pair-mode enabled) you can add this electric pair mode post self insert hook (adapted from Stefan's answer at https://stackoverflow.com/a/19715115/319698):
(defun python-electric-pair-docstring-delimiter () (when (and electric-pair-mode (memq last-command-event '(?\" ?\')) (let ((count 0)) (while (eq (char-before (- (point) count)) last-command-event) (setq count (1+ count))) (= count 3))) (save-excursion (insert ?\n (make-string 3 last-command-event)) (indent-according-to-mode)) (newline-and-indent))) (defun my-python-mode-hook () (add-hook 'post-self-insert-hook #'python-electric-pair-docstring-delimiter 'append t)) (add-hook 'python-mode-hook #'my-python-mode-hook)
I use yasnippet which avoids this problem. after writing function name, type
d and hit
TAB, it will expand to multiline string with correct indentation
def foo(): d
TAB, it becomes
def foo(): """| """
You can also write a custom snippet to make it
def foo(): """ | """