1

When adding the docstring to a fuction

def func():
    """|"""

After pressing RET I have this

def func():
    """
"""

Instead of this

def func():
    """
    |
    """

| is a cursor.

2 Answers 2

0

The problem stems from this check in electric-indent-post-self-insert-function:

(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)
8
  • Well, I've abandoned emacs for now, but as you can see this isn't doing what I wanted. Thanks anyway. Am I right that the core of a problem is that it doesn't indent in strings and comments? Commented May 24, 2017 at 16:36
  • yes, just like it does for parentheses and brackets etc. Commented May 24, 2017 at 16:43
  • I was, yes. Sorry I haven't mentioned it. Commented May 24, 2017 at 16:57
  • The first suggestion works as promised, but the second one doesn't change anything. Commented May 24, 2017 at 18:22
  • 1
    (make-string 3 last-command-event) is wrong. It inserts three unneeded quotes. Thanks! Commented May 24, 2017 at 19:07
-1

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

After hitting TAB, it becomes

def foo():
   """|
   """

You can also write a custom snippet to make it

def foo():
   """
   |
   """
1
  • 1
    Yeah, I use a lot of snippets in vim too, but I can't accept this as an answer. I'm interested in fixing this particular emacs bug, not just solving the problem via workaround. I think something like defadvice should help, but I'm to feeble in elisp. Commented Mar 25, 2017 at 8:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.