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? May 24, 2017 at 16:36
  • yes, just like it does for parentheses and brackets etc. May 24, 2017 at 16:43
  • I was, yes. Sorry I haven't mentioned it. May 24, 2017 at 16:57
  • The first suggestion works as promised, but the second one doesn't change anything. May 24, 2017 at 18:22
  • 1
    (make-string 3 last-command-event) is wrong. It inserts three unneeded quotes. Thanks! 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. Mar 25, 2017 at 8:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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