~a-roehler/python-mode/XEmacs-compat-test

« back to all changes in this revision

Viewing changes to devel/ipython-integration.el

  • Committer: Andreas Roehler
  • Date: 2012-01-25 20:31:09 UTC
  • Revision ID: andreas.roehler@online.de-20120125203109-cfag2pbgyrxyh3xa
renamed: tools/ => devel/

make visible these files are not for common usage











Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;;; ipython-integration.el - work-sheet integrating ipython.el
 
2
 
 
3
;; ipython.el added support for IPython to python-mode.el: Copyright (C) 2002, 2003, 2004, 2005 Alexander Schmolck
 
4
;; Author:        Alexander Schmolck
 
5
;; Keywords:      ipython python languages oop
 
6
;; URL:           http://ipython.org
 
7
;; Compatibility: Emacs21, XEmacs21
 
8
;; FIXME: #$@! INPUT RING
 
9
 
 
10
;; Integration started from ipython-version "0.11"
 
11
 
 
12
;;; Commentary
 
13
 
 
14
;; Uses Ipython will be set as the python interpreter, see URL above.
 
15
 
 
16
;; defines the command `ipython-to-doctest', which
 
17
;; can be used to convert bits of a ipython session into something that can be
 
18
;; used for doctests.
 
19
 
 
20
;; For ipython sessions autocompletion with <tab>
 
21
;; is also enabled (experimental feature!). Please also note that all the
 
22
;; terminal functions in py-shell are handled by emacs's comint, **not** by
 
23
;; (i)python, so importing readline etc. will have 0 effect.
 
24
;;
 
25
;; To start an interactive ipython session run `py-shell' with ``M-x py-shell``
 
26
;; (or the default keybinding ``C-c C-!``).
 
27
;;
 
28
 
 
29
;; You can customize the arguments passed to the IPython instance at startup by
 
30
;; setting the ``py-python-command-args`` variable.  For example, to start
 
31
;; always in ``pylab`` mode with hardcoded light-background colors, you can
 
32
;; use::
 
33
;;
 
