diff options
| author | Fabián Ezequiel Gallina | 2015-08-23 14:54:56 -0300 |
|---|---|---|
| committer | Fabián Ezequiel Gallina | 2015-08-23 14:55:06 -0300 |
| commit | a92066b80e4245f5093fa1ed481f0e3eb377f504 (patch) | |
| tree | a03a4c055ce3ea33bc9b4518511d357c3d5c8e7a /lisp/progmodes/python.el | |
| parent | e7be9861962a5a399047e86a254c2534d5d4d146 (diff) | |
| download | emacs-a92066b80e4245f5093fa1ed481f0e3eb377f504.tar.gz emacs-a92066b80e4245f5093fa1ed481f0e3eb377f504.zip | |
python.el: Fix completion for pdb interactions
* lisp/progmodes/python.el (python-shell-completion-setup-code):
Simplify. Toggle print_mode for native wrapped completer.
(python-shell-completion-native-setup): Ensure process buffer.
Add print_mode attribute to completer wrapper to toggle returning
or printing candidates.
(python-shell-completion-native-get-completions): Cleanup.
(python-shell-completion-get-completions): Cleanup.
(python-shell-completion-at-point): Perform prompt checks. Force
fallback completion in pdb interactions.
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 266 |
1 files changed, 139 insertions, 127 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 426b465f745..93ef7fe9db6 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -3138,50 +3138,56 @@ This function takes the list of setup code to send from the | |||
| 3138 | ;;; Shell completion | 3138 | ;;; Shell completion |
| 3139 | 3139 | ||
| 3140 | (defcustom python-shell-completion-setup-code | 3140 | (defcustom python-shell-completion-setup-code |
| 3141 | "try: | 3141 | " |
| 3142 | import readline | 3142 | def __PYTHON_EL_get_completions(text): |
| 3143 | except: | 3143 | completions = [] |
| 3144 | def __PYTHON_EL_get_completions(text): | 3144 | completer = None |
| 3145 | return [] | 3145 | |
| 3146 | else: | 3146 | try: |
| 3147 | def __PYTHON_EL_get_completions(text): | 3147 | import readline |
| 3148 | |||
| 3148 | try: | 3149 | try: |
| 3149 | import __builtin__ | 3150 | import __builtin__ |
| 3150 | except ImportError: | 3151 | except ImportError: |
| 3151 | # Python 3 | 3152 | # Python 3 |
| 3152 | import builtins as __builtin__ | 3153 | import builtins as __builtin__ |
| 3153 | builtins = dir(__builtin__) | 3154 | builtins = dir(__builtin__) |
| 3154 | completions = [] | 3155 | |
| 3155 | is_ipython = ('__IPYTHON__' in builtins or | 3156 | is_ipython = ('__IPYTHON__' in builtins or |
| 3156 | '__IPYTHON__active' in builtins) | 3157 | '__IPYTHON__active' in builtins) |
| 3157 | splits = text.split() | 3158 | splits = text.split() |
| 3158 | is_module = splits and splits[0] in ('from', 'import') | 3159 | is_module = splits and splits[0] in ('from', 'import') |
| 3159 | try: | 3160 | |
| 3160 | if is_ipython and is_module: | 3161 | if is_ipython and is_module: |
| 3161 | from IPython.core.completerlib import module_completion | 3162 | from IPython.core.completerlib import module_completion |
| 3162 | completions = module_completion(text.strip()) | 3163 | completions = module_completion(text.strip()) |
| 3163 | elif is_ipython and '__IP' in builtins: | 3164 | elif is_ipython and '__IP' in builtins: |
| 3164 | completions = __IP.complete(text) | 3165 | completions = __IP.complete(text) |
| 3165 | elif is_ipython and 'get_ipython' in builtins: | 3166 | elif is_ipython and 'get_ipython' in builtins: |
| 3166 | completions = get_ipython().Completer.all_completions(text) | 3167 | completions = get_ipython().Completer.all_completions(text) |
| 3167 | else: | 3168 | else: |
| 3168 | # Try to reuse current completer. | 3169 | # Try to reuse current completer. |
| 3170 | completer = readline.get_completer() | ||
| 3171 | if not completer: | ||
| 3172 | # importing rlcompleter sets the completer, use it as a | ||
| 3173 | # last resort to avoid breaking customizations. | ||
| 3174 | import rlcompleter | ||
| 3169 | completer = readline.get_completer() | 3175 | completer = readline.get_completer() |
| 3170 | if not completer: | 3176 | if getattr(completer, 'PYTHON_EL_WRAPPED', False): |
| 3171 | # importing rlcompleter sets the completer, use it as a | 3177 | completer.print_mode = False |
| 3172 | # last resort to avoid breaking customizations. | 3178 | i = 0 |
| 3173 | import rlcompleter | 3179 | while True: |
| 3174 | completer = readline.get_completer() | 3180 | completion = completer(text, i) |
| 3175 | i = 0 | 3181 | if not completion: |
| 3176 | while True: | 3182 | break |
| 3177 | completion = completer(text, i) | 3183 | i += 1 |
| 3178 | if not completion: | 3184 | completions.append(completion) |
| 3179 | break | 3185 | except: |
| 3180 | i += 1 | 3186 | pass |
| 3181 | completions.append(completion) | 3187 | finally: |
| 3182 | except: | 3188 | if getattr(completer, 'PYTHON_EL_WRAPPED', False): |
| 3183 | pass | 3189 | completer.print_mode = True |
| 3184 | return completions" | 3190 | return completions" |
| 3185 | "Code used to setup completion in inferior Python processes." | 3191 | "Code used to setup completion in inferior Python processes." |
| 3186 | :type 'string | 3192 | :type 'string |
| 3187 | :group 'python) | 3193 | :group 'python) |
| @@ -3243,12 +3249,13 @@ When a match is found, native completion is disabled." | |||
| 3243 | python-shell-completion-native-try-output-timeout)) | 3249 | python-shell-completion-native-try-output-timeout)) |
| 3244 | (python-shell-completion-native-get-completions | 3250 | (python-shell-completion-native-get-completions |
| 3245 | (get-buffer-process (current-buffer)) | 3251 | (get-buffer-process (current-buffer)) |
| 3246 | nil "int"))) | 3252 | nil ""))) |
| 3247 | 3253 | ||
| 3248 | (defun python-shell-completion-native-setup () | 3254 | (defun python-shell-completion-native-setup () |
| 3249 | "Try to setup native completion, return non-nil on success." | 3255 | "Try to setup native completion, return non-nil on success." |
| 3250 | (let ((process (python-shell-get-process))) | 3256 | (let ((process (python-shell-get-process))) |
| 3251 | (python-shell-send-string " | 3257 | (with-current-buffer (process-buffer process) |
| 3258 | (python-shell-send-string " | ||
| 3252 | def __PYTHON_EL_native_completion_setup(): | 3259 | def __PYTHON_EL_native_completion_setup(): |
| 3253 | try: | 3260 | try: |
| 3254 | import readline | 3261 | import readline |
| @@ -3283,6 +3290,7 @@ def __PYTHON_EL_native_completion_setup(): | |||
| 3283 | def __init__(self, completer): | 3290 | def __init__(self, completer): |
| 3284 | self.completer = completer | 3291 | self.completer = completer |
| 3285 | self.last_completion = None | 3292 | self.last_completion = None |
| 3293 | self.print_mode = True | ||
| 3286 | 3294 | ||
| 3287 | def __call__(self, text, state): | 3295 | def __call__(self, text, state): |
| 3288 | if state == 0: | 3296 | if state == 0: |
| @@ -3312,8 +3320,11 @@ def __PYTHON_EL_native_completion_setup(): | |||
| 3312 | # For every non-dummy completion, return a repeated dummy | 3320 | # For every non-dummy completion, return a repeated dummy |
| 3313 | # one and print the real candidate so it can be retrieved | 3321 | # one and print the real candidate so it can be retrieved |
| 3314 | # by comint output filters. | 3322 | # by comint output filters. |
| 3315 | print (completion) | 3323 | if self.print_mode: |
| 3316 | return '0__dummy_completion__' | 3324 | print (completion) |
| 3325 | return '0__dummy_completion__' | ||
| 3326 | else: | ||
| 3327 | return completion | ||
| 3317 | else: | 3328 | else: |
| 3318 | return completion | 3329 | return completion |
| 3319 | 3330 | ||
| @@ -3346,17 +3357,18 @@ def __PYTHON_EL_native_completion_setup(): | |||
| 3346 | # Require just one tab to send output. | 3357 | # Require just one tab to send output. |
| 3347 | readline.parse_and_bind('set show-all-if-ambiguous on') | 3358 | readline.parse_and_bind('set show-all-if-ambiguous on') |
| 3348 | 3359 | ||
| 3349 | print ('python.el: readline is available') | 3360 | print ('python.el: native completion setup loaded') |
| 3350 | except: | 3361 | except: |
| 3351 | print ('python.el: readline not available') | 3362 | print ('python.el: native completion setup failed') |
| 3352 | 3363 | ||
| 3353 | __PYTHON_EL_native_completion_setup()" | 3364 | __PYTHON_EL_native_completion_setup()" process) |
| 3354 | process) | 3365 | (when (and |
| 3355 | (python-shell-accept-process-output process) | 3366 | (python-shell-accept-process-output |
| 3356 | (when (save-excursion | 3367 | process python-shell-completion-native-try-output-timeout) |
| 3357 | (re-search-backward | 3368 | (save-excursion |
| 3358 | (regexp-quote "python.el: readline is available") nil t 1)) | 3369 | (re-search-backward |
| 3359 | (python-shell-completion-native-try)))) | 3370 | (regexp-quote "python.el: native completion setup loaded") nil t 1))) |
| 3371 | (python-shell-completion-native-try))))) | ||
| 3360 | 3372 | ||
| 3361 | (defun python-shell-completion-native-turn-off (&optional msg) | 3373 | (defun python-shell-completion-native-turn-off (&optional msg) |
| 3362 | "Turn off shell native completions. | 3374 | "Turn off shell native completions. |
| @@ -3421,91 +3433,75 @@ With argument MSG show activation/deactivation message." | |||
| 3421 | When IMPORT is non-nil takes precedence over INPUT for | 3433 | When IMPORT is non-nil takes precedence over INPUT for |
| 3422 | completion." | 3434 | completion." |
| 3423 | (with-current-buffer (process-buffer process) | 3435 | (with-current-buffer (process-buffer process) |
| 3424 | (when (and python-shell-completion-native-enable | 3436 | (let* ((input (or import input)) |
| 3425 | (python-util-comint-last-prompt) | 3437 | (original-filter-fn (process-filter process)) |
| 3426 | (>= (point) (cdr (python-util-comint-last-prompt)))) | 3438 | (redirect-buffer (get-buffer-create |
| 3427 | (let* ((input (or import input)) | 3439 | python-shell-completion-native-redirect-buffer)) |
| 3428 | (original-filter-fn (process-filter process)) | 3440 | (trigger "\t") |
| 3429 | (redirect-buffer (get-buffer-create | 3441 | (new-input (concat input trigger)) |
| 3430 | python-shell-completion-native-redirect-buffer)) | 3442 | (input-length |
| 3431 | (trigger "\t") | 3443 | (save-excursion |
| 3432 | (new-input (concat input trigger)) | 3444 | (+ (- (point-max) (comint-bol)) (length new-input)))) |
| 3433 | (input-length | 3445 | (delete-line-command (make-string input-length ?\b)) |
| 3434 | (save-excursion | 3446 | (input-to-send (concat new-input delete-line-command))) |
| 3435 | (+ (- (point-max) (comint-bol)) (length new-input)))) | 3447 | ;; Ensure restoring the process filter, even if the user quits |
| 3436 | (delete-line-command (make-string input-length ?\b)) | 3448 | ;; or there's some other error. |
| 3437 | (input-to-send (concat new-input delete-line-command))) | 3449 | (unwind-protect |
| 3438 | ;; Ensure restoring the process filter, even if the user quits | 3450 | (with-current-buffer redirect-buffer |
| 3439 | ;; or there's some other error. | 3451 | ;; Cleanup the redirect buffer |
| 3440 | (unwind-protect | 3452 | (erase-buffer) |
| 3441 | (with-current-buffer redirect-buffer | 3453 | ;; Mimic `comint-redirect-send-command', unfortunately it |
| 3442 | ;; Cleanup the redirect buffer | 3454 | ;; can't be used here because it expects a newline in the |
| 3443 | (erase-buffer) | 3455 | ;; command and that's exactly what we are trying to avoid. |
| 3444 | ;; Mimic `comint-redirect-send-command', unfortunately it | 3456 | (let ((comint-redirect-echo-input nil) |
| 3445 | ;; can't be used here because it expects a newline in the | 3457 | (comint-redirect-completed nil) |
| 3446 | ;; command and that's exactly what we are trying to avoid. | 3458 | (comint-redirect-perform-sanity-check nil) |
| 3447 | (let ((comint-redirect-echo-input nil) | 3459 | (comint-redirect-insert-matching-regexp t) |
| 3448 | (comint-redirect-completed nil) | 3460 | (comint-redirect-finished-regexp |
| 3449 | (comint-redirect-perform-sanity-check nil) | 3461 | "1__dummy_completion__[[:space:]]*\n") |
| 3450 | (comint-redirect-insert-matching-regexp t) | 3462 | (comint-redirect-output-buffer redirect-buffer)) |
| 3451 | (comint-redirect-finished-regexp | 3463 | ;; Compatibility with Emacs 24.x. Comint changed and |
| 3452 | "1__dummy_completion__[[:space:]]*\n") | 3464 | ;; now `comint-redirect-filter' gets 3 args. This |
| 3453 | (comint-redirect-output-buffer redirect-buffer)) | 3465 | ;; checks which version of `comint-redirect-filter' is |
| 3454 | ;; Compatibility with Emacs 24.x. Comint changed and | 3466 | ;; in use based on its args and uses `apply-partially' |
| 3455 | ;; now `comint-redirect-filter' gets 3 args. This | 3467 | ;; to make it up for the 3 args case. |
| 3456 | ;; checks which version of `comint-redirect-filter' is | 3468 | (if (= (length |
| 3457 | ;; in use based on its args and uses `apply-partially' | 3469 | (help-function-arglist 'comint-redirect-filter)) 3) |
| 3458 | ;; to make it up for the 3 args case. | 3470 | (set-process-filter |
| 3459 | (if (= (length | 3471 | process (apply-partially |
| 3460 | (help-function-arglist 'comint-redirect-filter)) 3) | 3472 | #'comint-redirect-filter original-filter-fn)) |
| 3461 | (set-process-filter | 3473 | (set-process-filter process #'comint-redirect-filter)) |
| 3462 | process (apply-partially | 3474 | (process-send-string process input-to-send) |
| 3463 | #'comint-redirect-filter original-filter-fn)) | 3475 | ;; Grab output until our dummy completion used as |
| 3464 | (set-process-filter process #'comint-redirect-filter)) | 3476 | ;; output end marker is found. |
| 3465 | (process-send-string process input-to-send) | 3477 | (when (python-shell-accept-process-output |
| 3466 | ;; Grab output until our dummy completion used as | 3478 | process python-shell-completion-native-output-timeout |
| 3467 | ;; output end marker is found. | 3479 | comint-redirect-finished-regexp) |
| 3468 | (when (python-shell-accept-process-output | 3480 | (re-search-backward "0__dummy_completion__" nil t) |
| 3469 | process python-shell-completion-native-output-timeout | 3481 | (cl-remove-duplicates |
| 3470 | comint-redirect-finished-regexp) | 3482 | (split-string |
| 3471 | (re-search-backward "0__dummy_completion__" nil t) | 3483 | (buffer-substring-no-properties |
| 3472 | (cl-remove-duplicates | 3484 | (line-beginning-position) (point-min)) |
| 3473 | (split-string | 3485 | "[ \f\t\n\r\v()]+" t) |
| 3474 | (buffer-substring-no-properties | 3486 | :test #'string=)))) |
| 3475 | (line-beginning-position) (point-min)) | 3487 | (set-process-filter process original-filter-fn))))) |
| 3476 | "[ \f\t\n\r\v()]+" t) | ||
| 3477 | :test #'string=)))) | ||
| 3478 | (set-process-filter process original-filter-fn)))))) | ||
| 3479 | 3488 | ||
| 3480 | (defun python-shell-completion-get-completions (process import input) | 3489 | (defun python-shell-completion-get-completions (process import input) |
| 3481 | "Do completion at point using PROCESS for IMPORT or INPUT. | 3490 | "Do completion at point using PROCESS for IMPORT or INPUT. |
| 3482 | When IMPORT is non-nil takes precedence over INPUT for | 3491 | When IMPORT is non-nil takes precedence over INPUT for |
| 3483 | completion." | 3492 | completion." |
| 3493 | (setq input (or import input)) | ||
| 3484 | (with-current-buffer (process-buffer process) | 3494 | (with-current-buffer (process-buffer process) |
| 3485 | (let* ((prompt | 3495 | (let ((completions |
| 3486 | (let ((prompt-boundaries (python-util-comint-last-prompt))) | 3496 | (python-util-strip-string |
| 3487 | (buffer-substring-no-properties | 3497 | (python-shell-send-string-no-output |
| 3488 | (car prompt-boundaries) (cdr prompt-boundaries)))) | 3498 | (format |
| 3489 | (completion-code | ||
| 3490 | ;; Check whether a prompt matches a pdb string, an import | ||
| 3491 | ;; statement or just the standard prompt and use the | ||
| 3492 | ;; correct python-shell-completion-*-code string | ||
| 3493 | (when (string-match python-shell--prompt-calculated-input-regexp prompt) | ||
| 3494 | ;; Since there are no guarantees the user will remain | ||
| 3495 | ;; in the same context where completion code was sent | ||
| 3496 | ;; (e.g. user steps into a function), safeguard | ||
| 3497 | ;; resending completion setup continuously. | ||
| 3498 | (concat python-shell-completion-setup-code | 3499 | (concat python-shell-completion-setup-code |
| 3499 | "\nprint (" python-shell-completion-string-code ")"))) | 3500 | "\nprint (" python-shell-completion-string-code ")") |
| 3500 | (subject (or import input))) | 3501 | input) process)))) |
| 3501 | (when (and completion-code (> (length input) 0)) | 3502 | (when (> (length completions) 2) |
| 3502 | (let ((completions | 3503 | (split-string completions |
| 3503 | (python-util-strip-string | 3504 | "^'\\|^\"\\|;\\|'$\\|\"$" t))))) |
| 3504 | (python-shell-send-string-no-output | ||
| 3505 | (format completion-code subject) process)))) | ||
| 3506 | (when (> (length completions) 2) | ||
| 3507 | (split-string completions | ||
| 3508 | "^'\\|^\"\\|;\\|'$\\|\"$" t))))))) | ||
| 3509 | 3505 | ||
| 3510 | (defun python-shell-completion-at-point (&optional process) | 3506 | (defun python-shell-completion-at-point (&optional process) |
| 3511 | "Function for `completion-at-point-functions' in `inferior-python-mode'. | 3507 | "Function for `completion-at-point-functions' in `inferior-python-mode'. |
| @@ -3532,10 +3528,26 @@ using that one instead of current buffer's process." | |||
| 3532 | (forward-char (length (match-string-no-properties 0))) | 3528 | (forward-char (length (match-string-no-properties 0))) |
| 3533 | (point)))) | 3529 | (point)))) |
| 3534 | (end (point)) | 3530 | (end (point)) |
| 3531 | (prompt-boundaries (python-util-comint-last-prompt)) | ||
| 3532 | (prompt | ||
| 3533 | (with-current-buffer (process-buffer process) | ||
| 3534 | (when prompt-boundaries | ||
| 3535 | (buffer-substring-no-properties | ||
| 3536 | (car prompt-boundaries) (cdr prompt-boundaries))))) | ||
| 3535 | (completion-fn | 3537 | (completion-fn |
| 3536 | (if python-shell-completion-native-enable | 3538 | (with-current-buffer (process-buffer process) |
| 3537 | #'python-shell-completion-native-get-completions | 3539 | (cond ((or (null prompt) |
| 3538 | #'python-shell-completion-get-completions))) | 3540 | (< (point) (cdr prompt-boundaries))) |
| 3541 | #'ignore) | ||
| 3542 | ((or (not python-shell-completion-native-enable) | ||
| 3543 | ;; Even if native completion is enabled, for | ||
| 3544 | ;; pdb interaction always use the fallback | ||
| 3545 | ;; mechanism since the completer is changed. | ||
| 3546 | ;; Also, since pdb interaction is single-line | ||
| 3547 | ;; based, this is enough. | ||
| 3548 | (string-match-p python-shell-prompt-pdb-regexp prompt)) | ||
| 3549 | #'python-shell-completion-get-completions) | ||
| 3550 | (t #'python-shell-completion-native-get-completions))))) | ||
| 3539 | (list start end | 3551 | (list start end |
| 3540 | (completion-table-dynamic | 3552 | (completion-table-dynamic |
| 3541 | (apply-partially | 3553 | (apply-partially |