[IPython-user] autoindentation problem in emacs

Liu Jin m.liu.jin at gmail.com
Sun Mar 26 23:11:02 CST 2006


>>>>> SK  <skokot at o2.pl> writes:
    > Now autoindent works. The only problem is that when new prompt
    > comes, the indentation remains as in the example below.

    > In [3]: for i in range(2):
    >    ...:     for j in range(1):
    >    ...:         print i, j
    >    ...:
    > 0 0
    > 1 0             | cursor comes here
    >                 v
    > In [4]:         x = 5

I've also noticed that. Here's the problematic part:

(defun ipython-newline-and-indent ()
  (interactive)
  (if ipython-autoindent
        ...
        (comint-send-input)
        (insert indention))

I should really check if current line begins with "   ...:"
(i.e. py-shell-input-prompt-2-regexp) before inserting
whitespaces. But the tricky part is, after the comint-send-input call
(which sends current line to ipython), the response is yet to come. 

So here's another attempt. It uses comint-output-filter. I have a gut
feeling that this is unreliable, but it seems to work so far...

<elisp code below>

(defvar ipython-autoindent t
  "If non-nil, enable autoindent for IPython shell through python-mode.")

(defvar ipython-indenting-buffer-name "*IPython Indentation Calculation*"
  "Temporary buffer for indenting multiline statement.")

(defun ipython-get-indenting-buffer ()
  "Return a temporary buffer set in python-mode. Create one if necessary."
  (let ((buf (get-buffer-create ipython-indenting-buffer-name)))
    (set-buffer buf)
    (unless (eq major-mode 'python-mode)
      (python-mode))
    buf))

(defvar ipython-indentation-string nil
  "Indentation for the next line in a multiline statement.")

(defun ipython-newline-and-indent ()
  "Send the current line to IPython, and calculate the indentation for the next line."
  (interactive)
  (if ipython-autoindent
      (let ((line (buffer-substring (line-beginning-position) (point)))
            (after-prompt1)
            (after-prompt2))
        (save-excursion
            (comint-bol t)
            (if (looking-at py-shell-input-prompt-1-regexp)
                (setq after-prompt1 t)
              (setq after-prompt2 (looking-at py-shell-input-prompt-2-regexp)))
            (set-buffer (ipython-get-indenting-buffer))
            (when after-prompt1
              (erase-buffer))
            (when (or after-prompt1 after-prompt2)
              (delete-region (line-beginning-position) (point))
              (insert line)
              (newline-and-indent)
              (setq ipython-indentation-string
                    (buffer-substring (line-beginning-position) (point)))))))
  (comint-send-input))

(defun ipython-indentation-hook (str)
  "Insert indentation string if py-shell-input-prompt-2-regexp
matches last process output."
  (or (= (length str) 0)
      (eq ipython-indentation-string nil)
      (progn
        (when (string-match
               py-shell-input-prompt-2-regexp
               (buffer-substring comint-last-output-start
                                 (process-mark (get-buffer-process
                                                (current-buffer)))))
          (insert ipython-indentation-string))
        (setq ipython-indentation-string nil))))

(add-hook 'py-shell-hook
          (lambda ()
            (add-hook 'comint-output-filter-functions
                      'ipython-indentation-hook)))

(define-key py-shell-map (kbd "RET") 'ipython-newline-and-indent)




More information about the IPython-user mailing list