+2014-07-21 Glenn Morris <rgm@gnu.org>
+
+ * emacs.texi (Intro): Workaround makeinfo 4 @acronym bug. (Bug#18040)
+
2014-07-09 Juri Linkov <juri@jurta.org>
* search.texi (Regexp Search): Update lax space matching that is
You are reading about GNU Emacs, the GNU incarnation of the
advanced, self-documenting, customizable, extensible editor Emacs.
-(The @samp{G} in @acronym{GNU, @acronym{GNU}'s Not Unix} is not silent.)
+(The @samp{G} in
+@c Workaround makeinfo 4 bug.
+@c http://lists.gnu.org/archive/html/bug-texinfo/2004-08/msg00009.html
+@iftex
+@acronym{GNU, @acronym{GNU}'s Not Unix}
+@end iftex
+@ifnottex
+@acronym{GNU, GNU's Not Unix}
+@end ifnottex
+is not silent.)
We call Emacs @dfn{advanced} because it can do much more than simple
insertion and deletion of text. It can control subprocesses, indent
** In Prolog mode, `prolog-use-smie' has been removed,
along with the non-SMIE indentation code.
+** Python mode
+
+*** Out of the box support for CPython, iPython and readline based shells.
+**** `python-shell-completion-module-string-code` is no longer used.
+
+*** Automatic shell prompt detection. New user options:
+**** `python-shell-interpreter-interactive-arg'.
+**** `python-shell-prompt-detect-enabled'.
+**** `python-shell-prompt-detect-failure-warning'.
+**** `python-shell-prompt-input-regexps'.
+**** `python-shell-prompt-output-regexps'.
+
+*** Python shell support for remote hosts via tramp.
+
+*** Correct display of line numbers for code sent to the Python shell.
+
** Remember
*** The new command `remember-notes' creates a buffer that is saved on exit.
+2014-07-21 Glenn Morris <rgm@gnu.org>
+
+ * progmodes/hideif.el (hide-ifdef-mode-submap):
+ Also substitute read-only-mode.
+ * bindings.el (mode-line-toggle-read-only):
+ * bs.el (bs-toggle-readonly):
+ * buff-menu.el (Buffer-menu-toggle-read-only):
+ * dired.el (dired-toggle-read-only):
+ * files.el (view-read-only, find-file-read-only)
+ (find-file-read-only-other-window)
+ (find-file-read-only-other-frame):
+ * progmodes/hideif.el (hide-ifdef-toggle-outside-read-only):
+ Doc fixes re toggle-read-only.
+
+2014-07-21 Fabián Ezequiel Gallina <fgallina@gnu.org>
+
+ * progmodes/python.el: Add comment about pipe buffering and
+ solutions for missing/delayed output in inferior Python shells.
+ (Bug#17304)
+
+ * progmodes/python.el (python-mode): Don't set
+ mode-require-final-newline. (Bug#17990)
+
+ Make python.el work with IPython automatically. (Bug#15510)
+ * progmodes/python.el:
+ (python-shell-completion-setup-code): New value supporting iPython.
+ (python-shell-completion-string-code): New value supporting iPython.
+ (python-shell-completion-get-completions): Use them.
+ (python-shell-completion-module-string-code): Make obsolete.
+ (python-shell-prompt-input-regexps)
+ (python-shell-prompt-output-regexps): Add safeguard for ipdb.
+ (python-shell-output-filter): Fix comment typo.
+
+ Fix Python shell prompts detection for remote hosts.
+ * progmodes/python.el (python-shell-prompt-detect): Replace
+ call-process with process-file and make it more robust.
+
+ Autodetect Python shell prompts. (Bug#17370)
+ * progmodes/python.el:
+ (python-shell-interpreter-interactive-arg)
+ (python-shell-prompt-detect-enabled)
+ (python-shell-prompt-detect-failure-warning)
+ (python-shell-prompt-input-regexps)
+ (python-shell-prompt-output-regexps): New vars.
+ (python-shell-prompt-calculated-input-regexp)
+ (python-shell-prompt-calculated-output-regexp): New vars.
+ (python-shell-get-process-name)
+ (python-shell-internal-get-process-name)
+ (python-shell-output-filter)
+ (python-shell-completion-get-completions): Use them.
+ (python-shell-prompt-detect)
+ (python-shell-prompt-validate-regexps): New functions.
+ (python-shell-prompt-set-calculated-regexps): New function.
+ (inferior-python-mode): Use it. Also honor overriden
+ python-shell-interpreter and python-shell-interpreter-args.
+ (python-shell-make-comint): Honor overriden
+ python-shell-interpreter and python-shell-interpreter-args.
+ (python-shell-get-or-create-process): Make it testable by allowing
+ to call run-python non-interactively.
+ (python-util-valid-regexp-p): New function.
+ (python-shell-prompt-regexp, python-shell-prompt-block-regexp)
+ (python-shell-prompt-output-regexp)
+ (python-shell-prompt-pdb-regexp): Use it as defcustom :safe.
+
2014-07-21 Stefan Monnier <monnier@iro.umontreal.ca>
* emacs-lisp/smie.el (smie-config--guess-1): Split from
(defun mode-line-toggle-read-only (event)
- "Like `toggle-read-only', for the mode-line."
+ "Like toggling `read-only-mode', for the mode-line."
(interactive "e")
(with-selected-window (posn-window (event-start event))
(read-only-mode 'toggle)))
(defun bs-toggle-readonly ()
"Toggle read-only status for buffer on current line.
-Uses function `toggle-read-only'."
+Uses function `read-only-mode'."
(interactive)
(with-current-buffer (bs--current-buffer)
(read-only-mode 'toggle))
(defun Buffer-menu-toggle-read-only ()
"Toggle read-only status of buffer on this line.
-This behaves like invoking \\[toggle-read-only] in that buffer."
+This behaves like invoking \\[read-only-mode] in that buffer."
(interactive)
(let ((read-only
(with-current-buffer (Buffer-menu-buffer t)
"Edit Dired buffer with Wdired, or make it read-only.
If the current buffer can be edited with Wdired, (i.e. the major
mode is `dired-mode'), call `wdired-change-to-wdired-mode'.
-Otherwise, call `toggle-read-only'."
+Otherwise, toggle `read-only-mode'."
(interactive)
(if (derived-mode-p 'dired-mode)
(wdired-change-to-wdired-mode)
In fact, this means that all read-only buffers normally have
View mode enabled, including buffers that are read-only because
you visit a file you cannot alter, and buffers you make read-only
-using \\[toggle-read-only]."
+using \\[read-only-mode]."
:type 'boolean
:group 'view)
(defun find-file-read-only (filename &optional wildcards)
"Edit file FILENAME but don't allow changes.
Like \\[find-file], but marks buffer as read-only.
-Use \\[toggle-read-only] to permit editing."
+Use \\[read-only-mode] to permit editing."
(interactive
(find-file-read-args "Find file read-only: "
(confirm-nonexistent-file-or-buffer)))
(defun find-file-read-only-other-window (filename &optional wildcards)
"Edit file FILENAME in another window but don't allow changes.
Like \\[find-file-other-window], but marks buffer as read-only.
-Use \\[toggle-read-only] to permit editing."
+Use \\[read-only-mode] to permit editing."
(interactive
(find-file-read-args "Find file read-only other window: "
(confirm-nonexistent-file-or-buffer)))
(defun find-file-read-only-other-frame (filename &optional wildcards)
"Edit file FILENAME in another frame but don't allow changes.
Like \\[find-file-other-frame], but marks buffer as read-only.
-Use \\[toggle-read-only] to permit editing."
+Use \\[read-only-mode] to permit editing."
(interactive
(find-file-read-args "Find file read-only other frame: "
(confirm-nonexistent-file-or-buffer)))
(define-key map "\C-q" 'hide-ifdef-toggle-read-only)
(define-key map "\C-w" 'hide-ifdef-toggle-shadowing)
+ (substitute-key-definition
+ 'read-only-mode 'hide-ifdef-toggle-outside-read-only map)
+ ;; `toggle-read-only' is obsoleted by `read-only-mode'.
(substitute-key-definition
'toggle-read-only 'hide-ifdef-toggle-outside-read-only map)
map)
(force-mode-line-update))
(defun hide-ifdef-toggle-outside-read-only ()
- "Replacement for `toggle-read-only' within Hide-Ifdef mode."
+ "Replacement for `read-only-mode' within Hide-Ifdef mode."
(interactive)
(setq hif-outside-read-only (not hif-outside-read-only))
(message "Read only %s"
;; Author: Fabián E. Gallina <fabian@anue.biz>
;; URL: https://github.com/fgallina/python.el
-;; Version: 0.24.2
+;; Version: 0.24.4
;; Maintainer: emacs-devel@gnu.org
;; Created: Jul 2010
;; Keywords: languages
;; (add-hook 'python-mode-hook
;; (lambda () (setq forward-sexp-function nil)))
-;; Shell interaction: is provided and allows you to execute easily any
-;; block of code of your current buffer in an inferior Python process.
+;; Shell interaction: is provided and allows opening Python shells
+;; inside Emacs and executing any block of code of your current buffer
+;; in that inferior Python process.
+
+;; Besides that only the standard CPython (2.x and 3.x) shell and
+;; IPython are officially supported out of the box, the interaction
+;; should support any other readline based Python shells as well
+;; (e.g. Jython and Pypy have been reported to work). You can change
+;; your default interpreter and commandline arguments by setting the
+;; `python-shell-interpreter' and `python-shell-interpreter-args'
+;; variables. This example enables IPython globally:
+
+;; (setq python-shell-interpreter "ipython"
+;; python-shell-interpreter-args "-i")
+
+;; Using the "console" subcommand to start IPython in server-client
+;; mode is known to fail intermittently due a bug on IPython itself
+;; (see URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=18052#27').
+;; There seems to be a race condition in the IPython server (A.K.A
+;; kernel) when code is sent while it is still initializing, sometimes
+;; causing the shell to get stalled. With that said, if an IPython
+;; kernel is already running, "console --existing" seems to work fine.
+
+;; Running IPython on Windows needs more tweaking. The way you should
+;; set `python-shell-interpreter' and `python-shell-interpreter-args'
+;; is as follows (of course you need to modify the paths according to
+;; your system):
+
+;; (setq python-shell-interpreter "C:\\Python27\\python.exe"
+;; python-shell-interpreter-args
+;; "-i C:\\Python27\\Scripts\\ipython-script.py")
+
+;; If you are experiencing missing or delayed output in your shells,
+;; that's likely caused by your Operating System's pipe buffering
+;; (e.g. this is known to happen running CPython 3.3.4 in Windows 7.
+;; See URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=17304'). To
+;; fix this, using CPython's "-u" commandline argument or setting the
+;; "PYTHONUNBUFFERED" environment variable should help: See URL
+;; `https://docs.python.org/3/using/cmdline.html#cmdoption-u'.
+
+;; The interaction relies upon having prompts for input (e.g. ">>> "
+;; and "... " in standard Python shell) and output (e.g. "Out[1]: " in
+;; IPython) detected properly. Failing that Emacs may hang but, in
+;; the case that happens, you can recover with \\[keyboard-quit]. To
+;; avoid this issue, a two-step prompt autodetection mechanism is
+;; provided: the first step is manual and consists of a collection of
+;; regular expressions matching common prompts for Python shells
+;; stored in `python-shell-prompt-input-regexps' and
+;; `python-shell-prompt-output-regexps', and dir-local friendly vars
+;; `python-shell-prompt-regexp', `python-shell-prompt-block-regexp',
+;; `python-shell-prompt-output-regexp' which are appended to the
+;; former automatically when a shell spawns; the second step is
+;; automatic and depends on the `python-shell-prompt-detect' helper
+;; function. See its docstring for details on global variables that
+;; modify its behavior.
;; Shell completion: hitting tab will try to complete the current
-;; word. Shell completion is implemented in a manner that if you
-;; change the `python-shell-interpreter' to any other (for example
-;; IPython) it should be easy to integrate another way to calculate
-;; completions. You just need to specify your custom
-;; `python-shell-completion-setup-code' and
-;; `python-shell-completion-string-code'.
-
-;; Here is a complete example of the settings you would use for
-;; iPython 0.11:
-
-;; (setq
-;; python-shell-interpreter "ipython"
-;; python-shell-interpreter-args ""
-;; python-shell-prompt-regexp "In \\[[0-9]+\\]: "
-;; python-shell-prompt-output-regexp "Out\\[[0-9]+\\]: "
-;; python-shell-completion-setup-code
-;; "from IPython.core.completerlib import module_completion"
-;; python-shell-completion-module-string-code
-;; "';'.join(module_completion('''%s'''))\n"
-;; python-shell-completion-string-code
-;; "';'.join(get_ipython().Completer.all_completions('''%s'''))\n")
-
-;; For iPython 0.10 everything would be the same except for
-;; `python-shell-completion-string-code' and
-;; `python-shell-completion-module-string-code':
-
-;; (setq python-shell-completion-string-code
-;; "';'.join(__IP.complete('''%s'''))\n"
-;; python-shell-completion-module-string-code "")
-
-;; Unfortunately running iPython on Windows needs some more tweaking.
-;; The way you must set `python-shell-interpreter' and
-;; `python-shell-interpreter-args' is as follows:
-
-;; (setq
-;; python-shell-interpreter "C:\\Python27\\python.exe"
-;; python-shell-interpreter-args
-;; "-i C:\\Python27\\Scripts\\ipython-script.py")
-
-;; That will spawn the iPython process correctly (Of course you need
-;; to modify the paths according to your system).
-
-;; Please note that the default completion system depends on the
+;; word. Shell completion is implemented in such way that if you
+;; change the `python-shell-interpreter' it should be possible to
+;; integrate custom logic to calculate completions. To achieve this
+;; you just need to set `python-shell-completion-setup-code' and
+;; `python-shell-completion-string-code'. The default provided code,
+;; enables autocompletion for both CPython and IPython (and ideally
+;; any readline based Python shell). This code depends on the
;; readline module, so if you are using some Operating System that
-;; bundles Python without it (like Windows) just install the
-;; pyreadline from http://ipython.scipy.org/moin/PyReadline/Intro and
-;; you should be good to go.
+;; bundles Python without it (like Windows), installing pyreadline
+;; from URL `http://ipython.scipy.org/moin/PyReadline/Intro' should
+;; suffice. To troubleshoot why you are not getting any completions
+;; you can try the following in your Python shell:
+
+;; >>> import readline, rlcompleter
+
+;; If you see an error, then you need to either install pyreadline or
+;; setup custom code that avoids that dependency.
;; Shell virtualenv support: The shell also contains support for
;; virtualenvs and other special environment modifications thanks to
;;; Code:
(require 'ansi-color)
+(require 'cl-lib)
(require 'comint)
+(require 'json)
;; Avoid compiler warnings
(defvar view-return-to-alist)
:type 'string
:group 'python)
+(defcustom python-shell-interpreter-interactive-arg "-i"
+ "Interpreter argument to force it to run interactively."
+ :type 'string
+ :version "24.4")
+
+(defcustom python-shell-prompt-detect-enabled t
+ "Non-nil enables autodetection of interpreter prompts."
+ :type 'boolean
+ :safe 'booleanp
+ :version "24.4")
+
+(defcustom python-shell-prompt-detect-failure-warning t
+ "Non-nil enables warnings when detection of prompts fail."
+ :type 'boolean
+ :safe 'booleanp
+ :version "24.4")
+
+(defcustom python-shell-prompt-input-regexps
+ '(">>> " "\\.\\.\\. " ; Python
+ "In \\[[0-9]+\\]: " ; IPython
+ ;; Using ipdb outside IPython may fail to cleanup and leave static
+ ;; IPython prompts activated, this adds some safeguard for that.
+ "In : " "\\.\\.\\.: ")
+ "List of regular expressions matching input prompts."
+ :type '(repeat string)
+ :version "24.4")
+
+(defcustom python-shell-prompt-output-regexps
+ '("" ; Python
+ "Out\\[[0-9]+\\]: " ; IPython
+ "Out :") ; ipdb safeguard
+ "List of regular expressions matching output prompts."
+ :type '(repeat string)
+ :version "24.4")
+
(defcustom python-shell-prompt-regexp ">>> "
- "Regular expression matching top-level input prompt of Python shell.
+ "Regular expression matching top level input prompt of Python shell.
It should not contain a caret (^) at the beginning."
- :type 'string
- :group 'python
- :safe 'stringp)
+ :type 'string)
-(defcustom python-shell-prompt-block-regexp "[.][.][.] "
+(defcustom python-shell-prompt-block-regexp "\\.\\.\\. "
"Regular expression matching block input prompt of Python shell.
It should not contain a caret (^) at the beginning."
- :type 'string
- :group 'python
- :safe 'stringp)
+ :type 'string)
(defcustom python-shell-prompt-output-regexp ""
"Regular expression matching output prompt of Python shell.
It should not contain a caret (^) at the beginning."
- :type 'string
- :group 'python
- :safe 'stringp)
+ :type 'string)
(defcustom python-shell-prompt-pdb-regexp "[(<]*[Ii]?[Pp]db[>)]+ "
"Regular expression matching pdb input prompt of Python shell.
It should not contain a caret (^) at the beginning."
- :type 'string
- :group 'python
- :safe 'stringp)
+ :type 'string)
(defcustom python-shell-enable-font-lock t
"Should syntax highlighting be enabled in the Python shell buffer?
:type '(alist string)
:group 'python)
+(defvar python-shell--prompt-calculated-input-regexp nil
+ "Calculated input prompt regexp for inferior python shell.
+Do not set this variable directly, instead use
+`python-shell-prompt-set-calculated-regexps'.")
+
+(defvar python-shell--prompt-calculated-output-regexp nil
+ "Calculated output prompt regexp for inferior python shell.
+Do not set this variable directly, instead use
+`python-shell-set-prompt-regexp'.")
+
+(defun python-shell-prompt-detect ()
+ "Detect prompts for the current `python-shell-interpreter'.
+When prompts can be retrieved successfully from the
+`python-shell-interpreter' run with
+`python-shell-interpreter-interactive-arg', returns a list of
+three elements, where the first two are input prompts and the
+last one is an output prompt. When no prompts can be detected
+and `python-shell-prompt-detect-failure-warning' is non-nil,
+shows a warning with instructions to avoid hangs and returns nil.
+When `python-shell-prompt-detect-enabled' is nil avoids any
+detection and just returns nil."
+ (when python-shell-prompt-detect-enabled
+ (let* ((process-environment (python-shell-calculate-process-environment))
+ (exec-path (python-shell-calculate-exec-path))
+ (code (concat
+ "import sys\n"
+ "ps = [getattr(sys, 'ps%s' % i, '') for i in range(1,4)]\n"
+ ;; JSON is built manually for compatibility
+ "ps_json = '\\n[\"%s\", \"%s\", \"%s\"]\\n' % tuple(ps)\n"
+ "print (ps_json)\n"
+ "sys.exit(0)\n"))
+ (output
+ (with-temp-buffer
+ ;; TODO: improve error handling by using
+ ;; `condition-case' and displaying the error message to
+ ;; the user in the no-prompts warning.
+ (ignore-errors
+ (let ((code-file (python-shell--save-temp-file code)))
+ ;; Use `process-file' as it is remote-host friendly.
+ (process-file
+ (executable-find python-shell-interpreter)
+ code-file
+ '(t nil)
+ nil
+ python-shell-interpreter-interactive-arg)
+ ;; Try to cleanup
+ (delete-file code-file)))
+ (buffer-string)))
+ (prompts
+ (catch 'prompts
+ (dolist (line (split-string output "\n" t))
+ (let ((res
+ ;; Check if current line is a valid JSON array
+ (and (string= (substring line 0 2) "[\"")
+ (ignore-errors
+ ;; Return prompts as a list, not vector
+ (append (json-read-from-string line) nil)))))
+ ;; The list must contain 3 strings, where the first
+ ;; is the input prompt, the second is the block
+ ;; prompt and the last one is the output prompt. The
+ ;; input prompt is the only one that can't be empty.
+ (when (and (= (length res) 3)
+ (cl-every #'stringp res)
+ (not (string= (car res) "")))
+ (throw 'prompts res))))
+ nil)))
+ (when (and (not prompts)
+ python-shell-prompt-detect-failure-warning)
+ (warn
+ (concat
+ "Python shell prompts cannot be detected.\n"
+ "If your emacs session hangs when starting python shells\n"
+ "recover with `keyboard-quit' and then try fixing the\n"
+ "interactive flag for your interpreter by adjusting the\n"
+ "`python-shell-interpreter-interactive-arg' or add regexps\n"
+ "matching shell prompts in the directory-local friendly vars:\n"
+ " + `python-shell-prompt-regexp'\n"
+ " + `python-shell-prompt-block-regexp'\n"
+ " + `python-shell-prompt-output-regexp'\n"
+ "Or alternatively in:\n"
+ " + `python-shell-prompt-input-regexps'\n"
+ " + `python-shell-prompt-output-regexps'")))
+ prompts)))
+
+(defun python-shell-prompt-validate-regexps ()
+ "Validate all user provided regexps for prompts.
+Signals `user-error' if any of these vars contain invalid
+regexps: `python-shell-prompt-regexp',
+`python-shell-prompt-block-regexp',
+`python-shell-prompt-pdb-regexp',
+`python-shell-prompt-output-regexp',
+`python-shell-prompt-input-regexps',
+`python-shell-prompt-output-regexps'."
+ (dolist (symbol (list 'python-shell-prompt-input-regexps
+ 'python-shell-prompt-output-regexps
+ 'python-shell-prompt-regexp
+ 'python-shell-prompt-block-regexp
+ 'python-shell-prompt-pdb-regexp
+ 'python-shell-prompt-output-regexp))
+ (dolist (regexp (let ((regexps (symbol-value symbol)))
+ (if (listp regexps)
+ regexps
+ (list regexps))))
+ (when (not (python-util-valid-regexp-p regexp))
+ (user-error "Invalid regexp %s in `%s'"
+ regexp symbol)))))
+
+(defun python-shell-prompt-set-calculated-regexps ()
+ "Detect and set input and output prompt regexps.
+Build and set the values for `python-shell-input-prompt-regexp'
+and `python-shell-output-prompt-regexp' using the values from
+`python-shell-prompt-regexp', `python-shell-prompt-block-regexp',
+`python-shell-prompt-pdb-regexp',
+`python-shell-prompt-output-regexp',
+`python-shell-prompt-input-regexps',
+`python-shell-prompt-output-regexps' and detected prompts from
+`python-shell-prompt-detect'."
+ (when (not (and python-shell--prompt-calculated-input-regexp
+ python-shell--prompt-calculated-output-regexp))
+ (let* ((detected-prompts (python-shell-prompt-detect))
+ (input-prompts nil)
+ (output-prompts nil)
+ (build-regexp
+ (lambda (prompts)
+ (concat "^\\("
+ (mapconcat #'identity
+ (sort prompts
+ (lambda (a b)
+ (let ((length-a (length a))
+ (length-b (length b)))
+ (if (= length-a length-b)
+ (string< a b)
+ (> (length a) (length b))))))
+ "\\|")
+ "\\)"))))
+ ;; Validate ALL regexps
+ (python-shell-prompt-validate-regexps)
+ ;; Collect all user defined input prompts
+ (dolist (prompt (append python-shell-prompt-input-regexps
+ (list python-shell-prompt-regexp
+ python-shell-prompt-block-regexp
+ python-shell-prompt-pdb-regexp)))
+ (cl-pushnew prompt input-prompts :test #'string=))
+ ;; Collect all user defined output prompts
+ (dolist (prompt (cons python-shell-prompt-output-regexp
+ python-shell-prompt-output-regexps))
+ (cl-pushnew prompt output-prompts :test #'string=))
+ ;; Collect detected prompts if any
+ (when detected-prompts
+ (dolist (prompt (butlast detected-prompts))
+ (setq prompt (regexp-quote prompt))
+ (cl-pushnew prompt input-prompts :test #'string=))
+ (cl-pushnew (regexp-quote
+ (car (last detected-prompts)))
+ output-prompts :test #'string=))
+ ;; Set input and output prompt regexps from collected prompts
+ (setq python-shell--prompt-calculated-input-regexp
+ (funcall build-regexp input-prompts)
+ python-shell--prompt-calculated-output-regexp
+ (funcall build-regexp output-prompts)))))
+
(defun python-shell-get-process-name (dedicated)
"Calculate the appropriate process name for inferior Python process.
If DEDICATED is t and the variable `buffer-file-name' is non-nil
python-shell-internal-buffer-name
(md5
(concat
- (python-shell-parse-command)
- python-shell-prompt-regexp
- python-shell-prompt-block-regexp
- python-shell-prompt-output-regexp
+ python-shell-interpreter
+ python-shell-interpreter-args
+ python-shell--prompt-calculated-input-regexp
+ python-shell--prompt-calculated-output-regexp
(mapconcat #'symbol-value python-shell-setup-codes "")
(mapconcat #'identity python-shell-process-environment "")
(mapconcat #'identity python-shell-extra-pythonpaths "")
variable.
\(Type \\[describe-mode] in the process buffer for a list of commands.)"
- (and python-shell--parent-buffer
- (python-util-clone-local-variables python-shell--parent-buffer))
- (setq comint-prompt-regexp (format "^\\(?:%s\\|%s\\|%s\\)"
- python-shell-prompt-regexp
- python-shell-prompt-block-regexp
- python-shell-prompt-pdb-regexp))
+ (let ((interpreter python-shell-interpreter)
+ (args python-shell-interpreter-args))
+ (when python-shell--parent-buffer
+ (python-util-clone-local-variables python-shell--parent-buffer))
+ ;; Users can override default values for these vars when calling
+ ;; `run-python'. This ensures new values let-bound in
+ ;; `python-shell-make-comint' are locally set.
+ (set (make-local-variable 'python-shell-interpreter) interpreter)
+ (set (make-local-variable 'python-shell-interpreter-args) args))
+ (set (make-local-variable 'python-shell--prompt-calculated-input-regexp) nil)
+ (set (make-local-variable 'python-shell--prompt-calculated-output-regexp) nil)
+ (python-shell-prompt-set-calculated-regexps)
+ (setq comint-prompt-regexp python-shell--prompt-calculated-input-regexp)
(setq mode-line-process '(":%s"))
(make-local-variable 'comint-output-filter-functions)
(add-hook 'comint-output-filter-functions
(exec-path (python-shell-calculate-exec-path)))
(when (not (comint-check-proc proc-buffer-name))
(let* ((cmdlist (split-string-and-unquote cmd))
+ (interpreter (car cmdlist))
+ (args (cdr cmdlist))
(buffer (apply #'make-comint-in-buffer proc-name proc-buffer-name
- (car cmdlist) nil (cdr cmdlist)))
+ interpreter nil args))
(python-shell--parent-buffer (current-buffer))
- (process (get-buffer-process buffer)))
+ (process (get-buffer-process buffer))
+ ;; As the user may have overriden default values for
+ ;; these vars on `run-python', let-binding them allows
+ ;; to have the new right values in all setup code
+ ;; that's is done in `inferior-python-mode', which is
+ ;; important, especially for prompt detection.
+ (python-shell-interpreter interpreter)
+ (python-shell-interpreter-args
+ (mapconcat #'identity args " ")))
(with-current-buffer buffer
(inferior-python-mode))
(accept-process-output process)
"Return inferior Python process for current buffer."
(get-buffer-process (python-shell-get-buffer)))
-(defun python-shell-get-or-create-process ()
- "Get or create an inferior Python process for current buffer and return it."
+(defun python-shell-get-or-create-process (&optional cmd dedicated show)
+ "Get or create an inferior Python process for current buffer and return it.
+Arguments CMD, DEDICATED and SHOW are those of `run-python' and
+are used to start the shell. If those arguments are not
+provided, `run-python' is called interactively and the user will
+be asked for their values."
(let* ((dedicated-proc-name (python-shell-get-process-name t))
(dedicated-proc-buffer-name (format "*%s*" dedicated-proc-name))
(global-proc-name (python-shell-get-process-name nil))
(dedicated-running (comint-check-proc dedicated-proc-buffer-name))
(global-running (comint-check-proc global-proc-buffer-name)))
(when (and (not dedicated-running) (not global-running))
- (if (call-interactively 'run-python)
+ (if (if (not cmd)
+ ;; XXX: Refactor code such that calling `run-python'
+ ;; interactively is not needed anymore.
+ (call-interactively 'run-python)
+ (run-python cmd dedicated show))
(setq dedicated-running t)
(setq global-running t)))
;; Always prefer dedicated
(when (string-match
;; XXX: It seems on OSX an extra carriage return is attached
;; at the end of output, this handles that too.
- (format "\r?\n\\(?:%s\\|%s\\|%s\\)$"
- python-shell-prompt-regexp
- python-shell-prompt-block-regexp
- python-shell-prompt-pdb-regexp)
+ (concat
+ "\r?\n"
+ ;; Remove initial caret from calculated regexp
+ (replace-regexp-in-string
+ (rx string-start ?^) ""
+ python-shell--prompt-calculated-input-regexp)
+ "$")
python-shell-output-filter-buffer)
;; Output ends when `python-shell-output-filter-buffer' contains
;; the prompt attached at the end of it.
python-shell-output-filter-buffer
(substring python-shell-output-filter-buffer
0 (match-beginning 0)))
- (when (and (> (length python-shell-prompt-output-regexp) 0)
- (string-match (concat "^" python-shell-prompt-output-regexp)
- python-shell-output-filter-buffer))
- ;; Some shells, like iPython might append a prompt before the
+ (when (string-match
+ python-shell--prompt-calculated-output-regexp
+ python-shell-output-filter-buffer)
+ ;; Some shells, like IPython might append a prompt before the
;; output, clean that.
(setq python-shell-output-filter-buffer
(substring python-shell-output-filter-buffer (match-end 0)))))
(defcustom python-shell-completion-setup-code
"try:
- import readline
+ import readline, rlcompleter
except ImportError:
- def __COMPLETER_all_completions(text): []
+ def __PYTHON_EL_get_completions(text):
+ return []
else:
- import rlcompleter
- readline.set_completer(rlcompleter.Completer().complete)
- def __COMPLETER_all_completions(text):
- import sys
+ def __PYTHON_EL_get_completions(text):
completions = []
try:
- i = 0
- while True:
- res = readline.get_completer()(text, i)
- if not res: break
- i += 1
- completions.append(res)
- except NameError:
+ splits = text.split()
+ is_module = splits and splits[0] in ('from', 'import')
+ is_ipython = getattr(
+ __builtins__, '__IPYTHON__',
+ getattr(__builtins__, '__IPYTHON__active', False))
+ if is_module:
+ from IPython.core.completerlib import module_completion
+ completions = module_completion(text.strip())
+ elif is_ipython and getattr(__builtins__, '__IP', None):
+ completions = __IP.complete(text)
+ elif is_ipython and getattr(__builtins__, 'get_ipython', None):
+ completions = get_ipython().Completer.all_completions(text)
+ else:
+ i = 0
+ while True:
+ res = readline.get_completer()(text, i)
+ if not res:
+ break
+ i += 1
+ completions.append(res)
+ except:
pass
return completions"
"Code used to setup completion in inferior Python processes."
:group 'python)
(defcustom python-shell-completion-string-code
- "';'.join(__COMPLETER_all_completions('''%s'''))\n"
- "Python code used to get a string of completions separated by semicolons."
+ "';'.join(__PYTHON_EL_get_completions('''%s'''))\n"
+ "Python code used to get a string of completions separated by semicolons.
+The string passed to the function is the current python name or
+the full statement in the case of imports."
:type 'string
:group 'python)
-(defcustom python-shell-completion-module-string-code ""
- "Python code used to get completions separated by semicolons for imports.
-
-For IPython v0.11, add the following line to
-`python-shell-completion-setup-code':
-
-from IPython.core.completerlib import module_completion
-
-and use the following as the value of this variable:
-
-';'.join(module_completion('''%s'''))\n"
- :type 'string
- :group 'python)
+(define-obsolete-variable-alias
+ 'python-shell-completion-module-string-code
+ 'python-shell-completion-string-code
+ "24.4"
+ "Completion string code must also autocomplete modules.")
(defcustom python-shell-completion-pdb-string-code
"';'.join(globals().keys() + locals().keys())"
(re-search-backward "^")
(python-util-forward-comment)
(point))))))
- (completion-context
+ (completion-code
;; Check whether a prompt matches a pdb string, an import
;; statement or just the standard prompt and use the
;; correct python-shell-completion-*-code string
(cond ((and (> (length python-shell-completion-pdb-string-code) 0)
(string-match
(concat "^" python-shell-prompt-pdb-regexp) prompt))
- 'pdb)
- ((and (>
- (length python-shell-completion-module-string-code) 0)
- (string-match
- (concat "^" python-shell-prompt-regexp) prompt)
- (string-match "^[ \t]*\\(from\\|import\\)[ \t]" line))
- 'import)
+ python-shell-completion-pdb-string-code)
((string-match
- (concat "^" python-shell-prompt-regexp) prompt)
- 'default)
+ python-shell--prompt-calculated-input-regexp prompt)
+ python-shell-completion-string-code)
(t nil)))
- (completion-code
- (pcase completion-context
- (`pdb python-shell-completion-pdb-string-code)
- (`import python-shell-completion-module-string-code)
- (`default python-shell-completion-string-code)
- (_ nil)))
(input
- (if (eq completion-context 'import)
- (replace-regexp-in-string "^[ \t]+" "" line)
+ (if (string-match
+ (python-rx (+ space) (or "from" "import") space)
+ line)
+ line
input)))
(and completion-code
(> (length input) 0)
""
string))
+(defun python-util-valid-regexp-p (regexp)
+ "Return non-nil if REGEXP is valid."
+ (ignore-errors (string-match regexp "") t))
+
\f
(defun python-electric-pair-string-delimiter ()
(when (and electric-pair-mode
,(lambda (_arg)
(python-nav-end-of-defun)) nil))
- (set (make-local-variable 'mode-require-final-newline) t)
-
(set (make-local-variable 'outline-regexp)
(python-rx (* space) block-start))
(set (make-local-variable 'outline-heading-end-regexp) ":[^\n]*\n")
(defun view--disable ()
(remove-hook 'change-major-mode-hook 'view--disable t)
(and view-overlay (delete-overlay view-overlay))
- ;; Calling toggle-read-only while View mode is enabled
+ ;; Calling read-only-mode while View mode is enabled
;; sets view-read-only to t as a buffer-local variable
- ;; after exiting View mode. That arranges that the next toggle-read-only
+ ;; after exiting View mode. That arranges that the next read-only-mode
;; will reenable View mode.
;; Canceling View mode in any other way should cancel that, too,
- ;; so that View mode stays off if toggle-read-only is called.
+ ;; so that View mode stays off if read-only-mode is called.
(if (local-variable-p 'view-read-only)
(kill-local-variable 'view-read-only))
(if (boundp 'Helper-return-blurb)
+2014-07-21 Jan Djärv <jan.h.d@swipnet.se>
+
+ * nsterm.m (applicationDidFinishLaunching:): Call
+ antialiasThresholdDidChange, register for antialias changes (Bug#17534).
+ (antialiasThresholdDidChange:): New method for EmacsApp.
+
+ * nsterm.h (EmacsApp): Add antialiasThresholdDidChange.
+
+ * macfont.m (macfont_update_antialias_threshold): Remove static.
+
+ * macfont.h (macfont_update_antialias_threshold): Declare.
+
+2014-07-21 Eli Zaretskii <eliz@gnu.org>
+
+ * w32select.c (setup_windows_coding_system): Apply
+ CODING_ANNOTATION_MASK to the common_flags member of struct
+ coding_system. Reported by martin rudalics <rudalics@gmx.at>.
+
+ * w16select.c (Fw16_get_clipboard_data): Apply
+ CODING_ANNOTATION_MASK to the common_flags member of struct
+ coding_system.
+
+ * xdisp.c (init_iterator): Initialize it->stop_charpos to the
+ buffer position where we are to start the iteration.
+ (handle_invisible_prop): Record in it->stop_charpos the position
+ where the invisible text ends. (Bug#18035)
+ (hscroll_window_tree): Don't try hscrolling windows whose cursor
+ row has zero buffer position as their start position. Reported by
+ martin rudalics <rudalics@gmx.at>.
+
+ * xdisp.c (move_it_vertically_backward, move_it_by_lines): Prevent
+ infinite looping in redisplay when display lines don't have enough
+ space to display even a single character. (Bug#18036)
+
2014-07-20 Dmitry Antipov <dmantipov@yandex.ru>
* frame.h (struct frame) [USE_X_TOOLKIT]: New member shell_position.
extern void mac_register_font_driver (struct frame *f);
extern void *macfont_get_nsctfont (struct font *font);
+extern void macfont_update_antialias_threshold (void);
static CGFloat macfont_antialias_threshold;
-static void
+void
macfont_update_antialias_threshold (void)
{
int threshold;
#endif
}
- (void)logNotification: (NSNotification *)notification;
+- (void)antialiasThresholdDidChange:(NSNotification *)notification;
- (void)sendEvent: (NSEvent *)theEvent;
- (void)showPreferencesWindow: (id)sender;
- (BOOL) openFile: (NSString *)fileName;
((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
#endif
[NSApp setServicesProvider: NSApp];
+
+ [self antialiasThresholdDidChange:nil];
+#ifdef NS_IMPL_COCOA
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(antialiasThresholdDidChange:)
+ name:NSAntialiasThresholdChangedNotification
+ object:nil];
+#endif
+#endif
+
ns_send_appdefined (-2);
}
+- (void)antialiasThresholdDidChange:(NSNotification *)notification
+{
+#ifdef NS_IMPL_COCOA
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ macfont_update_antialias_threshold ();
+#endif
+#endif
+}
+
/* Termination sequences:
C-x C-c:
coding.mode |= CODING_MODE_LAST_BLOCK;
/* We explicitly disable composition handling because selection
data should not contain any composition sequence. */
- coding.mode &= CODING_ANNOTATION_MASK;
+ coding.common_flags &= ~CODING_ANNOTATION_MASK;
decode_coding_object (&coding, Qnil, 0, 0, truelen, truelen, Qt);
ret = coding.dst_object;
Vlast_coding_system_used = CODING_ID_NAME (coding.id);
which both apply to ISO6429 only. We don't know if these really
need to be unset on Windows, but it probably doesn't hurt
either. */
- coding->mode &= ~CODING_ANNOTATION_MASK;
+ coding->common_flags &= ~CODING_ANNOTATION_MASK;
coding->mode |= CODING_MODE_LAST_BLOCK | CODING_MODE_SAFE_ENCODING;
}
getting overlays and face properties from that position. */
if (charpos >= BUF_BEG (current_buffer))
{
+ it->stop_charpos = charpos;
it->end_charpos = ZV;
eassert (charpos == BYTE_TO_CHAR (bytepos));
IT_CHARPOS (*it) = charpos;
&& get_overlay_strings (it, it->stop_charpos))
{
handled = HANDLED_RECOMPUTE_PROPS;
- it->stack[it->sp - 1].display_ellipsis_p = display_ellipsis_p;
+ if (it->sp > 0)
+ {
+ it->stack[it->sp - 1].display_ellipsis_p = display_ellipsis_p;
+ /* The call to get_overlay_strings above recomputes
+ it->stop_charpos, but it only considers changes
+ in properties and overlays beyond iterator's
+ current position. This causes us to miss changes
+ that happen exactly where the invisible property
+ ended. So we play it safe here and force the
+ iterator to check for potential stop positions
+ immediately after the invisible text. Note that
+ if get_overlay_strings returns non-zero, it
+ normally also pushed the iterator stack, so we
+ need to update the stop position in the slot
+ below the current one. */
+ it->stack[it->sp - 1].stop_charpos
+ = CHARPOS (it->stack[it->sp - 1].current.pos);
+ }
}
else if (display_ellipsis_p)
{
/* Estimate how many newlines we must move back. */
nlines = max (1, dy / default_line_pixel_height (it->w));
- if (it->line_wrap == TRUNCATE)
+ if (it->line_wrap == TRUNCATE || nchars_per_row == 0)
pos_limit = BEGV;
else
pos_limit = max (start_pos - nlines * nchars_per_row, BEGV);
/* Go back -DVPOS buffer lines, but no farther than -DVPOS full
screen lines, and reseat the iterator there. */
start_charpos = IT_CHARPOS (*it);
- if (it->line_wrap == TRUNCATE)
+ if (it->line_wrap == TRUNCATE || nchars_per_row == 0)
pos_limit = BEGV;
else
pos_limit = max (start_charpos + dvpos * nchars_per_row, BEGV);
h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w);
if (!NILP (Fbuffer_local_value (Qauto_hscroll_mode, w->contents))
+ /* In some pathological cases, like restoring a window
+ configuration into a frame that is much smaller than
+ the one from which the configuration was saved, we
+ get glyph rows whose start and end have zero buffer
+ positions, which we cannot handle below. Just skip
+ such windows. */
+ && CHARPOS (cursor_row->start.pos) >= BUF_BEG (w->contents)
/* For left-to-right rows, hscroll when cursor is either
(i) inside the right hscroll margin, or (ii) if it is
inside the left margin and the window is already
+2014-07-21 Fabián Ezequiel Gallina <fgallina@gnu.org>
+
+ * automated/python-tests.el:
+ (python-util-clone-local-variables-1): Fix test.
+
+ * automated/python-tests.el (python-shell-make-comint-1):
+ (python-shell-make-comint-2): Fix indentation.
+ (python-shell-make-comint-3)
+ (python-shell-make-comint-4): New tests.
+ (python-shell-get-or-create-process-1): Fix test.
+ (python-shell-get-or-create-process-2)
+ (python-shell-get-or-create-process-3): New tests.
+ (python-shell-internal-get-or-create-process-1): Fix test.
+ (python-shell-prompt-detect-1): New test.
+ (python-shell-prompt-detect-2): New test. (Bug#17370)
+ (python-shell-prompt-detect-3)
+ (python-shell-prompt-detect-4)
+ (python-shell-prompt-detect-5)
+ (python-shell-prompt-detect-6)
+ (python-shell-prompt-validate-regexps-1)
+ (python-shell-prompt-validate-regexps-2)
+ (python-shell-prompt-validate-regexps-3)
+ (python-shell-prompt-validate-regexps-4)
+ (python-shell-prompt-validate-regexps-5)
+ (python-shell-prompt-validate-regexps-6)
+ (python-shell-prompt-validate-regexps-7)
+ (python-shell-prompt-set-calculated-regexps-1)
+ (python-shell-prompt-set-calculated-regexps-2)
+ (python-shell-prompt-set-calculated-regexps-3)
+ (python-shell-prompt-set-calculated-regexps-4)
+ (python-shell-prompt-set-calculated-regexps-5)
+ (python-shell-prompt-set-calculated-regexps-6)
+ (python-util-valid-regexp-p-1): New tests.
+
2014-07-21 Stefan Monnier <monnier@iro.umontreal.ca>
* automated/advice-tests.el (advice-test-call-interactively): Make sure
* automated/python-tests.el (python-tests-self-insert): New function.
(python-triple-quote-pairing): Use it.
- (python-util-forward-comment-1): New test. (Bug#17658)
+ (python-parens-electric-indent-1): New test. (Bug#17658)
2014-06-30 Fabián Ezequiel Gallina <fgallina@gnu.org>
(proc-name (python-shell-get-process-name nil))
(shell-buffer
(python-tests-with-temp-buffer
- "" (python-shell-make-comint
- (python-shell-parse-command) proc-name)))
+ "" (python-shell-make-comint
+ (python-shell-parse-command) proc-name)))
(process (get-buffer-process shell-buffer)))
(unwind-protect
(progn
(proc-name (python-shell-internal-get-process-name))
(shell-buffer
(python-tests-with-temp-buffer
- "" (python-shell-make-comint
- (python-shell-parse-command) proc-name nil t)))
+ "" (python-shell-make-comint
+ (python-shell-parse-command) proc-name nil t)))
(process (get-buffer-process shell-buffer)))
(unwind-protect
(progn
(should (string= (buffer-name) (format " *%s*" proc-name)))))
(kill-buffer shell-buffer))))
+(ert-deftest python-shell-make-comint-3 ()
+ "Check comint creation with overriden python interpreter and args.
+The command passed to `python-shell-make-comint' as argument must
+locally override global values set in `python-shell-interpreter'
+and `python-shell-interpreter-args' in the new shell buffer."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (let* ((python-shell-setup-codes nil)
+ (python-shell-interpreter "interpreter")
+ (python-shell-interpreter-args "--some-args")
+ (proc-name (python-shell-get-process-name nil))
+ (interpreter-override
+ (concat (executable-find python-tests-shell-interpreter) " " "-i"))
+ (shell-buffer
+ (python-tests-with-temp-buffer
+ "" (python-shell-make-comint interpreter-override proc-name nil)))
+ (process (get-buffer-process shell-buffer)))
+ (unwind-protect
+ (progn
+ (set-process-query-on-exit-flag process nil)
+ (should (process-live-p process))
+ (with-current-buffer shell-buffer
+ (should (eq major-mode 'inferior-python-mode))
+ (should (string= python-shell-interpreter
+ (executable-find python-tests-shell-interpreter)))
+ (should (string= python-shell-interpreter-args "-i"))))
+ (kill-buffer shell-buffer))))
+
+(ert-deftest python-shell-make-comint-4 ()
+ "Check shell calculated prompts regexps are set."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (let* ((process-environment process-environment)
+ (python-shell-setup-codes nil)
+ (python-shell-interpreter
+ (executable-find python-tests-shell-interpreter))
+ (python-shell-interpreter-args "-i")
+ (python-shell--prompt-calculated-input-regexp nil)
+ (python-shell--prompt-calculated-output-regexp nil)
+ (python-shell-prompt-detect-enabled t)
+ (python-shell-prompt-input-regexps '("extralargeinputprompt" "sml"))
+ (python-shell-prompt-output-regexps '("extralargeoutputprompt" "sml"))
+ (python-shell-prompt-regexp "in")
+ (python-shell-prompt-block-regexp "block")
+ (python-shell-prompt-pdb-regexp "pdf")
+ (python-shell-prompt-output-regexp "output")
+ (startup-code (concat "import sys\n"
+ "sys.ps1 = 'py> '\n"
+ "sys.ps2 = '..> '\n"
+ "sys.ps3 = 'out '\n"))
+ (startup-file (python-shell--save-temp-file startup-code))
+ (proc-name (python-shell-get-process-name nil))
+ (shell-buffer
+ (progn
+ (setenv "PYTHONSTARTUP" startup-file)
+ (python-tests-with-temp-buffer
+ "" (python-shell-make-comint
+ (python-shell-parse-command) proc-name nil))))
+ (process (get-buffer-process shell-buffer)))
+ (unwind-protect
+ (progn
+ (set-process-query-on-exit-flag process nil)
+ (should (process-live-p process))
+ (with-current-buffer shell-buffer
+ (should (eq major-mode 'inferior-python-mode))
+ (should (string=
+ python-shell--prompt-calculated-input-regexp
+ (concat "^\\(extralargeinputprompt\\|\\.\\.> \\|"
+ "block\\|py> \\|pdf\\|sml\\|in\\)")))
+ (should (string=
+ python-shell--prompt-calculated-output-regexp
+ "^\\(extralargeoutputprompt\\|output\\|out \\|sml\\)"))))
+ (delete-file startup-file)
+ (kill-buffer shell-buffer))))
+
(ert-deftest python-shell-get-process-1 ()
"Check dedicated shell process preference over global."
(skip-unless (executable-find python-tests-shell-interpreter))
(ignore-errors (kill-buffer dedicated-shell-buffer))))))
(ert-deftest python-shell-get-or-create-process-1 ()
- "Check shell process creation fallback."
- :expected-result :failed
+ "Check shell dedicated process creation."
+ (skip-unless (executable-find python-tests-shell-interpreter))
(python-tests-with-temp-file
- ""
- ;; XXX: Break early until we can skip stuff. We need to mimic
- ;; user interaction because `python-shell-get-or-create-process'
- ;; asks for all arguments interactively when a shell process
- ;; doesn't exist.
- (should nil)
- (let* ((python-shell-interpreter
- (executable-find python-tests-shell-interpreter))
- (use-dialog-box)
- (dedicated-process-name (python-shell-get-process-name t))
- (dedicated-process (python-shell-get-or-create-process))
- (dedicated-shell-buffer (process-buffer dedicated-process)))
- (unwind-protect
- (progn
- (set-process-query-on-exit-flag dedicated-process nil)
- ;; Prefer dedicated if not buffer exist.
- (should (equal (process-name dedicated-process)
- dedicated-process-name))
- (kill-buffer dedicated-shell-buffer)
- ;; No buffer available.
- (should (not (python-shell-get-process))))
- (ignore-errors (kill-buffer dedicated-shell-buffer))))))
+ ""
+ (let* ((python-shell-interpreter
+ (executable-find python-tests-shell-interpreter))
+ (use-dialog-box)
+ (dedicated-process-name (python-shell-get-process-name t))
+ (dedicated-process
+ (python-shell-get-or-create-process python-shell-interpreter t))
+ (dedicated-shell-buffer (process-buffer dedicated-process)))
+ (unwind-protect
+ (progn
+ (set-process-query-on-exit-flag dedicated-process nil)
+ ;; should be dedicated.
+ (should (equal (process-name dedicated-process)
+ dedicated-process-name))
+ (kill-buffer dedicated-shell-buffer)
+ ;; Check there are no processes for current buffer.
+ (should (not (python-shell-get-process))))
+ (ignore-errors (kill-buffer dedicated-shell-buffer))))))
+
+(ert-deftest python-shell-get-or-create-process-2 ()
+ "Check shell global process creation."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (python-tests-with-temp-file
+ ""
+ (let* ((python-shell-interpreter
+ (executable-find python-tests-shell-interpreter))
+ (use-dialog-box)
+ (process-name (python-shell-get-process-name nil))
+ (process
+ (python-shell-get-or-create-process python-shell-interpreter))
+ (shell-buffer (process-buffer process)))
+ (unwind-protect
+ (progn
+ (set-process-query-on-exit-flag process nil)
+ ;; should be global.
+ (should (equal (process-name process) process-name))
+ (kill-buffer shell-buffer)
+ ;; Check there are no processes for current buffer.
+ (should (not (python-shell-get-process))))
+ (ignore-errors (kill-buffer dedicated-shell-buffer))))))
+
+(ert-deftest python-shell-get-or-create-process-3 ()
+ "Check shell dedicated/global process preference."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (python-tests-with-temp-file
+ ""
+ (let* ((python-shell-interpreter
+ (executable-find python-tests-shell-interpreter))
+ (use-dialog-box)
+ (dedicated-process-name (python-shell-get-process-name t))
+ (global-process)
+ (dedicated-process))
+ (unwind-protect
+ (progn
+ ;; Create global process
+ (run-python python-shell-interpreter nil)
+ (setq global-process (get-buffer-process "*Python*"))
+ (should global-process)
+ (set-process-query-on-exit-flag global-process nil)
+ ;; Create dedicated process
+ (run-python python-shell-interpreter t)
+ (setq dedicated-process (get-process dedicated-process-name))
+ (should dedicated-process)
+ (set-process-query-on-exit-flag dedicated-process nil)
+ ;; Prefer dedicated.
+ (should (equal (python-shell-get-or-create-process)
+ dedicated-process))
+ ;; Kill the dedicated so the global takes over.
+ (kill-buffer (process-buffer dedicated-process))
+ ;; Detect global.
+ (should (equal (python-shell-get-or-create-process) global-process))
+ ;; Kill the global.
+ (kill-buffer (process-buffer global-process))
+ ;; Check there are no processes for current buffer.
+ (should (not (python-shell-get-process))))
+ (ignore-errors (kill-buffer dedicated-shell-buffer))))))
(ert-deftest python-shell-internal-get-or-create-process-1 ()
"Check internal shell process creation fallback."
(skip-unless (executable-find python-tests-shell-interpreter))
(python-tests-with-temp-file
- ""
- (should (not (process-live-p (python-shell-internal-get-process-name))))
- (let* ((python-shell-interpreter
- (executable-find python-tests-shell-interpreter))
- (internal-process-name (python-shell-internal-get-process-name))
- (internal-process (python-shell-internal-get-or-create-process))
- (internal-shell-buffer (process-buffer internal-process)))
- (unwind-protect
- (progn
- (set-process-query-on-exit-flag internal-process nil)
- (should (equal (process-name internal-process)
- internal-process-name))
- (should (equal internal-process
- (python-shell-internal-get-or-create-process)))
- ;; No user buffer available.
- (should (not (python-shell-get-process)))
- (kill-buffer internal-shell-buffer))
- (ignore-errors (kill-buffer internal-shell-buffer))))))
+ ""
+ (should (not (process-live-p (python-shell-internal-get-process-name))))
+ (let* ((python-shell-interpreter
+ (executable-find python-tests-shell-interpreter))
+ (internal-process-name (python-shell-internal-get-process-name))
+ (internal-process (python-shell-internal-get-or-create-process))
+ (internal-shell-buffer (process-buffer internal-process)))
+ (unwind-protect
+ (progn
+ (set-process-query-on-exit-flag internal-process nil)
+ (should (equal (process-name internal-process)
+ internal-process-name))
+ (should (equal internal-process
+ (python-shell-internal-get-or-create-process)))
+ ;; Assert the internal process is not a user process
+ (should (not (python-shell-get-process)))
+ (kill-buffer internal-shell-buffer))
+ (ignore-errors (kill-buffer internal-shell-buffer))))))
+
+(ert-deftest python-shell-prompt-detect-1 ()
+ "Check prompt autodetection."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (let ((process-environment process-environment))
+ ;; Ensure no startup file is enabled
+ (setenv "PYTHONSTARTUP" "")
+ (should python-shell-prompt-detect-enabled)
+ (should (equal (python-shell-prompt-detect) '(">>> " "... " "")))))
+
+(ert-deftest python-shell-prompt-detect-2 ()
+ "Check prompt autodetection with startup file. Bug#17370."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (let* ((process-environment process-environment)
+ (startup-code (concat "import sys\n"
+ "sys.ps1 = 'py> '\n"
+ "sys.ps2 = '..> '\n"
+ "sys.ps3 = 'out '\n"))
+ (startup-file (python-shell--save-temp-file startup-code)))
+ (unwind-protect
+ (progn
+ ;; Ensure startup file is enabled
+ (setenv "PYTHONSTARTUP" startup-file)
+ (should python-shell-prompt-detect-enabled)
+ (should (equal (python-shell-prompt-detect) '("py> " "..> " "out "))))
+ (ignore-errors (delete-file startup-file)))))
+
+(ert-deftest python-shell-prompt-detect-3 ()
+ "Check prompts are not autodetected when feature is disabled."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (let ((process-environment process-environment)
+ (python-shell-prompt-detect-enabled nil))
+ ;; Ensure no startup file is enabled
+ (should (not python-shell-prompt-detect-enabled))
+ (should (not (python-shell-prompt-detect)))))
+
+(ert-deftest python-shell-prompt-detect-4 ()
+ "Check warning is shown when detection fails."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (let* ((process-environment process-environment)
+ ;; Trigger failure by removing prompts in the startup file
+ (startup-code (concat "import sys\n"
+ "sys.ps1 = ''\n"
+ "sys.ps2 = ''\n"
+ "sys.ps3 = ''\n"))
+ (startup-file (python-shell--save-temp-file startup-code)))
+ (unwind-protect
+ (progn
+ (kill-buffer (get-buffer-create "*Warnings*"))
+ (should (not (get-buffer "*Warnings*")))
+ (setenv "PYTHONSTARTUP" startup-file)
+ (should python-shell-prompt-detect-failure-warning)
+ (should python-shell-prompt-detect-enabled)
+ (should (not (python-shell-prompt-detect)))
+ (should (get-buffer "*Warnings*")))
+ (ignore-errors (delete-file startup-file)))))
+
+(ert-deftest python-shell-prompt-detect-5 ()
+ "Check disabled warnings are not shown when detection fails."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (let* ((process-environment process-environment)
+ (startup-code (concat "import sys\n"
+ "sys.ps1 = ''\n"
+ "sys.ps2 = ''\n"
+ "sys.ps3 = ''\n"))
+ (startup-file (python-shell--save-temp-file startup-code))
+ (python-shell-prompt-detect-failure-warning nil))
+ (unwind-protect
+ (progn
+ (kill-buffer (get-buffer-create "*Warnings*"))
+ (should (not (get-buffer "*Warnings*")))
+ (setenv "PYTHONSTARTUP" startup-file)
+ (should (not python-shell-prompt-detect-failure-warning))
+ (should python-shell-prompt-detect-enabled)
+ (should (not (python-shell-prompt-detect)))
+ (should (not (get-buffer "*Warnings*"))))
+ (ignore-errors (delete-file startup-file)))))
+
+(ert-deftest python-shell-prompt-detect-6 ()
+ "Warnings are not shown when detection is disabled."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (let* ((process-environment process-environment)
+ (startup-code (concat "import sys\n"
+ "sys.ps1 = ''\n"
+ "sys.ps2 = ''\n"
+ "sys.ps3 = ''\n"))
+ (startup-file (python-shell--save-temp-file startup-code))
+ (python-shell-prompt-detect-failure-warning t)
+ (python-shell-prompt-detect-enabled nil))
+ (unwind-protect
+ (progn
+ (kill-buffer (get-buffer-create "*Warnings*"))
+ (should (not (get-buffer "*Warnings*")))
+ (setenv "PYTHONSTARTUP" startup-file)
+ (should python-shell-prompt-detect-failure-warning)
+ (should (not python-shell-prompt-detect-enabled))
+ (should (not (python-shell-prompt-detect)))
+ (should (not (get-buffer "*Warnings*"))))
+ (ignore-errors (delete-file startup-file)))))
+
+(ert-deftest python-shell-prompt-validate-regexps-1 ()
+ "Check `python-shell-prompt-input-regexps' are validated."
+ (let* ((python-shell-prompt-input-regexps '("\\("))
+ (error-data (should-error (python-shell-prompt-validate-regexps)
+ :type 'user-error)))
+ (should
+ (string= (cadr error-data)
+ "Invalid regexp \\( in `python-shell-prompt-input-regexps'"))))
+
+(ert-deftest python-shell-prompt-validate-regexps-2 ()
+ "Check `python-shell-prompt-output-regexps' are validated."
+ (let* ((python-shell-prompt-output-regexps '("\\("))
+ (error-data (should-error (python-shell-prompt-validate-regexps)
+ :type 'user-error)))
+ (should
+ (string= (cadr error-data)
+ "Invalid regexp \\( in `python-shell-prompt-output-regexps'"))))
+
+(ert-deftest python-shell-prompt-validate-regexps-3 ()
+ "Check `python-shell-prompt-regexp' is validated."
+ (let* ((python-shell-prompt-regexp "\\(")
+ (error-data (should-error (python-shell-prompt-validate-regexps)
+ :type 'user-error)))
+ (should
+ (string= (cadr error-data)
+ "Invalid regexp \\( in `python-shell-prompt-regexp'"))))
+
+(ert-deftest python-shell-prompt-validate-regexps-4 ()
+ "Check `python-shell-prompt-block-regexp' is validated."
+ (let* ((python-shell-prompt-block-regexp "\\(")
+ (error-data (should-error (python-shell-prompt-validate-regexps)
+ :type 'user-error)))
+ (should
+ (string= (cadr error-data)
+ "Invalid regexp \\( in `python-shell-prompt-block-regexp'"))))
+
+(ert-deftest python-shell-prompt-validate-regexps-5 ()
+ "Check `python-shell-prompt-pdb-regexp' is validated."
+ (let* ((python-shell-prompt-pdb-regexp "\\(")
+ (error-data (should-error (python-shell-prompt-validate-regexps)
+ :type 'user-error)))
+ (should
+ (string= (cadr error-data)
+ "Invalid regexp \\( in `python-shell-prompt-pdb-regexp'"))))
+
+(ert-deftest python-shell-prompt-validate-regexps-6 ()
+ "Check `python-shell-prompt-output-regexp' is validated."
+ (let* ((python-shell-prompt-output-regexp "\\(")
+ (error-data (should-error (python-shell-prompt-validate-regexps)
+ :type 'user-error)))
+ (should
+ (string= (cadr error-data)
+ "Invalid regexp \\( in `python-shell-prompt-output-regexp'"))))
+
+(ert-deftest python-shell-prompt-validate-regexps-7 ()
+ "Check default regexps are valid."
+ ;; should not signal error
+ (python-shell-prompt-validate-regexps))
+
+(ert-deftest python-shell-prompt-set-calculated-regexps-1 ()
+ "Check regexps are validated."
+ (let* ((python-shell-prompt-output-regexp '("\\("))
+ (python-shell--prompt-calculated-input-regexp nil)
+ (python-shell--prompt-calculated-output-regexp nil)
+ (python-shell-prompt-detect-enabled nil)
+ (error-data (should-error (python-shell-prompt-set-calculated-regexps)
+ :type 'user-error)))
+ (should
+ (string= (cadr error-data)
+ "Invalid regexp \\( in `python-shell-prompt-output-regexp'"))))
+
+(ert-deftest python-shell-prompt-set-calculated-regexps-2 ()
+ "Check `python-shell-prompt-input-regexps' are set."
+ (let* ((python-shell-prompt-input-regexps '("my" "prompt"))
+ (python-shell-prompt-output-regexps '(""))
+ (python-shell-prompt-regexp "")
+ (python-shell-prompt-block-regexp "")
+ (python-shell-prompt-pdb-regexp "")
+ (python-shell-prompt-output-regexp "")
+ (python-shell--prompt-calculated-input-regexp nil)
+ (python-shell--prompt-calculated-output-regexp nil)
+ (python-shell-prompt-detect-enabled nil))
+ (python-shell-prompt-set-calculated-regexps)
+ (should (string= python-shell--prompt-calculated-input-regexp
+ "^\\(prompt\\|my\\|\\)"))))
+
+(ert-deftest python-shell-prompt-set-calculated-regexps-3 ()
+ "Check `python-shell-prompt-output-regexps' are set."
+ (let* ((python-shell-prompt-input-regexps '(""))
+ (python-shell-prompt-output-regexps '("my" "prompt"))
+ (python-shell-prompt-regexp "")
+ (python-shell-prompt-block-regexp "")
+ (python-shell-prompt-pdb-regexp "")
+ (python-shell-prompt-output-regexp "")
+ (python-shell--prompt-calculated-input-regexp nil)
+ (python-shell--prompt-calculated-output-regexp nil)
+ (python-shell-prompt-detect-enabled nil))
+ (python-shell-prompt-set-calculated-regexps)
+ (should (string= python-shell--prompt-calculated-output-regexp
+ "^\\(prompt\\|my\\|\\)"))))
+
+(ert-deftest python-shell-prompt-set-calculated-regexps-4 ()
+ "Check user defined prompts are set."
+ (let* ((python-shell-prompt-input-regexps '(""))
+ (python-shell-prompt-output-regexps '(""))
+ (python-shell-prompt-regexp "prompt")
+ (python-shell-prompt-block-regexp "block")
+ (python-shell-prompt-pdb-regexp "pdb")
+ (python-shell-prompt-output-regexp "output")
+ (python-shell--prompt-calculated-input-regexp nil)
+ (python-shell--prompt-calculated-output-regexp nil)
+ (python-shell-prompt-detect-enabled nil))
+ (python-shell-prompt-set-calculated-regexps)
+ (should (string= python-shell--prompt-calculated-input-regexp
+ "^\\(prompt\\|block\\|pdb\\|\\)"))
+ (should (string= python-shell--prompt-calculated-output-regexp
+ "^\\(output\\|\\)"))))
+
+(ert-deftest python-shell-prompt-set-calculated-regexps-5 ()
+ "Check order of regexps (larger first)."
+ (let* ((python-shell-prompt-input-regexps '("extralargeinputprompt" "sml"))
+ (python-shell-prompt-output-regexps '("extralargeoutputprompt" "sml"))
+ (python-shell-prompt-regexp "in")
+ (python-shell-prompt-block-regexp "block")
+ (python-shell-prompt-pdb-regexp "pdf")
+ (python-shell-prompt-output-regexp "output")
+ (python-shell--prompt-calculated-input-regexp nil)
+ (python-shell--prompt-calculated-output-regexp nil)
+ (python-shell-prompt-detect-enabled nil))
+ (python-shell-prompt-set-calculated-regexps)
+ (should (string= python-shell--prompt-calculated-input-regexp
+ "^\\(extralargeinputprompt\\|block\\|pdf\\|sml\\|in\\)"))
+ (should (string= python-shell--prompt-calculated-output-regexp
+ "^\\(extralargeoutputprompt\\|output\\|sml\\)"))))
+
+(ert-deftest python-shell-prompt-set-calculated-regexps-6 ()
+ "Check detected prompts are included `regexp-quote'd."
+ (skip-unless (executable-find python-tests-shell-interpreter))
+ (let* ((python-shell-prompt-input-regexps '(""))
+ (python-shell-prompt-output-regexps '(""))
+ (python-shell-prompt-regexp "")
+ (python-shell-prompt-block-regexp "")
+ (python-shell-prompt-pdb-regexp "")
+ (python-shell-prompt-output-regexp "")
+ (python-shell--prompt-calculated-input-regexp nil)
+ (python-shell--prompt-calculated-output-regexp nil)
+ (python-shell-prompt-detect-enabled t)
+ (process-environment process-environment)
+ (startup-code (concat "import sys\n"
+ "sys.ps1 = 'p.> '\n"
+ "sys.ps2 = '..> '\n"
+ "sys.ps3 = 'o.t '\n"))
+ (startup-file (python-shell--save-temp-file startup-code)))
+ (unwind-protect
+ (progn
+ (setenv "PYTHONSTARTUP" startup-file)
+ (python-shell-prompt-set-calculated-regexps)
+ (should (string= python-shell--prompt-calculated-input-regexp
+ "^\\(\\.\\.> \\|p\\.> \\|\\)"))
+ (should (string= python-shell--prompt-calculated-output-regexp
+ "^\\(o\\.t \\|\\)")))
+ (ignore-errors (delete-file startup-file)))))
\f
;;; Shell completion
(python-shell-extra-pythonpaths "/home/user/pylib/")
(python-shell-completion-setup-code
. "from IPython.core.completerlib import module_completion")
- (python-shell-completion-module-string-code
- . "';'.join(module_completion('''%s'''))\n")
(python-shell-completion-string-code
. "';'.join(get_ipython().Completer.all_completions('''%s'''))\n")
(python-shell-virtualenv-path
(python-util-forward-comment -1)
(should (= (point) (point-min)))))
+(ert-deftest python-util-valid-regexp-p-1 ()
+ (should (python-util-valid-regexp-p ""))
+ (should (python-util-valid-regexp-p python-shell-prompt-regexp))
+ (should (not (python-util-valid-regexp-p "\\("))))
+
\f
;;; Electricity