34
;; (setq py-python-command-args '("-pylab" "--colors" "LightBG"))
 
35
 
 
36
 
 
37
;; NOTE: This mode is currently somewhat alpha and although I hope that it
 
38
;; will work fine for most cases, doing certain things (like the
 
39
;; autocompletion and a decent scheme to switch between python interpreters)
 
40
;; properly will also require changes to ipython that will likely have to wait
 
41
;; for a larger rewrite scheduled some time in the future.
 
42
;;
 
43
 
 
44
;; Hints for effective usage
 
45
;; -------------------------
 
46
;;
 
47
;; - IMO the best feature by far of the ipython/emacs combo is how much easier
 
48
;;   it makes it to find and fix bugs thanks to the ``%pdb on or %debug``/
 
49
;;   pdbtrack combo. Try it: first in the ipython to shell do ``%pdb on`` then
 
50
;;   do something that will raise an exception (FIXME nice example), or type
 
51
;;   ``%debug`` after the exception has been raised.  YOu'll be amazed at how
 
52
;;   easy it is to inspect the live objects in each stack frames and to jump to
 
53
;;   the corresponding sourcecode locations as you walk up and down the stack
 
54
;;   trace (even without ``%pdb on`` you can always use ``C-c -``
 
55
;;   (`py-up-exception') to jump to the corresponding source code locations).
 
56
;;
 
57
 
 
58
;; - This is not really specific to ipython, but for more convenient history
 
59
;;   access you might want to add something like the following to *the beggining*
 
60
;;   of your ``.emacs`` (if you want behavior that's more similar to stand-alone
 
61
;;   ipython, you can change ``meta p`` etc. for ``control p``)::
 
62
;;
 
63
;;         (require 'comint)
 
64
;;         (define-key comint-mode-map [(meta p)]
 
65
;;           'comint-previous-matching-input-from-input)
 
66
;;         (define-key comint-mode-map [(meta n)]
 
67
;;           'comint-next-matching-input-from-input)
 
68
;;         (define-key comint-mode-map [(control meta n)]
 
69
;;            'comint-next-input)
 
70
;;         (define-key comint-mode-map [(control meta p)]
 
71
;;            'comint-previous-input)
 
72
;;
 
73
 
 
74
;; - Be aware that if you customize py-python-command previously, this value
 
75
;;   will override what ipython.el does (because loading the customization
 
76
;;   variables comes later).
 
77
;;
 
78
 
 
79
;; Please send comments and feedback to the ipython-list
 
80
;; (<ipython-user@scipy.org>) where I (a.s.) or someone else will try to
 
81
;; answer them (it helps if you specify your emacs version, OS etc;
 
82
;; familiarity with <http://www.catb.org/~esr/faqs/smart-questions.html> might
 
83
;; speed up things further).
 
84
;;
 
85
;; Footnotes:
 
86
;;
 
87
;;     [1] If you don't know what `load-path' is, C-h v load-path will tell
 
88
;;     you; if required you can also add a new directory. So assuming that
 
89
;;     ipython.el resides in ~/el/, put this in your emacs:
 
90
;;
 
91
;;
 
92
;;           (add-to-list 'load-path "~/el")
 
93
;;           (setq ipython-command "/some-path/ipython")
 
94
;;           (require 'ipython)
 
95
;;
 
96
;;
 
97
;;
 
98
;;
 
99
;; TODO:
 
100
;;      - do autocompletion properly
 
101
;;      - implement a proper switching between python interpreters
 
102
;;
 
103
;; BUGS:
 
104
;;      - neither::
 
105
;;
 
106
;;         (py-shell "-c print 'FOOBAR'")
 
107
;;
 
108
;;        nor::
 
109
;;
 
110
;;         (let ((py-python-command-args (append py-python-command-args
 
111
;;                                              '("-c" "print 'FOOBAR'"))))
 
112
;;           (py-shell))
 
113
;;
 
114
;;        seem to print anything as they should
 
115
;;
 
116
;;      - look into init priority issues with `py-python-command' (if it's set
 
117
;;        via custom)
 
118
 
 
119
;;; Code
 
120
(require 'cl)
 
121
(require 'shell)
 
122
(require 'executable)
 
123
(require 'ansi-color)
 
124
 
 
125
;; XXX load python-mode, so that we can screw around with its variables
 
126
;; this has the disadvantage that python-mode is loaded even if no
 
127
;; python-file is ever edited etc. but it means that `py-shell' works
 
128
;; without loading a python-file first. Obviously screwing around with
 
129
;; python-mode's variables like this is a mess, but well.
 
130
(require 'python-mode)
 
131
;; turn on ansi colors for ipython and activate completion
 
132
;; (defun ipython-shell-hook ()
 
133
;;   ;; the following is to synchronize dir-changes
 
134
;;   (make-local-variable 'shell-dirstack)
 
135
;;   (setq shell-dirstack nil)
 
136
;;   (make-local-variable 'shell-last-dir)
 
137
;;   (setq shell-last-dir nil)
 
138
;;   (make-local-variable 'shell-dirtrackp)
 
139
;;   (setq shell-dirtrackp t)
 
140
;;   (add-hook 'comint-input-filter-functions 'shell-directory-tracker nil t)
 
141
;;
 
142
;;   (ansi-color-for-comint-mode-on)
 
143
;;   (define-key py-shell-map [tab] 'ipython-complete)
 
144
;;   ;; Add this so that tab-completion works both in X11 frames and inside
 
145
;;   ;; terminals (such as when emacs is called with -nw).
 
146
;;   (define-key py-shell-map "\t" 'ipython-complete)
 
147
;;   ;;XXX this is really just a cheap hack, it only completes symbols in the
 
148
;;   ;;interactive session -- useful nonetheless.
 
149
;;   (define-key py-mode-map [(meta tab)] 'ipython-complete)
 
150
;;
 
151
;;)
 
152
;;    (add-hook 'py-shell-hook 'ipython-shell-hook)
 
153
;; Regular expression that describes tracebacks for IPython in context and
 
154
;; verbose mode.
 
155
 
 
156
;;Adapt python-mode settings for ipython.
 
157
;; (this works for %xmode 'verbose' or 'context')
 
158
 
 
159
;; XXX putative regexps for syntax errors; unfortunately the
 
160
;;     current python-mode traceback-line-re scheme is too primitive,
 
161
;;     so it's either matching syntax errors, *or* everything else
 
162
;;     (XXX: should ask Fernando for a change)
 
163
;;"^   File \"\\(.*?\\)\", line \\([0-9]+\\).*\n.*\n.*\nSyntaxError:"
 
164
;;^   File \"\\(.*?\\)\", line \\([0-9]+\\)"
 
165
 
 
166
(setq py-traceback-line-re
 
167
      "\\(^[^\t >].+?\\.py\\).*\n +[0-9]+[^\00]*?\n-+> \\([0-9]+\\)+")
 
168
 
 
169
;; Recognize the ipython pdb, whose prompt is 'ipdb>' or 'ipydb>'
 
170
;;instead of '(Pdb)'
 
171
(setq py-pdbtrack-input-prompt "\n[(<]*[Ii]?[Pp]y?db[>)]+ ")
 
172
(setq pydb-pydbtrack-input-prompt "\n[(]*ipydb[>)]+ ")
 
173
 
 
174
(setq py-shell-input-prompt-1-regexp "^In \\[[0-9]+\\]: *"
 
175
      py-shell-input-prompt-2-regexp "^   [.][.][.]+: *")
 
176
;; select a suitable color-scheme
 
177
(unless (member "--colors" py-python-command-args)
 
178
  (setq py-python-command-args
 
179
        (nconc py-python-command-args
 
180
               (list "--colors"
 
181
                     (cond
 
182
                      ((eq frame-background-mode 'dark)
 
183
                       "Linux")
 
184
                      ((eq frame-background-mode 'light)
 
185
                       "LightBG")
 
186
                      (t ; default (backg-mode isn't always set by XEmacs)
 
187
                       "LightBG"))))))
 
188
(unless (equal ipython-backup-of-py-python-command py-python-command)
 
189
  (setq ipython-backup-of-py-python-command py-python-command))
 
190
(setq py-python-command ipython-command)
 
191
 
 
192
;; MODIFY py-shell so that it loads the editing history
 
193
(defadvice py-shell (around py-shell-with-history)
 
194
  "Add persistent command-history support (in
 
195
$PYTHONHISTORY (or \"~/.ipython/history\", if we use IPython)). Also, if
 
196
`py-shell-initial-switch-buffers' is nil, it only switches to *Python* if that
 
197
buffer already exists."
 
198
  (if (comint-check-proc "*Python*")
 
199
      ad-do-it
 
200
    (setq comint-input-ring-file-name
 
201
          (if (string-equal py-python-command ipython-command)
 
202
              (concat (or (getenv "IPYTHONDIR") "~/.ipython") "/history")
 
203
            (or (getenv "PYTHONHISTORY") "~/.python-history.py")))
 
204
    (comint-read-input-ring t)
 
205
    (let ((buf (current-buffer)))
 
206
      ad-do-it
 
207
      (unless py-shell-initial-switch-buffers
 
208
        (switch-to-buffer-other-window buf)))))
 
209
(ad-activate 'py-shell)
 
210
 
 
211
(defun ipython-to-doctest (start end)
 
212
  "Transform a cut-and-pasted bit from an IPython session into something that
 
213
looks like it came from a normal interactive python session, so that it can
 
214
be used in doctests. Example:
 
215
 
 
216
    In [1]: import sys
 
217
 
 
218
    In [2]: sys.stdout.write 'Hi!\n'
 
219
    ------> sys.stdout.write ('Hi!\n')
 
220
    Hi!
 
221
 
 
222
    In [3]: 3 + 4
 
223
    Out[3]: 7
 
224
 
 
225
gets converted to:
 
226
 
 
227
    >>> import sys
 
228
    >>> sys.stdout.write ('Hi!\n')
 
229
    Hi!
 
230
    >>> 3 + 4
 
231
    7
 
232
 
 
233
"
 
234
  (interactive "*r\n")
 
235
  ;(message (format "###DEBUG s:%de:%d" start end))
 
236
  (save-excursion
 
237
    (save-match-data
 
238
      ;; replace ``In [3]: bla`` with ``>>> bla`` and
 
239
      ;;         ``... :   bla`` with ``...    bla``
 
240
      (goto-char start)
 
241
      (while (re-search-forward ipython-de-input-prompt-regexp end t)
 
242
        ;(message "finding 1")
 
243
        (cond ((match-string 3)         ;continued
 
244
               (replace-match "... \\3" t nil))
 
245
              (t
 
246
               (replace-match ">>> \\1\\2" t nil))))
 
247
      ;; replace ``
 
248
      (goto-char start)
 
249
      (while (re-search-forward ipython-de-output-prompt-regexp end t)
 
250
        (replace-match "" t nil)))))
 
251
 
 
252
(defvar ipython-completion-command-string
 
253
  "print(';'.join(get_ipython().Completer.all_completions('%s'))) #PYTHON-MODE SILENT\n"
 
254
  "The string send to ipython to query for all possible completions")
 
255
 
 
256
;; xemacs doesn't have `comint-preoutput-filter-functions' so we'll try the
 
257
;; following wonderful hack to work around this case
 
258
(if (featurep 'xemacs)
 
259
    ;;xemacs
 
260
    (defun ipython-complete ()
 
261
      "Try to complete the python symbol before point. Only knows about the stuff
 
262
in the current *Python* session."
 
263
      (interactive)
 
264
      (let* ((ugly-return nil)
 
265
             (sep ";")
 
266
             (python-process (or (get-buffer-process (current-buffer))
 
267
                                 ;XXX hack for .py buffers
 
268
                                 (get-process py-which-bufname)))
 
269
             ;; XXX currently we go backwards to find the beginning of an
 
270
             ;; expression part; a more powerful approach in the future might be
 
271
             ;; to let ipython have the complete line, so that context can be used
 
272
             ;; to do things like filename completion etc.
 
273
             (beg (save-excursion (skip-chars-backward "a-z0-9A-Z_." (point-at-bol))
 
274
                                  (point)))
 
275
             (end (point))
 
276
             (pattern (buffer-substring-no-properties beg end))
 
277
             (completions nil)
 
278
             (completion-table nil)
 
279
             completion
 
280
             (comint-output-filter-functions
 
281
              (append comint-output-filter-functions
 
282
                      '(ansi-color-filter-apply
 
283
                        (lambda (string)
 
284
                                        ;(message (format "DEBUG filtering: %s" string))
 
285
                          (setq ugly-return (concat ugly-return string))
 
286
                          (delete-region comint-last-output-start
 
287
                                         (process-mark (get-buffer-process (current-buffer)))))))))
 
288
        ;(message (format "#DEBUG pattern: '%s'" pattern))
 
289
        (process-send-string python-process
 
290
                              (format ipython-completion-command-string pattern))
 
291
        (accept-process-output python-process)
 
292
 
 
293
        ;(message (format "DEBUG return: %s" ugly-return))
 
294
        (setq completions
 
295
              (split-string (substring ugly-return 0 (position ?\n ugly-return)) sep))
 
296
        (setq completion-table (loop for str in completions
 
297
                                     collect (list str nil)))
 
298
        (setq completion (try-completion pattern completion-table))
 
299
        (cond ((eq completion t))
 
300
              ((null completion)
 
301
               (message "Can't find completion for \"%s\"" pattern)
 
302
               (ding))
 
303
              ((not (string= pattern completion))
 
304
               (delete-region beg end)
 
305
               (insert completion))
 
306
              (t
 
307
               (message "Making completion list...")
 
308
               (with-output-to-temp-buffer "*Python Completions*"
 
309
                 (display-completion-list (all-completions pattern completion-table)))
 
310
               (message "Making completion list...%s" "done")))))
 
311
  ;; emacs
 
312
  (defun ipython-complete ()
 
313
    "Try to complete the python symbol before point. Only knows about the stuff
 
314
in the current *Python* session."
 
315
    (interactive)
 
316
    (let* ((ugly-return nil)
 
317
           (sep ";")
 
318
           (python-process (or (get-buffer-process (current-buffer))
 
319
                                        ;XXX hack for .py buffers
 
320
                               (get-process py-which-bufname)))
 
321
           ;; XXX currently we go backwards to find the beginning of an
 
322
           ;; expression part; a more powerful approach in the future might be
 
323
           ;; to let ipython have the complete line, so that context can be used
 
324
           ;; to do things like filename completion etc.
 
325
           (beg (save-excursion (skip-chars-backward "a-z0-9A-Z_./" (point-at-bol))
 
326
                                (point)))
 
327
           (end (point))
 
328
           (pattern (buffer-substring-no-properties beg end))
 
329
           (completions nil)
 
330
           (completion-table nil)
 
331
           completion
 
332
         (comint-preoutput-filter-functions
 
333
          (append comint-preoutput-filter-functions
 
334
                  '(ansi-color-filter-apply
 
335
                    (lambda (string)
 
336
                      (setq ugly-return (concat ugly-return string))
 
337
                      "")))))
 
338
      (process-send-string python-process
 
339
                            (format ipython-completion-command-string pattern))
 
340
      (accept-process-output python-process)
 
341
      (setq completions
 
342
            (split-string (substring ugly-return 0 (position ?\n ugly-return)) sep))
 
343
                                        ;(message (format "DEBUG completions: %S" completions))
 
344
      (setq completion-table (loop for str in completions
 
345
                                   collect (list str nil)))
 
346
      (setq completion (try-completion pattern completion-table))
 
347
      (cond ((eq completion t))
 
348
            ((null completion)
 
349
             (message "Can't find completion for \"%s\"" pattern)
 
350
             (ding))
 
351
            ((not (string= pattern completion))
 
352
             (delete-region beg end)
 
353
             (insert completion))
 
354
            (t
 
355
             (message "Making completion list...")
 
356
             (with-output-to-temp-buffer "*IPython Completions*"
 
357
               (display-completion-list (all-completions pattern completion-table)))
 
358
             (message "Making completion list...%s" "done")))))
 
359
)
 
360
 
 
361
;;; autoindent support: patch sent in by Jin Liu <m.liu.jin@gmail.com>,
 
362
;;; originally written by doxgen@newsmth.net
 
363
;;; Minor modifications by fperez for xemacs compatibility.
 
364
 
 
365
(defvar ipython-autoindent t
 
366
 "If non-nil, enable autoindent for IPython shell through python-mode.")
 
367
 
 
368
(defvar ipython-indenting-buffer-name "*IPython Indentation Calculation*"
 
369
 "Temporary buffer for indenting multiline statement.")
 
370
 
 
371
(defun ipython-get-indenting-buffer ()
 
372
 "Return a temporary buffer set in python-mode. Create one if necessary."
 
373
 (let ((buf (get-buffer-create ipython-indenting-buffer-name)))
 
374
   (set-buffer buf)
 
375
   (unless (eq major-mode 'python-mode)
 
376
     (python-mode))
 
377
   buf))
 
378
 
 
379
(defvar ipython-indentation-string nil
 
380
 "Indentation for the next line in a multiline statement.")
 
381
 
 
382
(defun ipython-send-and-indent ()
 
383
 "Send the current line to IPython, and calculate the indentation for
 
384
the next line."
 
385
 (interactive)
 
386
 (if ipython-autoindent
 
387
     (let ((line (buffer-substring (point-at-bol) (point)))
 
388
           (after-prompt1)
 
389
           (after-prompt2))
 
390
       (save-excursion
 
391
           (comint-bol t)
 
392
           (if (looking-at py-shell-input-prompt-1-regexp)
 
393
               (setq after-prompt1 t)
 
394
             (setq after-prompt2 (looking-at py-shell-input-prompt-2-regexp)))
 
395
           (with-current-buffer (ipython-get-indenting-buffer)
 
396
             (when after-prompt1
 
397
               (erase-buffer))
 
398
             (when (or after-prompt1 after-prompt2)
 
399
               (delete-region (point-at-bol) (point))
 
400
               (insert line)
 
401
               (newline-and-indent))))))
 
402
 ;; send input line to ipython interpreter
 
403
 (comint-send-input))
 
404
 
 
405
(defun ipython-indentation-hook (string)
 
406
 "Insert indentation string if py-shell-input-prompt-2-regexp
 
407
matches last process output."
 
408
 (let* ((start-marker (or comint-last-output-start
 
409
                          (point-min-marker)))
 
410
        (end-marker (process-mark (get-buffer-process (current-buffer))))
 
411
        (text (ansi-color-filter-apply (buffer-substring start-marker end-marker))))
 
412
   ;; XXX if `text' matches both pattern, it MUST be the last prompt-2
 
413
   (when (and (string-match py-shell-input-prompt-2-regexp text)
 
414
              (not (string-match "\n$" text)))
 
415
     (with-current-buffer (ipython-get-indenting-buffer)
 
416
       (setq ipython-indentation-string
 
417
             (buffer-substring (point-at-bol) (point))))
 
418
     (goto-char end-marker)
 
419
     (insert ipython-indentation-string)
 
420
     (setq ipython-indentation-string nil))))
 
421
 
 
422
(add-hook 'py-shell-hook
 
423
         (lambda ()
 
424
           (add-hook 'comint-output-filter-functions
 
425
                     'ipython-indentation-hook)))
 
426
 
 
427
(define-key py-shell-map (kbd "RET") 'ipython-send-and-indent)
 
428
;;; / end autoindent support
 
429
 
 
430
(provide 'ipython)