aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
authorFabián Ezequiel Gallina2014-12-27 20:58:45 -0300
committerFabián Ezequiel Gallina2014-12-27 20:58:45 -0300
commit2cb7592275bce47e44916134223b994a75e4b861 (patch)
tree8b9ebc87e8be0dcf0ab94a1f5cc963f393deb34b /lisp/progmodes/python.el
parent968d096203fd900c8497ed455cd2682f9875448f (diff)
downloademacs-2cb7592275bce47e44916134223b994a75e4b861.tar.gz
emacs-2cb7592275bce47e44916134223b994a75e4b861.zip
python.el: Native readline completion.
This commit adds native readline completion that fallbacks to the old mechanism when it cannot be used for the current interpreter. * lisp/progmodes/python.el (python-shell-completion-native-disabled-interpreters) (python-shell-completion-native-enable) (python-shell-completion-native-output-timeout): New defcustoms. (python-shell-completion-native-interpreter-disabled-p) (python-shell-completion-native-try) (python-shell-completion-native-setup) (python-shell-completion-native-turn-off) (python-shell-completion-native-turn-on) (python-shell-completion-native-turn-on-maybe) (python-shell-completion-native-turn-on-maybe-with-msg) (python-shell-completion-native-toggle): New functions. (python-shell-completion-native-get-completions): New function. (python-shell-completion-at-point): Use it. * test/automated/python-tests.el (python-shell-completion-native-interpreter-disabled-p-1): New test.
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el229
1 files changed, 214 insertions, 15 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 8a85763f765..c46c5d68019 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -69,7 +69,7 @@
69;; Besides that only the standard CPython (2.x and 3.x) shell and 69;; Besides that only the standard CPython (2.x and 3.x) shell and
70;; IPython are officially supported out of the box, the interaction 70;; IPython are officially supported out of the box, the interaction
71;; should support any other readline based Python shells as well 71;; should support any other readline based Python shells as well
72;; (e.g. Jython and Pypy have been reported to work). You can change 72;; (e.g. Jython and PyPy have been reported to work). You can change
73;; your default interpreter and commandline arguments by setting the 73;; your default interpreter and commandline arguments by setting the
74;; `python-shell-interpreter' and `python-shell-interpreter-args' 74;; `python-shell-interpreter' and `python-shell-interpreter-args'
75;; variables. This example enables IPython globally: 75;; variables. This example enables IPython globally:
@@ -119,18 +119,24 @@
119;; modify its behavior. 119;; modify its behavior.
120 120
121;; Shell completion: hitting tab will try to complete the current 121;; Shell completion: hitting tab will try to complete the current
122;; word. Shell completion is implemented in such way that if you 122;; word. The two built-in mechanisms depend on Python's readline
123;; change the `python-shell-interpreter' it should be possible to 123;; module: the "native" completion is tried first and is activated
124;; integrate custom logic to calculate completions. To achieve this 124;; when `python-shell-completion-native-enable' is non-nil, the
125;; you just need to set `python-shell-completion-setup-code' and 125;; current `python-shell-interpreter' is not a member of the
126;; `python-shell-completion-string-code'. The default provided code, 126;; `python-shell-completion-native-disabled-interpreters' variable and
127;; enables autocompletion for both CPython and IPython (and ideally 127;; `python-shell-completion-native-setup' succeeds; the "fallback" or
128;; any readline based Python shell). This code depends on the 128;; "legacy" mechanism works by executing Python code in the background
129;; readline module, so if you are using some Operating System that 129;; and enables auto-completion for shells that do not support
130;; bundles Python without it (like Windows), installing pyreadline 130;; receiving escape sequences (with some limitations, i.e. completion
131;; from URL `http://ipython.scipy.org/moin/PyReadline/Intro' should 131;; in blocks does not work). The code executed for the "fallback"
132;; suffice. To troubleshoot why you are not getting any completions 132;; completion can be found in `python-shell-completion-setup-code' and
133;; you can try the following in your Python shell: 133;; `python-shell-completion-string-code' variables. Their default
134;; values enable completion for both CPython and IPython, and probably
135;; any readline based shell (it's known to work with PyPy). If your
136;; Python installation lacks readline (like CPython for Windows),
137;; installing pyreadline (URL `http://ipython.org/pyreadline.html')
138;; should suffice. To troubleshoot why you are not getting any
139;; completions, you can try the following in your Python shell:
134 140
135;; >>> import readline, rlcompleter 141;; >>> import readline, rlcompleter
136 142
@@ -256,6 +262,7 @@
256(defvar outline-heading-end-regexp) 262(defvar outline-heading-end-regexp)
257 263
258(autoload 'comint-mode "comint") 264(autoload 'comint-mode "comint")
265(autoload 'help-function-arglist "help-fns")
259 266
260;;;###autoload 267;;;###autoload
261(add-to-list 'auto-mode-alist (cons (purecopy "\\.py\\'") 'python-mode)) 268(add-to-list 'auto-mode-alist (cons (purecopy "\\.py\\'") 'python-mode))
@@ -2997,6 +3004,194 @@ the full statement in the case of imports."
2997 "25.1" 3004 "25.1"
2998 "Completion string code must work for (i)pdb.") 3005 "Completion string code must work for (i)pdb.")
2999 3006
3007(defcustom python-shell-completion-native-disabled-interpreters
3008 ;; PyPy's readline cannot handle some escape sequences yet.
3009 (list "pypy")
3010 "List of disabled interpreters.
3011When a match is found, native completion is disabled."
3012 :type '(repeat string))
3013
3014(defcustom python-shell-completion-native-enable t
3015 "Enable readline based native completion."
3016 :type 'boolean)
3017
3018(defcustom python-shell-completion-native-output-timeout 0.01
3019 "Time in seconds to wait for completion output before giving up."
3020 :type 'float)
3021
3022(defvar python-shell-completion-native-redirect-buffer
3023 " *Python completions redirect*"
3024 "Buffer to be used to redirect output of readline commands.")
3025
3026(defun python-shell-completion-native-interpreter-disabled-p ()
3027 "Return non-nil if interpreter has native completion disabled."
3028 (when python-shell-completion-native-disabled-interpreters
3029 (string-match
3030 (regexp-opt python-shell-completion-native-disabled-interpreters)
3031 (file-name-nondirectory python-shell-interpreter))))
3032
3033(defun python-shell-completion-native-try ()
3034 "Return non-nil if can trigger native completion."
3035 (let ((python-shell-completion-native-enable t))
3036 (python-shell-completion-native-get-completions
3037 (get-buffer-process (current-buffer))
3038 nil "int")))
3039
3040(defun python-shell-completion-native-setup ()
3041 "Try to setup native completion, return non-nil on success."
3042 (let ((process (python-shell-get-process)))
3043 (python-shell-send-string
3044 (funcall
3045 'mapconcat
3046 #'identity
3047 (list
3048 "try:"
3049 " import readline, rlcompleter"
3050 ;; Remove parens on callables as it breaks completion on
3051 ;; arguments (e.g. str(Ari<tab>)).
3052 " class Completer(rlcompleter.Completer):"
3053 " def _callable_postfix(self, val, word):"
3054 " return word"
3055 " readline.set_completer(Completer().complete)"
3056 " if readline.__doc__ and 'libedit' in readline.__doc__:"
3057 " readline.parse_and_bind('bind ^I rl_complete')"
3058 " else:"
3059 " readline.parse_and_bind('tab: complete')"
3060 " print ('python.el: readline is available')"
3061 "except:"
3062 " print ('python.el: readline not available')")
3063 "\n")
3064 process)
3065 (python-shell-accept-process-output process)
3066 (when (save-excursion
3067 (re-search-backward
3068 (regexp-quote "python.el: readline is available") nil t 1))
3069 (python-shell-completion-native-try))))
3070
3071(defun python-shell-completion-native-turn-off (&optional msg)
3072 "Turn off shell native completions.
3073With argument MSG show deactivation message."
3074 (interactive "p")
3075 (python-shell-with-shell-buffer
3076 (set (make-local-variable 'python-shell-completion-native-enable) nil)
3077 (when msg
3078 (message "Shell native completion is disabled, using fallback"))))
3079
3080(defun python-shell-completion-native-turn-on (&optional msg)
3081 "Turn on shell native completions.
3082With argument MSG show deactivation message."
3083 (interactive "p")
3084 (python-shell-with-shell-buffer
3085 (set (make-local-variable 'python-shell-completion-native-enable) t)
3086 (python-shell-completion-native-turn-on-maybe msg)))
3087
3088(defun python-shell-completion-native-turn-on-maybe (&optional msg)
3089 "Turn on native completions if enabled and available.
3090With argument MSG show activation/deactivation message."
3091 (interactive "p")
3092 (python-shell-with-shell-buffer
3093 (when python-shell-completion-native-enable
3094 (cond
3095 ((python-shell-completion-native-interpreter-disabled-p)
3096 (python-shell-completion-native-turn-off msg))
3097 ((python-shell-completion-native-setup)
3098 (when msg
3099 (message "Shell native completion is enabled.")))
3100 (t (lwarn
3101 '(python python-shell-completion-native-turn-on-maybe)
3102 :warning
3103 (concat
3104 "Your `python-shell-interpreter' doesn't seem to "
3105 "support readline, yet `python-shell-completion-native' "
3106 (format "was `t' and %S is not part of the "
3107 (file-name-nondirectory python-shell-interpreter))
3108 "`python-shell-completion-native-disabled-interpreters' "
3109 "list. Native completions have been disabled locally. "))
3110 (python-shell-completion-native-turn-off msg))))))
3111
3112(defun python-shell-completion-native-turn-on-maybe-with-msg ()
3113 "Like `python-shell-completion-native-turn-on-maybe' but force messages."
3114 (python-shell-completion-native-turn-on-maybe t))
3115
3116(add-hook 'inferior-python-mode-hook
3117 #'python-shell-completion-native-turn-on-maybe-with-msg)
3118
3119(defun python-shell-completion-native-toggle (&optional msg)
3120 "Toggle shell native completion.
3121With argument MSG show activation/deactivation message."
3122 (interactive "p")
3123 (python-shell-with-shell-buffer
3124 (if python-shell-completion-native-enable
3125 (python-shell-completion-native-turn-off msg)
3126 (python-shell-completion-native-turn-on msg))
3127 python-shell-completion-native-enable))
3128
3129(defun python-shell-completion-native-get-completions (process import input)
3130 "Get completions using native readline for PROCESS.
3131When IMPORT is non-nil takes precedence over INPUT for
3132completion."
3133 (when (and python-shell-completion-native-enable
3134 (python-util-comint-last-prompt)
3135 (>= (point) (cdr (python-util-comint-last-prompt))))
3136 (let* ((input (or import input))
3137 (original-filter-fn (process-filter process))
3138 (redirect-buffer (get-buffer-create
3139 python-shell-completion-native-redirect-buffer))
3140 (separators (python-rx
3141 (or whitespace open-paren close-paren)))
3142 (trigger "\t\t\t")
3143 (new-input (concat input trigger))
3144 (input-length
3145 (save-excursion
3146 (+ (- (point-max) (comint-bol)) (length new-input))))
3147 (delete-line-command (make-string input-length ?\b))
3148 (input-to-send (concat new-input delete-line-command)))
3149 ;; Ensure restoring the process filter, even if the user quits
3150 ;; or there's some other error.
3151 (unwind-protect
3152 (with-current-buffer redirect-buffer
3153 ;; Cleanup the redirect buffer
3154 (delete-region (point-min) (point-max))
3155 ;; Mimic `comint-redirect-send-command', unfortunately it
3156 ;; can't be used here because it expects a newline in the
3157 ;; command and that's exactly what we are trying to avoid.
3158 (let ((comint-redirect-echo-input nil)
3159 (comint-redirect-verbose nil)
3160 (comint-redirect-perform-sanity-check nil)
3161 (comint-redirect-insert-matching-regexp nil)
3162 ;; Feed it some regex that will never match.
3163 (comint-redirect-finished-regexp "^\\'$")
3164 (comint-redirect-output-buffer redirect-buffer))
3165 ;; Compatibility with Emacs 24.x. Comint changed and
3166 ;; now `comint-redirect-filter' gets 3 args. This
3167 ;; checks which version of `comint-redirect-filter' is
3168 ;; in use based on its args and uses `apply-partially'
3169 ;; to make it up for the 3 args case.
3170 (if (= (length
3171 (help-function-arglist 'comint-redirect-filter)) 3)
3172 (set-process-filter
3173 process (apply-partially
3174 #'comint-redirect-filter original-filter-fn))
3175 (set-process-filter process #'comint-redirect-filter))
3176 (process-send-string process input-to-send)
3177 (accept-process-output
3178 process
3179 python-shell-completion-native-output-timeout)
3180 ;; XXX: can't use `python-shell-accept-process-output'
3181 ;; here because there are no guarantees on how output
3182 ;; ends. The workaround here is to call
3183 ;; `accept-process-output' until we don't find anything
3184 ;; else to accept.
3185 (while (accept-process-output
3186 process
3187 python-shell-completion-native-output-timeout))
3188 (cl-remove-duplicates
3189 (split-string
3190 (buffer-substring-no-properties
3191 (point-min) (point-max))
3192 separators t))))
3193 (set-process-filter process original-filter-fn)))))
3194
3000(defun python-shell-completion-get-completions (process import input) 3195(defun python-shell-completion-get-completions (process import input)
3001 "Do completion at point using PROCESS for IMPORT or INPUT. 3196 "Do completion at point using PROCESS for IMPORT or INPUT.
3002When IMPORT is non-nil takes precedence over INPUT for 3197When IMPORT is non-nil takes precedence over INPUT for
@@ -3054,11 +3249,15 @@ using that one instead of current buffer's process."
3054 last-prompt-end 3249 last-prompt-end
3055 (forward-char (length (match-string-no-properties 0))) 3250 (forward-char (length (match-string-no-properties 0)))
3056 (point)))) 3251 (point))))
3057 (end (point))) 3252 (end (point))
3253 (completion-fn
3254 (if python-shell-completion-native-enable
3255 #'python-shell-completion-native-get-completions
3256 #'python-shell-completion-get-completions)))
3058 (list start end 3257 (list start end
3059 (completion-table-dynamic 3258 (completion-table-dynamic
3060 (apply-partially 3259 (apply-partially
3061 #'python-shell-completion-get-completions 3260 completion-fn
3062 process import-statement))))) 3261 process import-statement)))))
3063 3262
3064(define-obsolete-function-alias 3263(define-obsolete-function-alias