diff options
| author | Liu Hui | 2024-01-18 12:00:00 +0800 |
|---|---|---|
| committer | Eli Zaretskii | 2024-02-08 14:09:42 +0200 |
| commit | 0b9c7148fd681c8ad63fd0eb3895db44403e9f8c (patch) | |
| tree | d454370049b289722ba06e2777e6006fcf762917 /lisp/progmodes/python.el | |
| parent | ebf4ef2022a5f0a69cdd881eb41104e7b59d698e (diff) | |
| download | emacs-0b9c7148fd681c8ad63fd0eb3895db44403e9f8c.tar.gz emacs-0b9c7148fd681c8ad63fd0eb3895db44403e9f8c.zip | |
Respect the delimiter of completer in Python shell completion
* lisp/progmodes/python.el: (python-shell-completion-setup-code): Fix
the completion code of IPython. Change the return value to JSON string
and ...
(python-shell-completion-get-completions): ... simplify parsing.
(inferior-python-mode): Update docstring.
(python-shell-readline-completer-delims): New variable indicating the
word delimiters of readline completer.
(python-shell-completion-native-setup): Set the completer delimiter.
(python-shell-completion-native-get-completions): Convert output string
to completions properly.
(python-shell--get-multiline-input)
(python-shell--extra-completion-context)
(python-shell-completion-extra-context): New functions.
(python-shell-completion-at-point): Send text beginning from the line
start if the completion backend does not need word splitting. Remove
the detection of import statement because it is not needed anymore.
Create proper completion table based on completions returned from
different backends.
* test/lisp/progmodes/python-tests.el (python-tests--completion-module)
(python-tests--completion-parameters)
(python-tests--completion-extra-context): New helper functions.
(python-shell-completion-at-point-jedi-completer)
(python-shell-completion-at-point-ipython): New tests. (bug#68559)
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 220 |
1 files changed, 172 insertions, 48 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 9d840efb9da..b1654b6a5aa 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | ;; Author: Fabián E. Gallina <fgallina@gnu.org> | 5 | ;; Author: Fabián E. Gallina <fgallina@gnu.org> |
| 6 | ;; URL: https://github.com/fgallina/python.el | 6 | ;; URL: https://github.com/fgallina/python.el |
| 7 | ;; Version: 0.28 | 7 | ;; Version: 0.28 |
| 8 | ;; Package-Requires: ((emacs "24.4") (compat "28.1.2.1") (seq "2.23")) | 8 | ;; Package-Requires: ((emacs "24.4") (compat "29.1.1.0") (seq "2.23")) |
| 9 | ;; Maintainer: emacs-devel@gnu.org | 9 | ;; Maintainer: emacs-devel@gnu.org |
| 10 | ;; Created: Jul 2010 | 10 | ;; Created: Jul 2010 |
| 11 | ;; Keywords: languages | 11 | ;; Keywords: languages |
| @@ -128,9 +128,9 @@ | |||
| 128 | ;; receiving escape sequences (with some limitations, i.e. completion | 128 | ;; receiving escape sequences (with some limitations, i.e. completion |
| 129 | ;; in blocks does not work). The code executed for the "fallback" | 129 | ;; in blocks does not work). The code executed for the "fallback" |
| 130 | ;; completion can be found in `python-shell-completion-setup-code' and | 130 | ;; completion can be found in `python-shell-completion-setup-code' and |
| 131 | ;; `python-shell-completion-string-code' variables. Their default | 131 | ;; `python-shell-completion-get-completions'. Their default values |
| 132 | ;; values enable completion for both CPython and IPython, and probably | 132 | ;; enable completion for both CPython and IPython, and probably any |
| 133 | ;; any readline based shell (it's known to work with PyPy). If your | 133 | ;; readline based shell (it's known to work with PyPy). If your |
| 134 | ;; Python installation lacks readline (like CPython for Windows), | 134 | ;; Python installation lacks readline (like CPython for Windows), |
| 135 | ;; installing pyreadline (URL `https://ipython.org/pyreadline.html') | 135 | ;; installing pyreadline (URL `https://ipython.org/pyreadline.html') |
| 136 | ;; should suffice. To troubleshoot why you are not getting any | 136 | ;; should suffice. To troubleshoot why you are not getting any |
| @@ -141,6 +141,12 @@ | |||
| 141 | ;; If you see an error, then you need to either install pyreadline or | 141 | ;; If you see an error, then you need to either install pyreadline or |
| 142 | ;; setup custom code that avoids that dependency. | 142 | ;; setup custom code that avoids that dependency. |
| 143 | 143 | ||
| 144 | ;; By default, the "native" completion uses the built-in rlcompleter. | ||
| 145 | ;; To use other readline completer (e.g. Jedi) or a custom one, you just | ||
| 146 | ;; need to set it in the PYTHONSTARTUP file. You can set an | ||
| 147 | ;; Emacs-specific completer by testing the environment variable | ||
| 148 | ;; INSIDE_EMACS. | ||
| 149 | |||
| 144 | ;; Shell virtualenv support: The shell also contains support for | 150 | ;; Shell virtualenv support: The shell also contains support for |
| 145 | ;; virtualenvs and other special environment modifications thanks to | 151 | ;; virtualenvs and other special environment modifications thanks to |
| 146 | ;; `python-shell-process-environment' and `python-shell-exec-path'. | 152 | ;; `python-shell-process-environment' and `python-shell-exec-path'. |
| @@ -3604,7 +3610,6 @@ interpreter is run. Variables | |||
| 3604 | `python-shell-prompt-block-regexp', | 3610 | `python-shell-prompt-block-regexp', |
| 3605 | `python-shell-font-lock-enable', | 3611 | `python-shell-font-lock-enable', |
| 3606 | `python-shell-completion-setup-code', | 3612 | `python-shell-completion-setup-code', |
| 3607 | `python-shell-completion-string-code', | ||
| 3608 | `python-eldoc-setup-code', | 3613 | `python-eldoc-setup-code', |
| 3609 | `python-ffap-setup-code' can | 3614 | `python-ffap-setup-code' can |
| 3610 | customize this mode for different Python interpreters. | 3615 | customize this mode for different Python interpreters. |
| @@ -4244,8 +4249,9 @@ def __PYTHON_EL_get_completions(text): | |||
| 4244 | completions = [] | 4249 | completions = [] |
| 4245 | completer = None | 4250 | completer = None |
| 4246 | 4251 | ||
| 4252 | import json | ||
| 4247 | try: | 4253 | try: |
| 4248 | import readline | 4254 | import readline, re |
| 4249 | 4255 | ||
| 4250 | try: | 4256 | try: |
| 4251 | import __builtin__ | 4257 | import __builtin__ |
| @@ -4256,16 +4262,29 @@ def __PYTHON_EL_get_completions(text): | |||
| 4256 | 4262 | ||
| 4257 | is_ipython = ('__IPYTHON__' in builtins or | 4263 | is_ipython = ('__IPYTHON__' in builtins or |
| 4258 | '__IPYTHON__active' in builtins) | 4264 | '__IPYTHON__active' in builtins) |
| 4259 | splits = text.split() | 4265 | |
| 4260 | is_module = splits and splits[0] in ('from', 'import') | 4266 | if is_ipython and 'get_ipython' in builtins: |
| 4261 | 4267 | def filter_c(prefix, c): | |
| 4262 | if is_ipython and is_module: | 4268 | if re.match('_+(i?[0-9]+)?$', c): |
| 4263 | from IPython.core.completerlib import module_completion | 4269 | return False |
| 4264 | completions = module_completion(text.strip()) | 4270 | elif c[0] == '%' and not re.match('[%a-zA-Z]+$', prefix): |
| 4265 | elif is_ipython and '__IP' in builtins: | 4271 | return False |
| 4266 | completions = __IP.complete(text) | 4272 | return True |
| 4267 | elif is_ipython and 'get_ipython' in builtins: | 4273 | |
| 4268 | completions = get_ipython().Completer.all_completions(text) | 4274 | import IPython |
| 4275 | try: | ||
| 4276 | if IPython.version_info[0] >= 6: | ||
| 4277 | from IPython.core.completer import provisionalcompleter | ||
| 4278 | with provisionalcompleter(): | ||
| 4279 | completions = [ | ||
| 4280 | [c.text, c.start, c.end, c.type or '?', c.signature or ''] | ||
| 4281 | for c in get_ipython().Completer.completions(text, len(text)) | ||
| 4282 | if filter_c(text, c.text)] | ||
| 4283 | else: | ||
| 4284 | part, matches = get_ipython().Completer.complete(line_buffer=text) | ||
| 4285 | completions = [text + m[len(part):] for m in matches if filter_c(text, m)] | ||
| 4286 | except: | ||
| 4287 | pass | ||
| 4269 | else: | 4288 | else: |
| 4270 | # Try to reuse current completer. | 4289 | # Try to reuse current completer. |
| 4271 | completer = readline.get_completer() | 4290 | completer = readline.get_completer() |
| @@ -4288,7 +4307,7 @@ def __PYTHON_EL_get_completions(text): | |||
| 4288 | finally: | 4307 | finally: |
| 4289 | if getattr(completer, 'PYTHON_EL_WRAPPED', False): | 4308 | if getattr(completer, 'PYTHON_EL_WRAPPED', False): |
| 4290 | completer.print_mode = True | 4309 | completer.print_mode = True |
| 4291 | return completions" | 4310 | return json.dumps(completions)" |
| 4292 | "Code used to setup completion in inferior Python processes." | 4311 | "Code used to setup completion in inferior Python processes." |
| 4293 | :type 'string) | 4312 | :type 'string) |
| 4294 | 4313 | ||
| @@ -4329,6 +4348,10 @@ When a match is found, native completion is disabled." | |||
| 4329 | :version "25.1" | 4348 | :version "25.1" |
| 4330 | :type 'float) | 4349 | :type 'float) |
| 4331 | 4350 | ||
| 4351 | (defvar python-shell-readline-completer-delims nil | ||
| 4352 | "Word delimiters used by the readline completer. | ||
| 4353 | It is automatically set by Python shell.") | ||
| 4354 | |||
| 4332 | (defvar python-shell-completion-native-redirect-buffer | 4355 | (defvar python-shell-completion-native-redirect-buffer |
| 4333 | " *Python completions redirect*" | 4356 | " *Python completions redirect*" |
| 4334 | "Buffer to be used to redirect output of readline commands.") | 4357 | "Buffer to be used to redirect output of readline commands.") |
| @@ -4467,6 +4490,10 @@ def __PYTHON_EL_native_completion_setup(): | |||
| 4467 | __PYTHON_EL_native_completion_setup()" process))) | 4490 | __PYTHON_EL_native_completion_setup()" process))) |
| 4468 | (when (string-match-p "python\\.el: native completion setup loaded" | 4491 | (when (string-match-p "python\\.el: native completion setup loaded" |
| 4469 | output) | 4492 | output) |
| 4493 | (setq-local python-shell-readline-completer-delims | ||
| 4494 | (string-trim-right | ||
| 4495 | (python-shell-send-string-no-output | ||
| 4496 | "import readline; print(readline.get_completer_delims())"))) | ||
| 4470 | (python-shell-completion-native-try)))) | 4497 | (python-shell-completion-native-try)))) |
| 4471 | 4498 | ||
| 4472 | (defun python-shell-completion-native-turn-off (&optional msg) | 4499 | (defun python-shell-completion-native-turn-off (&optional msg) |
| @@ -4534,6 +4561,8 @@ With argument MSG show activation/deactivation message." | |||
| 4534 | (let* ((original-filter-fn (process-filter process)) | 4561 | (let* ((original-filter-fn (process-filter process)) |
| 4535 | (redirect-buffer (get-buffer-create | 4562 | (redirect-buffer (get-buffer-create |
| 4536 | python-shell-completion-native-redirect-buffer)) | 4563 | python-shell-completion-native-redirect-buffer)) |
| 4564 | (sep (if (string= python-shell-readline-completer-delims "") | ||
| 4565 | "[\n\r]+" "[ \f\t\n\r\v()]+")) | ||
| 4537 | (trigger "\t") | 4566 | (trigger "\t") |
| 4538 | (new-input (concat input trigger)) | 4567 | (new-input (concat input trigger)) |
| 4539 | (input-length | 4568 | (input-length |
| @@ -4576,28 +4605,80 @@ With argument MSG show activation/deactivation message." | |||
| 4576 | process python-shell-completion-native-output-timeout | 4605 | process python-shell-completion-native-output-timeout |
| 4577 | comint-redirect-finished-regexp) | 4606 | comint-redirect-finished-regexp) |
| 4578 | (re-search-backward "0__dummy_completion__" nil t) | 4607 | (re-search-backward "0__dummy_completion__" nil t) |
| 4579 | (cl-remove-duplicates | 4608 | (let ((str (buffer-substring-no-properties |
| 4580 | (split-string | 4609 | (line-beginning-position) (point-min)))) |
| 4581 | (buffer-substring-no-properties | 4610 | ;; The readline completer is allowed to return a list |
| 4582 | (line-beginning-position) (point-min)) | 4611 | ;; of (text start end type signature) as a JSON |
| 4583 | "[ \f\t\n\r\v()]+" t) | 4612 | ;; string. See the return value for IPython in |
| 4584 | :test #'string=)))) | 4613 | ;; `python-shell-completion-setup-code'. |
| 4614 | (if (string= "[" (substring str 0 1)) | ||
| 4615 | (condition-case nil | ||
| 4616 | (python--parse-json-array str) | ||
| 4617 | (t (cl-remove-duplicates (split-string str sep t) | ||
| 4618 | :test #'string=))) | ||
| 4619 | (cl-remove-duplicates (split-string str sep t) | ||
| 4620 | :test #'string=)))))) | ||
| 4585 | (set-process-filter process original-filter-fn))))) | 4621 | (set-process-filter process original-filter-fn))))) |
| 4586 | 4622 | ||
| 4587 | (defun python-shell-completion-get-completions (process input) | 4623 | (defun python-shell-completion-get-completions (process input) |
| 4588 | "Get completions of INPUT using PROCESS." | 4624 | "Get completions of INPUT using PROCESS." |
| 4589 | (with-current-buffer (process-buffer process) | 4625 | (with-current-buffer (process-buffer process) |
| 4590 | (let ((completions | 4626 | (python--parse-json-array |
| 4591 | (python-util-strip-string | 4627 | (python-shell-send-string-no-output |
| 4592 | (python-shell-send-string-no-output | 4628 | (format "%s\nprint(__PYTHON_EL_get_completions(%s))" |
| 4593 | (format | ||
| 4594 | "%s\nprint(';'.join(__PYTHON_EL_get_completions(%s)))" | ||
| 4595 | python-shell-completion-setup-code | 4629 | python-shell-completion-setup-code |
| 4596 | (python-shell--encode-string input)) | 4630 | (python-shell--encode-string input)) |
| 4597 | process)))) | 4631 | process)))) |
| 4598 | (when (> (length completions) 2) | 4632 | |
| 4599 | (split-string completions | 4633 | (defun python-shell--get-multiline-input () |
| 4600 | "^'\\|^\"\\|;\\|'$\\|\"$" t))))) | 4634 | "Return lines at a multi-line input in Python shell." |
| 4635 | (save-excursion | ||
| 4636 | (let ((p (point)) lines) | ||
| 4637 | (when (progn | ||
| 4638 | (beginning-of-line) | ||
| 4639 | (looking-back python-shell-prompt-block-regexp (pos-bol))) | ||
| 4640 | (push (buffer-substring-no-properties (point) p) lines) | ||
| 4641 | (while (progn (comint-previous-prompt 1) | ||
| 4642 | (looking-back python-shell-prompt-block-regexp (pos-bol))) | ||
| 4643 | (push (buffer-substring-no-properties (point) (pos-eol)) lines)) | ||
| 4644 | (push (buffer-substring-no-properties (point) (pos-eol)) lines)) | ||
| 4645 | lines))) | ||
| 4646 | |||
| 4647 | (defun python-shell--extra-completion-context () | ||
| 4648 | "Get extra completion context of current input in Python shell." | ||
| 4649 | (let ((lines (python-shell--get-multiline-input)) | ||
| 4650 | (python-indent-guess-indent-offset nil)) | ||
| 4651 | (when (not (zerop (length lines))) | ||
| 4652 | (with-temp-buffer | ||
| 4653 | (delay-mode-hooks | ||
| 4654 | (insert (string-join lines "\n")) | ||
| 4655 | (python-mode) | ||
| 4656 | (python-shell-completion-extra-context)))))) | ||
| 4657 | |||
| 4658 | (defun python-shell-completion-extra-context (&optional pos) | ||
| 4659 | "Get extra completion context at position POS in Python buffer. | ||
| 4660 | If optional argument POS is nil, use current position. | ||
| 4661 | |||
| 4662 | Readline completers could use current line as the completion | ||
| 4663 | context, which may be insufficient. In this function, extra | ||
| 4664 | context (e.g. multi-line function call) is found and reformatted | ||
| 4665 | as one line, which is required by native completion." | ||
| 4666 | (let (bound p) | ||
| 4667 | (save-excursion | ||
| 4668 | (and pos (goto-char pos)) | ||
| 4669 | (setq bound (pos-bol)) | ||
| 4670 | (python-nav-up-list -1) | ||
| 4671 | (when (and (< (point) bound) | ||
| 4672 | (or | ||
| 4673 | (looking-back | ||
| 4674 | (python-rx (group (+ (or "." symbol-name)))) (pos-bol) t) | ||
| 4675 | (progn | ||
| 4676 | (forward-line 0) | ||
| 4677 | (looking-at "^[ \t]*\\(from \\)")))) | ||
| 4678 | (setq p (match-beginning 1)))) | ||
| 4679 | (when p | ||
| 4680 | (replace-regexp-in-string | ||
| 4681 | "\n[ \t]*" "" (buffer-substring-no-properties p (1- bound)))))) | ||
| 4601 | 4682 | ||
| 4602 | (defvar-local python-shell--capf-cache nil | 4683 | (defvar-local python-shell--capf-cache nil |
| 4603 | "Variable to store cached completions and invalidation keys.") | 4684 | "Variable to store cached completions and invalidation keys.") |
| @@ -4612,21 +4693,26 @@ using that one instead of current buffer's process." | |||
| 4612 | ;; Working on a shell buffer: use prompt end. | 4693 | ;; Working on a shell buffer: use prompt end. |
| 4613 | (cdr (python-util-comint-last-prompt)) | 4694 | (cdr (python-util-comint-last-prompt)) |
| 4614 | (line-beginning-position))) | 4695 | (line-beginning-position))) |
| 4615 | (import-statement | 4696 | (no-delims |
| 4616 | (when (string-match-p | 4697 | (and (not (if is-shell-buffer |
| 4617 | (rx (* space) word-start (or "from" "import") word-end space) | 4698 | (eq 'font-lock-comment-face |
| 4618 | (buffer-substring-no-properties line-start (point))) | 4699 | (get-text-property (1- (point)) 'face)) |
| 4619 | (buffer-substring-no-properties line-start (point)))) | 4700 | (python-syntax-context 'comment))) |
| 4701 | (with-current-buffer (process-buffer process) | ||
| 4702 | (if python-shell-completion-native-enable | ||
| 4703 | (string= python-shell-readline-completer-delims "") | ||
| 4704 | (string-match-p "ipython[23]?\\'" python-shell-interpreter))))) | ||
| 4620 | (start | 4705 | (start |
| 4621 | (if (< (point) line-start) | 4706 | (if (< (point) line-start) |
| 4622 | (point) | 4707 | (point) |
| 4623 | (save-excursion | 4708 | (save-excursion |
| 4624 | (if (not (re-search-backward | 4709 | (if (or no-delims |
| 4625 | (python-rx | 4710 | (not (re-search-backward |
| 4626 | (or whitespace open-paren close-paren | 4711 | (python-rx |
| 4627 | string-delimiter simple-operator)) | 4712 | (or whitespace open-paren close-paren |
| 4628 | line-start | 4713 | string-delimiter simple-operator)) |
| 4629 | t 1)) | 4714 | line-start |
| 4715 | t 1))) | ||
| 4630 | line-start | 4716 | line-start |
| 4631 | (forward-char (length (match-string-no-properties 0))) | 4717 | (forward-char (length (match-string-no-properties 0))) |
| 4632 | (point))))) | 4718 | (point))))) |
| @@ -4666,18 +4752,56 @@ using that one instead of current buffer's process." | |||
| 4666 | (t #'python-shell-completion-native-get-completions)))) | 4752 | (t #'python-shell-completion-native-get-completions)))) |
| 4667 | (prev-prompt (car python-shell--capf-cache)) | 4753 | (prev-prompt (car python-shell--capf-cache)) |
| 4668 | (re (or (cadr python-shell--capf-cache) regexp-unmatchable)) | 4754 | (re (or (cadr python-shell--capf-cache) regexp-unmatchable)) |
| 4669 | (prefix (buffer-substring-no-properties start end))) | 4755 | (prefix (buffer-substring-no-properties start end)) |
| 4756 | (prefix-offset 0) | ||
| 4757 | (extra-context (when no-delims | ||
| 4758 | (if is-shell-buffer | ||
| 4759 | (python-shell--extra-completion-context) | ||
| 4760 | (python-shell-completion-extra-context)))) | ||
| 4761 | (extra-offset (length extra-context))) | ||
| 4762 | (unless (zerop extra-offset) | ||
| 4763 | (setq prefix (concat extra-context prefix))) | ||
| 4670 | ;; To invalidate the cache, we check if the prompt position or the | 4764 | ;; To invalidate the cache, we check if the prompt position or the |
| 4671 | ;; completion prefix changed. | 4765 | ;; completion prefix changed. |
| 4672 | (unless (and (equal prev-prompt (car prompt-boundaries)) | 4766 | (unless (and (equal prev-prompt (car prompt-boundaries)) |
| 4673 | (string-match re prefix)) | 4767 | (string-match re prefix) |
| 4768 | (setq prefix-offset (- (length prefix) (match-end 1)))) | ||
| 4674 | (setq python-shell--capf-cache | 4769 | (setq python-shell--capf-cache |
| 4675 | `(,(car prompt-boundaries) | 4770 | `(,(car prompt-boundaries) |
| 4676 | ,(if (string-empty-p prefix) | 4771 | ,(if (string-empty-p prefix) |
| 4677 | regexp-unmatchable | 4772 | regexp-unmatchable |
| 4678 | (concat "\\`" (regexp-quote prefix) "\\(?:\\sw\\|\\s_\\)*\\'")) | 4773 | (concat "\\`\\(" (regexp-quote prefix) "\\)\\(?:\\sw\\|\\s_\\)*\\'")) |
| 4679 | ,@(funcall completion-fn process (or import-statement prefix))))) | 4774 | ,@(funcall completion-fn process prefix)))) |
| 4680 | (list start end (cddr python-shell--capf-cache)))) | 4775 | (let ((cands (cddr python-shell--capf-cache))) |
| 4776 | (cond | ||
| 4777 | ((stringp (car cands)) | ||
| 4778 | (if no-delims | ||
| 4779 | ;; Reduce completion candidates due to long prefix. | ||
| 4780 | (if-let ((Lp (length prefix)) | ||
| 4781 | ((string-match "\\(\\sw\\|\\s_\\)+\\'" prefix)) | ||
| 4782 | (L (match-beginning 0))) | ||
| 4783 | ;; If extra-offset is not zero: | ||
| 4784 | ;; start end | ||
| 4785 | ;; o------------------o---------o-------o | ||
| 4786 | ;; |<- extra-offset ->| | ||
| 4787 | ;; |<----------- L ------------>| | ||
| 4788 | ;; new-start | ||
| 4789 | (list (+ start L (- extra-offset)) end | ||
| 4790 | (mapcar (lambda (s) (substring s L)) cands)) | ||
| 4791 | (list end end (mapcar (lambda (s) (substring s Lp)) cands))) | ||
| 4792 | (list start end cands))) | ||
| 4793 | ;; python-shell-completion(-native)-get-completions may produce a | ||
| 4794 | ;; list of (text start end type signature) for completion. | ||
| 4795 | ((consp (car cands)) | ||
| 4796 | (list (+ start (nth 1 (car cands)) (- extra-offset)) | ||
| 4797 | ;; Candidates may be cached, so the end position should | ||
| 4798 | ;; be adjusted according to current completion prefix. | ||
| 4799 | (+ start (nth 2 (car cands)) (- extra-offset) prefix-offset) | ||
| 4800 | cands | ||
| 4801 | :annotation-function | ||
| 4802 | (lambda (c) (concat " " (nth 3 (assoc c cands)))) | ||
| 4803 | :company-docsig | ||
| 4804 | (lambda (c) (nth 4 (assoc c cands))))))))) | ||
| 4681 | 4805 | ||
| 4682 | (define-obsolete-function-alias | 4806 | (define-obsolete-function-alias |
| 4683 | 'python-shell-completion-complete-at-point | 4807 | 'python-shell-completion-complete-at-point |