aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el136
1 files changed, 94 insertions, 42 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index c89241bbaa0..da38152558f 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -3040,10 +3040,14 @@ When a match is found, native completion is disabled."
3040 "Enable readline based native completion." 3040 "Enable readline based native completion."
3041 :type 'boolean) 3041 :type 'boolean)
3042 3042
3043(defcustom python-shell-completion-native-output-timeout 0.01 3043(defcustom python-shell-completion-native-output-timeout 5.0
3044 "Time in seconds to wait for completion output before giving up." 3044 "Time in seconds to wait for completion output before giving up."
3045 :type 'float) 3045 :type 'float)
3046 3046
3047(defcustom python-shell-completion-native-try-output-timeout 1.0
3048 "Time in seconds to wait for *trying* native completion output."
3049 :type 'float)
3050
3047(defvar python-shell-completion-native-redirect-buffer 3051(defvar python-shell-completion-native-redirect-buffer
3048 " *Python completions redirect*" 3052 " *Python completions redirect*"
3049 "Buffer to be used to redirect output of readline commands.") 3053 "Buffer to be used to redirect output of readline commands.")
@@ -3057,7 +3061,9 @@ When a match is found, native completion is disabled."
3057 3061
3058(defun python-shell-completion-native-try () 3062(defun python-shell-completion-native-try ()
3059 "Return non-nil if can trigger native completion." 3063 "Return non-nil if can trigger native completion."
3060 (let ((python-shell-completion-native-enable t)) 3064 (let ((python-shell-completion-native-enable t)
3065 (python-shell-completion-native-output-timeout
3066 python-shell-completion-native-try-output-timeout))
3061 (python-shell-completion-native-get-completions 3067 (python-shell-completion-native-get-completions
3062 (get-buffer-process (current-buffer)) 3068 (get-buffer-process (current-buffer))
3063 nil "int"))) 3069 nil "int")))
@@ -3065,27 +3071,73 @@ When a match is found, native completion is disabled."
3065(defun python-shell-completion-native-setup () 3071(defun python-shell-completion-native-setup ()
3066 "Try to setup native completion, return non-nil on success." 3072 "Try to setup native completion, return non-nil on success."
3067 (let ((process (python-shell-get-process))) 3073 (let ((process (python-shell-get-process)))
3068 (python-shell-send-string 3074 (python-shell-send-string "
3069 (funcall 3075def __PYTHON_EL_native_completion_setup():
3070 'mapconcat 3076 try:
3071 #'identity 3077 import readline
3072 (list 3078 try:
3073 "try:" 3079 import __builtin__
3074 " import readline, rlcompleter" 3080 except ImportError:
3075 ;; Remove parens on callables as it breaks completion on 3081 # Python 3
3076 ;; arguments (e.g. str(Ari<tab>)). 3082 import builtins as __builtin__
3077 " class Completer(rlcompleter.Completer):" 3083 builtins = dir(__builtin__)
3078 " def _callable_postfix(self, val, word):" 3084 is_ipython = ('__IPYTHON__' in builtins or
3079 " return word" 3085 '__IPYTHON__active' in builtins)
3080 " readline.set_completer(Completer().complete)" 3086 class __PYTHON_EL_Completer:
3081 " if readline.__doc__ and 'libedit' in readline.__doc__:" 3087 PYTHON_EL_WRAPPED = True
3082 " readline.parse_and_bind('bind ^I rl_complete')" 3088 def __init__(self, completer):
3083 " else:" 3089 self.completer = completer
3084 " readline.parse_and_bind('tab: complete')" 3090 self.last_completion = None
3085 " print ('python.el: readline is available')" 3091 def __call__(self, text, state):
3086 "except:" 3092 if state == 0:
3087 " print ('python.el: readline not available')") 3093 # The first completion is always a dummy completion. This
3088 "\n") 3094 # ensures proper output for sole completions and a current
3095 # input safeguard when no completions are available.
3096 self.last_completion = None
3097 completion = '0__dummy_completion__'
3098 else:
3099 completion = self.completer(text, state - 1)
3100 if not completion:
3101 if state == 1:
3102 # When no completions are available, two non-sharing
3103 # prefix strings are returned just to ensure output
3104 # while preventing changes to current input.
3105 completion = '1__dummy_completion__'
3106 elif self.last_completion != '~~~~__dummy_completion__':
3107 # This marks the end of output.
3108 completion = '~~~~__dummy_completion__'
3109 elif completion.endswith('('):
3110 # Remove parens on callables as it breaks completion on
3111 # arguments (e.g. str(Ari<tab>)).
3112 completion = completion[:-1]
3113 self.last_completion = completion
3114 return completion
3115 completer = readline.get_completer()
3116 if not completer:
3117 # Used as last resort to avoid breaking customizations.
3118 import rlcompleter
3119 completer = readline.get_completer()
3120 if completer and not getattr(completer, 'PYTHON_EL_WRAPPED', False):
3121 # Wrap the existing completer function only once.
3122 new_completer = __PYTHON_EL_Completer(completer)
3123 if not is_ipython:
3124 readline.set_completer(new_completer)
3125 else:
3126 # IPython hacks readline such that `readline.set_completer`
3127 # won't work. This workaround injects the new completer
3128 # function into the existing instance directly.
3129 instance = getattr(completer, 'im_self', completer.__self__)
3130 instance.rlcomplete = new_completer
3131 if readline.__doc__ and 'libedit' in readline.__doc__:
3132 readline.parse_and_bind('bind ^I rl_complete')
3133 else:
3134 readline.parse_and_bind('tab: complete')
3135 # Require just one tab to send output.
3136 readline.parse_and_bind('set show-all-if-ambiguous on')
3137 print ('python.el: readline is available')
3138 except IOError:
3139 print ('python.el: readline not available')
3140__PYTHON_EL_native_completion_setup()"
3089 process) 3141 process)
3090 (python-shell-accept-process-output process) 3142 (python-shell-accept-process-output process)
3091 (when (save-excursion 3143 (when (save-excursion
@@ -3163,9 +3215,8 @@ completion."
3163 (original-filter-fn (process-filter process)) 3215 (original-filter-fn (process-filter process))
3164 (redirect-buffer (get-buffer-create 3216 (redirect-buffer (get-buffer-create
3165 python-shell-completion-native-redirect-buffer)) 3217 python-shell-completion-native-redirect-buffer))
3166 (separators (python-rx 3218 (separators (python-rx (or whitespace open-paren close-paren)))
3167 (or whitespace open-paren close-paren))) 3219 (trigger "\t")
3168 (trigger "\t\t\t")
3169 (new-input (concat input trigger)) 3220 (new-input (concat input trigger))
3170 (input-length 3221 (input-length
3171 (save-excursion 3222 (save-excursion
@@ -3187,7 +3238,8 @@ completion."
3187 (comint-redirect-insert-matching-regexp nil) 3238 (comint-redirect-insert-matching-regexp nil)
3188 ;; Feed it some regex that will never match. 3239 ;; Feed it some regex that will never match.
3189 (comint-redirect-finished-regexp "^\\'$") 3240 (comint-redirect-finished-regexp "^\\'$")
3190 (comint-redirect-output-buffer redirect-buffer)) 3241 (comint-redirect-output-buffer redirect-buffer)
3242 (current-time (float-time)))
3191 ;; Compatibility with Emacs 24.x. Comint changed and 3243 ;; Compatibility with Emacs 24.x. Comint changed and
3192 ;; now `comint-redirect-filter' gets 3 args. This 3244 ;; now `comint-redirect-filter' gets 3 args. This
3193 ;; checks which version of `comint-redirect-filter' is 3245 ;; checks which version of `comint-redirect-filter' is
@@ -3200,22 +3252,22 @@ completion."
3200 #'comint-redirect-filter original-filter-fn)) 3252 #'comint-redirect-filter original-filter-fn))
3201 (set-process-filter process #'comint-redirect-filter)) 3253 (set-process-filter process #'comint-redirect-filter))
3202 (process-send-string process input-to-send) 3254 (process-send-string process input-to-send)
3203 (accept-process-output 3255 ;; Grab output until our dummy completion used as
3204 process 3256 ;; output end marker is found. Output is accepted
3205 python-shell-completion-native-output-timeout) 3257 ;; *very* quickly to keep the shell super-responsive.
3206 ;; XXX: can't use `python-shell-accept-process-output' 3258 (while (and (not (re-search-backward "~~~~__dummy_completion__" nil t))
3207 ;; here because there are no guarantees on how output 3259 (< (- current-time (float-time))
3208 ;; ends. The workaround here is to call 3260 python-shell-completion-native-output-timeout))
3209 ;; `accept-process-output' until we don't find anything 3261 (accept-process-output process 0.01))
3210 ;; else to accept.
3211 (while (accept-process-output
3212 process
3213 python-shell-completion-native-output-timeout))
3214 (cl-remove-duplicates 3262 (cl-remove-duplicates
3215 (split-string 3263 (cl-remove-if
3216 (buffer-substring-no-properties 3264 (lambda (c)
3217 (point-min) (point-max)) 3265 (string-match "__dummy_completion__" c))
3218 separators t)))) 3266 (split-string
3267 (buffer-substring-no-properties
3268 (point-min) (point-max))
3269 separators t))
3270 :test #'string=)))
3219 (set-process-filter process original-filter-fn)))))) 3271 (set-process-filter process original-filter-fn))))))
3220 3272
3221(defun python-shell-completion-get-completions (process import input) 3273(defun python-shell-completion-get-completions (process import input)