diff options
| author | Fabián Ezequiel Gallina | 2014-07-27 03:39:17 -0300 |
|---|---|---|
| committer | Fabián Ezequiel Gallina | 2014-07-27 03:39:17 -0300 |
| commit | 4b03be01ceaddfd010f1cacdb49662c34d691187 (patch) | |
| tree | d36979652d92675df273553bdeb0f07966fe5b2e | |
| parent | 9578a71f2e3fea51d56eaed577e5172a8394a0b4 (diff) | |
| download | emacs-4b03be01ceaddfd010f1cacdb49662c34d691187.tar.gz emacs-4b03be01ceaddfd010f1cacdb49662c34d691187.zip | |
Support for packages in Python shell.
* lisp/progmodes/python.el (python-shell--package-depth): New var.
(python-shell-package-enable): New command.
(python-util-list-directories, python-util-list-files)
(python-util-list-packages): New functions.
Fixes: debbugs:13570
| -rw-r--r-- | lisp/ChangeLog | 8 | ||||
| -rw-r--r-- | lisp/progmodes/python.el | 95 |
2 files changed, 101 insertions, 2 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 789ad74e95c..0b9edd3dcf6 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,5 +1,13 @@ | |||
| 1 | 2014-07-27 Fabián Ezequiel Gallina <fgallina@gnu.org> | 1 | 2014-07-27 Fabián Ezequiel Gallina <fgallina@gnu.org> |
| 2 | 2 | ||
| 3 | Support for packages in Python shell. (Bug#13570) | ||
| 4 | * progmodes/python.el (python-shell--package-depth): New var. | ||
| 5 | (python-shell-package-enable): New command. | ||
| 6 | (python-util-list-directories, python-util-list-files) | ||
| 7 | (python-util-list-packages): New functions. | ||
| 8 | |||
| 9 | 2014-07-27 Fabián Ezequiel Gallina <fgallina@gnu.org> | ||
| 10 | |||
| 3 | Faster comint output. (Bug#16875) | 11 | Faster comint output. (Bug#16875) |
| 4 | * progmodes/python.el: | 12 | * progmodes/python.el: |
| 5 | (python-comint-output-filter-function): Make obsolete. | 13 | (python-comint-output-filter-function): Make obsolete. |
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index acb5b40165f..50dc293a955 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -32,8 +32,8 @@ | |||
| 32 | 32 | ||
| 33 | ;; Implements Syntax highlighting, Indentation, Movement, Shell | 33 | ;; Implements Syntax highlighting, Indentation, Movement, Shell |
| 34 | ;; interaction, Shell completion, Shell virtualenv support, Shell | 34 | ;; interaction, Shell completion, Shell virtualenv support, Shell |
| 35 | ;; syntax highlighting, Pdb tracking, Symbol completion, Skeletons, | 35 | ;; package support, Shell syntax highlighting, Pdb tracking, Symbol |
| 36 | ;; FFAP, Code Check, Eldoc, Imenu. | 36 | ;; completion, Skeletons, FFAP, Code Check, Eldoc, Imenu. |
| 37 | 37 | ||
| 38 | ;; Syntax highlighting: Fontification of code is provided and supports | 38 | ;; Syntax highlighting: Fontification of code is provided and supports |
| 39 | ;; python's triple quoted strings properly. | 39 | ;; python's triple quoted strings properly. |
| @@ -170,6 +170,10 @@ | |||
| 170 | ;; introduced as simple way of adding paths to the PYTHONPATH without | 170 | ;; introduced as simple way of adding paths to the PYTHONPATH without |
| 171 | ;; affecting existing values. | 171 | ;; affecting existing values. |
| 172 | 172 | ||
| 173 | ;; Shell package support: you can enable a package in the current | ||
| 174 | ;; shell so that relative imports work properly using the | ||
| 175 | ;; `python-shell-package-enable' command. | ||
| 176 | |||
| 173 | ;; Shell syntax highlighting: when enabled current input in shell is | 177 | ;; Shell syntax highlighting: when enabled current input in shell is |
| 174 | ;; highlighted. The variable `python-shell-font-lock-enable' controls | 178 | ;; highlighted. The variable `python-shell-font-lock-enable' controls |
| 175 | ;; activation of this feature globally when shells are started. | 179 | ;; activation of this feature globally when shells are started. |
| @@ -2100,6 +2104,31 @@ uniqueness for different types of configurations." | |||
| 2100 | (directory-file-name python-shell-virtualenv-path)) | 2104 | (directory-file-name python-shell-virtualenv-path)) |
| 2101 | path)))) | 2105 | path)))) |
| 2102 | 2106 | ||
| 2107 | (defvar python-shell--package-depth 10) | ||
| 2108 | |||
| 2109 | (defun python-shell-package-enable (directory package) | ||
| 2110 | "Add DIRECTORY parent to $PYTHONPATH and enable PACKAGE." | ||
| 2111 | (interactive | ||
| 2112 | (let* ((dir (expand-file-name | ||
| 2113 | (read-directory-name | ||
| 2114 | "Package root: " | ||
| 2115 | (file-name-directory | ||
| 2116 | (or (buffer-file-name) default-directory))))) | ||
| 2117 | (name (completing-read | ||
| 2118 | "Package: " | ||
| 2119 | (python-util-list-packages | ||
| 2120 | dir python-shell--package-depth)))) | ||
| 2121 | (list dir name))) | ||
| 2122 | (python-shell-send-string | ||
| 2123 | (format | ||
| 2124 | (concat | ||
| 2125 | "import os.path;import sys;" | ||
| 2126 | "sys.path.append(os.path.dirname(os.path.dirname('''%s''')));" | ||
| 2127 | "__package__ = '''%s''';" | ||
| 2128 | "import %s") | ||
| 2129 | directory package package) | ||
| 2130 | (python-shell-get-process))) | ||
| 2131 | |||
| 2103 | (defun python-shell-comint-end-of-output-p (output) | 2132 | (defun python-shell-comint-end-of-output-p (output) |
| 2104 | "Return non-nil if OUTPUT is ends with input prompt." | 2133 | "Return non-nil if OUTPUT is ends with input prompt." |
| 2105 | (string-match | 2134 | (string-match |
| @@ -4070,6 +4099,68 @@ Optional argument DIRECTION defines the direction to move to." | |||
| 4070 | (goto-char comment-start)) | 4099 | (goto-char comment-start)) |
| 4071 | (forward-comment factor))) | 4100 | (forward-comment factor))) |
| 4072 | 4101 | ||
| 4102 | (defun python-util-list-directories (directory &optional predicate max-depth) | ||
| 4103 | "List DIRECTORY subdirs, filtered by PREDICATE and limited by MAX-DEPTH. | ||
| 4104 | Argument PREDICATE defaults to `identity' and must be a function | ||
| 4105 | that takes one argument (a full path) and returns non-nil for | ||
| 4106 | allowed files. When optional argument MAX-DEPTH is non-nil, stop | ||
| 4107 | searching when depth is reached, else don't limit." | ||
| 4108 | (let* ((dir (expand-file-name directory)) | ||
| 4109 | (dir-length (length dir)) | ||
| 4110 | (predicate (or predicate #'identity)) | ||
| 4111 | (to-scan (list dir)) | ||
| 4112 | (tally nil)) | ||
| 4113 | (while to-scan | ||
| 4114 | (let ((current-dir (car to-scan))) | ||
| 4115 | (when (funcall predicate current-dir) | ||
| 4116 | (setq tally (cons current-dir tally))) | ||
| 4117 | (setq to-scan (append (cdr to-scan) | ||
| 4118 | (python-util-list-files | ||
| 4119 | current-dir #'file-directory-p) | ||
| 4120 | nil)) | ||
| 4121 | (when (and max-depth | ||
| 4122 | (<= max-depth | ||
| 4123 | (length (split-string | ||
| 4124 | (substring current-dir dir-length) | ||
| 4125 | "/\\|\\\\" t)))) | ||
| 4126 | (setq to-scan nil)))) | ||
| 4127 | (nreverse tally))) | ||
| 4128 | |||
| 4129 | (defun python-util-list-files (dir &optional predicate) | ||
| 4130 | "List files in DIR, filtering with PREDICATE. | ||
| 4131 | Argument PREDICATE defaults to `identity' and must be a function | ||
| 4132 | that takes one argument (a full path) and returns non-nil for | ||
| 4133 | allowed files." | ||
| 4134 | (let ((dir-name (file-name-as-directory dir))) | ||
| 4135 | (apply #'nconc | ||
| 4136 | (mapcar (lambda (file-name) | ||
| 4137 | (let ((full-file-name (expand-file-name file-name dir-name))) | ||
| 4138 | (when (and | ||
| 4139 | (not (member file-name '("." ".."))) | ||
| 4140 | (funcall (or predicate #'identity) full-file-name)) | ||
| 4141 | (list full-file-name)))) | ||
| 4142 | (directory-files dir-name))))) | ||
| 4143 | |||
| 4144 | (defun python-util-list-packages (dir &optional max-depth) | ||
| 4145 | "List packages in DIR, limited by MAX-DEPTH. | ||
| 4146 | When optional argument MAX-DEPTH is non-nil, stop searching when | ||
| 4147 | depth is reached, else don't limit." | ||
| 4148 | (let* ((dir (expand-file-name dir)) | ||
| 4149 | (parent-dir (file-name-directory | ||
| 4150 | (directory-file-name | ||
| 4151 | (file-name-directory | ||
| 4152 | (file-name-as-directory dir))))) | ||
| 4153 | (subpath-length (length parent-dir))) | ||
| 4154 | (mapcar | ||
| 4155 | (lambda (file-name) | ||
| 4156 | (replace-regexp-in-string | ||
| 4157 | (rx (or ?\\ ?/)) "." (substring file-name subpath-length))) | ||
| 4158 | (python-util-list-directories | ||
| 4159 | (directory-file-name dir) | ||
| 4160 | (lambda (dir) | ||
| 4161 | (file-exists-p (expand-file-name "__init__.py" dir))) | ||
| 4162 | max-depth)))) | ||
| 4163 | |||
| 4073 | (defun python-util-popn (lst n) | 4164 | (defun python-util-popn (lst n) |
| 4074 | "Return LST first N elements. | 4165 | "Return LST first N elements. |
| 4075 | N should be an integer, when negative its opposite is used. | 4166 | N should be an integer, when negative its opposite is used. |