Now on revision 111855. ------------------------------------------------------------ revno: 111855 committer: Glenn Morris branch nick: trunk timestamp: Thu 2013-02-21 21:33:42 -0500 message: Use derived-mode-p in previous change diff: === modified file 'lisp/textmodes/sgml-mode.el' --- lisp/textmodes/sgml-mode.el 2013-02-22 02:01:32 +0000 +++ lisp/textmodes/sgml-mode.el 2013-02-22 02:33:42 +0000 @@ -62,7 +62,7 @@ (set-default sym val) (mapc (lambda (buff) (with-current-buffer buff - (and (eq major-mode 'sgml-mode) + (and (derived-mode-p 'sgml-mode) (not sgml-xml-mode) (setq skeleton-transformation-function val)))) (buffer-list))) ------------------------------------------------------------ revno: 111854 committer: Glenn Morris branch nick: trunk timestamp: Thu 2013-02-21 21:01:32 -0500 message: Tweak for sgml-transformation-function * lisp/textmodes/sgml-mode.el (sgml-xml-mode): Move before use. (sgml-transformation-function): Give it a :set function. (sgml-tag): Doc fix. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-02-22 01:59:28 +0000 +++ lisp/ChangeLog 2013-02-22 02:01:32 +0000 @@ -1,5 +1,9 @@ 2013-02-22 Glenn Morris + * textmodes/sgml-mode.el (sgml-xml-mode): Move before use. + (sgml-transformation-function): Give it a :set function. + (sgml-tag): Doc fix. + * cmuscheme.el (scheme-buffer): * progmodes/inf-lisp.el (inferior-lisp-buffer): * progmodes/tcl.el (inferior-tcl-buffer): === modified file 'lisp/textmodes/sgml-mode.el' --- lisp/textmodes/sgml-mode.el 2013-01-11 23:08:55 +0000 +++ lisp/textmodes/sgml-mode.el 2013-02-22 02:01:32 +0000 @@ -46,9 +46,26 @@ :type 'integer :group 'sgml) +(defcustom sgml-xml-mode nil + "When non-nil, tag insertion functions will be XML-compliant. +It is set to be buffer-local when the file has +a DOCTYPE or an XML declaration." + :type 'boolean + :version "22.1" + :group 'sgml) + (defcustom sgml-transformation-function 'identity "Default value for `skeleton-transformation-function' in SGML mode." :type 'function + :initialize 'custom-initialize-default + :set (lambda (sym val) + (set-default sym val) + (mapc (lambda (buff) + (with-current-buffer buff + (and (eq major-mode 'sgml-mode) + (not sgml-xml-mode) + (setq skeleton-transformation-function val)))) + (buffer-list))) :group 'sgml) (put 'sgml-transformation-function 'variable-interactive @@ -364,14 +381,6 @@ (string :tag "Description"))) :group 'sgml) -(defcustom sgml-xml-mode nil - "When non-nil, tag insertion functions will be XML-compliant. -It is set to be buffer-local when the file has -a DOCTYPE or an XML declaration." - :type 'boolean - :version "22.1" - :group 'sgml) - (defvar sgml-empty-tags nil "List of tags whose !ELEMENT definition says EMPTY.") @@ -635,10 +644,8 @@ (define-skeleton sgml-tag "Prompt for a tag and insert it, optionally with attributes. Completion and configuration are done according to `sgml-tag-alist'. -If you like tags and attributes in uppercase do \\[set-variable] -`skeleton-transformation-function' RET `upcase' RET, or put this -in your `.emacs': - (setq sgml-transformation-function 'upcase)" +If you like tags and attributes in uppercase, customize +`sgml-transformation-function' to 'upcase." (funcall (or skeleton-transformation-function 'identity) (setq sgml-tag-last (completing-read ------------------------------------------------------------ revno: 111853 committer: Glenn Morris branch nick: trunk timestamp: Thu 2013-02-21 20:59:28 -0500 message: Doc fixes re set-variable * lisp/cmuscheme.el (scheme-buffer): * lisp/progmodes/inf-lisp.el (inferior-lisp-buffer): * lisp/progmodes/tcl.el (inferior-tcl-buffer): * lisp/textmodes/tex-mode.el (tex-command): Doc fixes. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-02-22 01:34:06 +0000 +++ lisp/ChangeLog 2013-02-22 01:59:28 +0000 @@ -1,5 +1,10 @@ 2013-02-22 Glenn Morris + * cmuscheme.el (scheme-buffer): + * progmodes/inf-lisp.el (inferior-lisp-buffer): + * progmodes/tcl.el (inferior-tcl-buffer): + * textmodes/tex-mode.el (tex-command): Doc fixes. + * image-mode.el (image-mode): Add mouse bindings for mode-line-process. * htmlfontify.el (hfy-default-header): Encode title string. (Bug#7457) === modified file 'lisp/cmuscheme.el' --- lisp/cmuscheme.el 2013-02-21 21:50:14 +0000 +++ lisp/cmuscheme.el 2013-02-22 01:59:28 +0000 @@ -478,8 +478,8 @@ Whenever \\[run-scheme] fires up a new process, it resets `scheme-buffer' to be the new process's buffer. If you only run one process, this will -do the right thing. If you run multiple processes, you can change -`scheme-buffer' to another process buffer with \\[set-variable]. +do the right thing. If you run multiple processes, you might need to +set `scheme-buffer' to whichever process buffer you want to use. More sophisticated approaches are, of course, possible. If you find yourself needing to switch back and forth between multiple processes frequently, === modified file 'lisp/progmodes/inf-lisp.el' --- lisp/progmodes/inf-lisp.el 2013-01-01 09:11:05 +0000 +++ lisp/progmodes/inf-lisp.el 2013-02-22 01:59:28 +0000 @@ -201,8 +201,8 @@ Whenever \\[inferior-lisp] fires up a new process, it resets `inferior-lisp-buffer' to be the new process's buffer. If you only run one process, this does the right thing. If you run multiple -processes, you can change `inferior-lisp-buffer' to another process -buffer with \\[set-variable].") +processes, you might need to change `inferior-lisp-buffer' to +whichever process buffer you want to use.") (defvar inferior-lisp-mode-hook '() "Hook for customizing Inferior Lisp mode.") === modified file 'lisp/progmodes/tcl.el' --- lisp/progmodes/tcl.el 2013-01-01 09:11:05 +0000 +++ lisp/progmodes/tcl.el 2013-02-22 01:59:28 +0000 @@ -332,8 +332,8 @@ Whenever \\[inferior-tcl] fires up a new process, it resets `inferior-tcl-buffer' to be the new process's buffer. If you only run one process, this does the right thing. If you run multiple -processes, you can change `inferior-tcl-buffer' to another process -buffer with \\[set-variable].") +processes, you might need to set `inferior-tcl-buffer' to +whichever process buffer you want to use.") ;; ;; Hooks and other customization. === modified file 'lisp/textmodes/tex-mode.el' --- lisp/textmodes/tex-mode.el 2013-01-02 16:13:04 +0000 +++ lisp/textmodes/tex-mode.el 2013-02-22 01:59:28 +0000 @@ -271,9 +271,7 @@ value of `tex-start-commands', and the file name are added at the end with blanks as separators. -In TeX, LaTeX, and SliTeX Mode this variable becomes buffer local. -In these modes, use \\[set-variable] if you want to change it for the -current buffer.") +In TeX, LaTeX, and SliTeX Mode this variable becomes buffer local.") (defvar tex-trailer nil "String appended after the end of a region sent to TeX by \\[tex-region].") ------------------------------------------------------------ revno: 111852 committer: Glenn Morris branch nick: trunk timestamp: Thu 2013-02-21 20:34:06 -0500 message: * lisp/image-mode.el (image-mode): Add mouse bindings for mode-line-process. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-02-22 01:32:45 +0000 +++ lisp/ChangeLog 2013-02-22 01:34:06 +0000 @@ -1,5 +1,7 @@ 2013-02-22 Glenn Morris + * image-mode.el (image-mode): Add mouse bindings for mode-line-process. + * htmlfontify.el (hfy-default-header): Encode title string. (Bug#7457) 2013-02-21 Bastien Guerry === modified file 'lisp/image-mode.el' --- lisp/image-mode.el 2013-02-20 07:57:33 +0000 +++ lisp/image-mode.el 2013-02-22 01:34:06 +0000 @@ -476,11 +476,22 @@ ((setq animated (image-multi-frame-p image)) (setq image-multi-frame t mode-line-process - `(:eval (propertize - (format " [%s/%s]" - (1+ (image-current-frame ',image)) - ,(car animated)) - 'help-echo "Frame number"))) + `(:eval + (concat " " + (propertize + (format "[%s/%s]" + (1+ (image-current-frame ',image)) + ,(car animated)) + 'help-echo "Frames +mouse-1: Next frame +mouse-3: Previous frame" + 'mouse-face 'mode-line-highlight + 'local-map + '(keymap + (mode-line + keymap + (down-mouse-1 . image-next-frame) + (down-mouse-3 . image-previous-frame))))))) (message "%s" (concat msg1 "text. This image has multiple frames."))) ;;; (substitute-command-keys ------------------------------------------------------------ revno: 111851 committer: Glenn Morris branch nick: trunk timestamp: Thu 2013-02-21 20:32:45 -0500 message: * lisp/htmlfontify.el (hfy-default-header): Encode title string. (Bug#7457) diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-02-21 21:50:14 +0000 +++ lisp/ChangeLog 2013-02-22 01:32:45 +0000 @@ -1,3 +1,7 @@ +2013-02-22 Glenn Morris + + * htmlfontify.el (hfy-default-header): Encode title string. (Bug#7457) + 2013-02-21 Bastien Guerry * cmuscheme.el (scheme-buffer): Fix docstring. (Bug#13778) === modified file 'lisp/htmlfontify.el' --- lisp/htmlfontify.el 2013-01-01 09:11:05 +0000 +++ lisp/htmlfontify.el 2013-02-22 01:32:45 +0000 @@ -717,7 +717,7 @@ --> \n" - file style)) + (mapconcat 'hfy-html-quote (mapcar 'char-to-string file) "") style)) (defun hfy-default-footer (_file) "Default value for `hfy-page-footer'. ------------------------------------------------------------ revno: 111850 committer: Paul Eggert branch nick: trunk timestamp: Thu 2013-02-21 14:42:56 -0800 message: Parallelize documentation builds. This speeds up building of documentation on multiprocessor platforms, and is motivated by Texinfo 5.0, which is much slower. Add a toplevel rule 'make docs' to make all the documentation. * .bzrignore: Add .dvi, .html, .ps. * Makefile.in (DVIS, HTMLS, INFOS, PSS, DOCS): New macros. ($(DOCS), docs, vi, html, pdf, ps): New rules. (info-real): Depend on $(INFOS) rather than doing it sequentially. (dvi): Depend on $(DVIS) rather than doing it sequentially. * doc/misc/Makefile.in (html): New rule. diff: === modified file '.bzrignore' --- .bzrignore 2013-02-11 23:37:18 +0000 +++ .bzrignore 2013-02-21 22:42:56 +0000 @@ -62,7 +62,10 @@ doc/**/*.tps doc/**/*.vr doc/**/*.vrs +doc/**/*.dvi +doc/**/*.html doc/**/*.pdf +doc/**/*.ps !doc/lispintro/cons-*.pdf !doc/lispintro/drawers.pdf !doc/lispintro/lambda-*.pdf === modified file 'ChangeLog' --- ChangeLog 2013-02-18 18:27:51 +0000 +++ ChangeLog 2013-02-21 22:42:56 +0000 @@ -1,3 +1,15 @@ +2013-02-21 Paul Eggert + + Parallelize documentation builds. + This speeds up building of documentation on multiprocessor + platforms, and is motivated by Texinfo 5.0, which is much slower. + Add a toplevel rule 'make docs' to make all the documentation. + * .bzrignore: Add .dvi, .html, .ps. + * Makefile.in (DVIS, HTMLS, INFOS, PSS, DOCS): New macros. + ($(DOCS), docs, vi, html, pdf, ps): New rules. + (info-real): Depend on $(INFOS) rather than doing it sequentially. + (dvi): Depend on $(DVIS) rather than doing it sequentially. + 2013-02-18 Aidan Gauland * doc/misc/eshell.texi: Added documentation for Eshell insert === modified file 'Makefile.in' --- Makefile.in 2013-01-19 20:38:13 +0000 +++ Makefile.in 2013-02-21 22:42:56 +0000 @@ -54,6 +54,9 @@ # make bootstrap # Removes all the compiled files to force a new bootstrap from a # clean slate, and then build in the normal way. +# +# make docs +# Make Emacs documentation files from their sources; requires makeinfo. SHELL = /bin/sh @@ -859,13 +862,25 @@ dist: cd ${srcdir}; ./make-dist +DVIS = lispref-dvi lispintro-dvi emacs-dvi misc-dvi +HTMLS = lispref-html lispintro-html emacs-html misc-html +INFOS = lispref-info lispintro-info emacs-info misc-info +PDFS = lispref-pdf lispintro-pdf emacs-pdf misc-pdf +PSS = lispref-ps lispintro-ps emacs-ps # no misc-ps + +DOCS = $(DVIS) $(HTMLS) $(INFOS) $(PDFS) $(PSS) +$(DOCS): + t=$@; IFS=-; set $$t; IFS=; cd doc/$$1 && $(MAKE) $(MFLAGS) $$2 + +.PHONY: $(DOCS) docs pdf ps .PHONY: info dvi dist check html info-real force-info check-info-dir -info-real: - (cd doc/emacs; $(MAKE) $(MFLAGS) info) - (cd doc/misc; $(MAKE) $(MFLAGS) info) - (cd doc/lispref; $(MAKE) $(MFLAGS) info) - (cd doc/lispintro; $(MAKE) $(MFLAGS) info) +docs: $(DOCS) +dvi: $(DVIS) +html: $(HTMLS) +info-real: $(INFOS) +pdf: $(PDFS) +ps: $(PSS) force-info: # Note that man/Makefile knows how to put the info files in $(srcdir), @@ -904,12 +919,6 @@ fi ; \ echo "info/dir is OK" -dvi: - (cd doc/emacs; $(MAKE) $(MFLAGS) dvi) - (cd doc/misc; $(MAKE) $(MFLAGS) dvi) - (cd doc/lispref; $(MAKE) $(MFLAGS) elisp.dvi) - (cd doc/lispintro; $(MAKE) $(MFLAGS) emacs-lisp-intro.dvi) - #### Bootstrapping. ### This first cleans the lisp subdirectory, removing all compiled === modified file 'doc/misc/ChangeLog' --- doc/misc/ChangeLog 2013-02-20 14:49:52 +0000 +++ doc/misc/ChangeLog 2013-02-21 22:42:56 +0000 @@ -1,3 +1,7 @@ +2013-02-21 Paul Eggert + + * Makefile.in (html): New rule. + 2013-02-20 Michael Albinus * tramp.texi (Android shell setup): Improve. Reported by Thierry === modified file 'doc/misc/Makefile.in' --- doc/misc/Makefile.in 2013-01-04 19:22:37 +0000 +++ doc/misc/Makefile.in 2013-02-21 22:42:56 +0000 @@ -192,6 +192,8 @@ dvi: $(DVI_TARGETS) +html: $(HTML_TARGETS) + pdf: $(PDF_TARGETS) # Note that all the Info targets build the Info files in srcdir. ------------------------------------------------------------ revno: 111849 committer: Bastien Guerry branch nick: trunk timestamp: Thu 2013-02-21 22:50:14 +0100 message: * cmuscheme.el (scheme-buffer): Fix docstring. Thanks to Xue Fuqiao for reporting this. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-02-21 16:56:49 +0000 +++ lisp/ChangeLog 2013-02-21 21:50:14 +0000 @@ -1,3 +1,7 @@ +2013-02-21 Bastien Guerry + + * cmuscheme.el (scheme-buffer): Fix docstring. (Bug#13778) + 2013-02-21 Fabián Ezequiel Gallina * progmodes/python.el (python-info-current-defun): Enhance === modified file 'lisp/cmuscheme.el' --- lisp/cmuscheme.el 2013-01-01 09:11:05 +0000 +++ lisp/cmuscheme.el 2013-02-21 21:50:14 +0000 @@ -447,7 +447,7 @@ "\"\)\n"))) -(defvar scheme-buffer nil "*The current scheme process buffer. +(defvar scheme-buffer nil "The current scheme process buffer. MULTIPLE PROCESS SUPPORT =========================================================================== ------------------------------------------------------------ revno: 111848 [merge] committer: Glenn Morris branch nick: trunk timestamp: Thu 2013-02-21 08:56:49 -0800 message: Merge from emacs-24; up to r111286 diff: === modified file 'etc/MORE.STUFF' --- etc/MORE.STUFF 2013-02-19 03:10:46 +0000 +++ etc/MORE.STUFF 2013-02-21 06:05:10 +0000 @@ -179,9 +179,6 @@ WhizzyTeX provides a minor mode for Emacs or XEmacs, a (bash) shell-script daemon and some LaTeX macros. - * X-Symbol: - Quasi-WYSIWYG editing of TeX & al. - Local Variables: mode: text eval: (view-mode 1) === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-02-21 14:23:12 +0000 +++ lisp/ChangeLog 2013-02-21 16:56:49 +0000 @@ -1,3 +1,18 @@ +2013-02-21 Fabián Ezequiel Gallina + + * progmodes/python.el (python-info-current-defun): Enhance + match-data cluttering prevention. + +2013-02-21 Glenn Morris + + * net/tramp.el (tramp-get-debug-buffer): Ensure outline.el is not + loaded while outline-regexp is let bound. (Bug#9584) + +2013-02-21 Fabián Ezequiel Gallina + + * progmodes/python.el (python-info-current-defun): Fix failed + defun name retrieval because of unwanted match-data cluttering. + 2013-02-21 Michael Albinus * net/tramp.el (tramp-ssh-controlmaster-template): Make it a === modified file 'lisp/net/tramp.el' --- lisp/net/tramp.el 2013-02-21 14:23:12 +0000 +++ lisp/net/tramp.el 2013-02-21 16:56:49 +0000 @@ -1354,6 +1354,8 @@ (get-buffer-create (tramp-debug-buffer-name vec)) (when (bobp) (setq buffer-undo-list t) + ;; So it does not get loaded while outline-regexp is let-bound. + (require 'outline) ;; Activate `outline-mode'. This runs `text-mode-hook' and ;; `outline-mode-hook'. We must prevent that local processes ;; die. Yes: I've seen `flyspell-mode', which starts "ispell". === modified file 'lisp/progmodes/python.el' --- lisp/progmodes/python.el 2013-02-19 03:29:28 +0000 +++ lisp/progmodes/python.el 2013-02-21 16:56:49 +0000 @@ -2959,39 +2959,40 @@ (type)) (catch 'exit (while (python-nav-beginning-of-defun 1) - (when (and - (or (not last-indent) - (< (current-indentation) last-indent)) - (or - (and first-run + (when (save-match-data + (and + (or (not last-indent) + (< (current-indentation) last-indent)) + (or + (and first-run + (save-excursion + ;; If this is the first run, we may add + ;; the current defun at point. + (setq first-run nil) + (goto-char starting-pos) + (python-nav-beginning-of-statement) + (beginning-of-line 1) + (looking-at-p + python-nav-beginning-of-defun-regexp))) + (< starting-pos (save-excursion - ;; If this is the first run, we may add - ;; the current defun at point. - (setq first-run nil) - (goto-char starting-pos) - (python-nav-beginning-of-statement) - (beginning-of-line 1) - (looking-at-p - python-nav-beginning-of-defun-regexp))) - (< starting-pos - (save-excursion - (let ((min-indent - (+ (current-indentation) - python-indent-offset))) - (if (< starting-indentation min-indent) - ;; If the starting indentation is not - ;; within the min defun indent make the - ;; check fail. - starting-pos - ;; Else go to the end of defun and add - ;; up the current indentation to the - ;; ending position. - (python-nav-end-of-defun) - (+ (point) - (if (>= (current-indentation) min-indent) - (1+ (current-indentation)) - 0)))))))) - (setq last-indent (current-indentation)) + (let ((min-indent + (+ (current-indentation) + python-indent-offset))) + (if (< starting-indentation min-indent) + ;; If the starting indentation is not + ;; within the min defun indent make the + ;; check fail. + starting-pos + ;; Else go to the end of defun and add + ;; up the current indentation to the + ;; ending position. + (python-nav-end-of-defun) + (+ (point) + (if (>= (current-indentation) min-indent) + (1+ (current-indentation)) + 0))))))))) + (save-match-data (setq last-indent (current-indentation))) (if (or (not include-type) type) (setq names (cons (match-string-no-properties 1) names)) (let ((match (split-string (match-string-no-properties 0)))) === modified file 'test/ChangeLog' --- test/ChangeLog 2013-02-14 05:45:33 +0000 +++ test/ChangeLog 2013-02-21 16:56:49 +0000 @@ -1,3 +1,7 @@ +2013-02-21 Fabián Ezequiel Gallina + + * automated/python-tests.el: New file. + 2013-02-14 Dmitry Gutov * automated/ruby-mode-tests.el === added file 'test/automated/python-tests.el' --- test/automated/python-tests.el 1970-01-01 00:00:00 +0000 +++ test/automated/python-tests.el 2013-02-20 20:27:08 +0000 @@ -0,0 +1,1947 @@ +;;; python-tests.el --- Test suite for python.el + +;; Copyright (C) 2013 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;;; Code: + +(require 'python) + +(defmacro python-tests-with-temp-buffer (contents &rest body) + "Create a `python-mode' enabeld temp buffer with CONTENTS. +BODY is code to be executed within the temp buffer. Point is +always located at the beginning of buffer." + (declare (indent 1) (debug t)) + `(with-temp-buffer + (python-mode) + (insert ,contents) + (goto-char (point-min)) + ,@body)) + +(defun python-tests-look-at (string &optional num restore-point) + "Move point at beginning of STRING in the current buffer. +Optional argument NUM defaults to 1 and is an integer indicating +how many ocurrences must be found, when positive the search is +done forwards, otherwise backwards. When RESTORE-POINT is +non-nil the point is not moved but the position found is still +returned. When searching forward and point is already looking at +STRING, it is skipped so the next STRING occurrence is selected." + (let* ((num (or num 1)) + (starting-point (point)) + (string (regexp-quote string)) + (search-fn (if (> num 0) #'re-search-forward #'re-search-backward)) + (deinc-fn (if (> num 0) #'1- #'1+)) + (found-point)) + (prog2 + (catch 'exit + (while (not (= num 0)) + (when (and (> num 0) + (looking-at string)) + ;; Moving forward and already looking at STRING, skip it. + (forward-char (length (match-string-no-properties 0)))) + (and (not (funcall search-fn string nil t)) + (throw 'exit t)) + (when (> num 0) + ;; `re-search-forward' leaves point at the end of the + ;; occurrence, move back so point is at the beginning + ;; instead. + (forward-char (- (length (match-string-no-properties 0))))) + (setq + num (funcall deinc-fn num) + found-point (point)))) + found-point + (and restore-point (goto-char starting-point))))) + + +;;; Tests for your tests, so you can test while you test. + +(ert-deftest python-tests-look-at-1 () + "Test forward movement." + (python-tests-with-temp-buffer + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna +aliqua." + (let ((expected (save-excursion + (dotimes (i 3) + (re-search-forward "et" nil t)) + (forward-char -2) + (point)))) + (should (= (python-tests-look-at "et" 3 t) expected)) + ;; Even if NUM is bigger than found occurrences the point of last + ;; one should be returned. + (should (= (python-tests-look-at "et" 6 t) expected)) + ;; If already looking at STRING, it should skip it. + (dotimes (i 2) (re-search-forward "et")) + (forward-char -2) + (should (= (python-tests-look-at "et") expected))))) + +(ert-deftest python-tests-look-at-2 () + "Test backward movement." + (python-tests-with-temp-buffer + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna +aliqua." + (let ((expected + (save-excursion + (re-search-forward "et" nil t) + (forward-char -2) + (point)))) + (dotimes (i 3) + (re-search-forward "et" nil t)) + (should (= (python-tests-look-at "et" -3 t) expected)) + (should (= (python-tests-look-at "et" -6 t) expected))))) + + +;;; Bindings + + +;;; Python specialized rx + + +;;; Font-lock and syntax + + +;;; Indentation + +;; See: http://www.python.org/dev/peps/pep-0008/#indentation + +(ert-deftest python-indent-pep8-1 () + "First pep8 case." + (python-tests-with-temp-buffer + "# Aligned with opening delimiter +foo = long_function_name(var_one, var_two, + var_three, var_four) +" + (should (eq (car (python-indent-context)) 'no-indent)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "foo = long_function_name(var_one, var_two,") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "var_three, var_four)") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 25)))) + +(ert-deftest python-indent-pep8-2 () + "Second pep8 case." + (python-tests-with-temp-buffer + "# More indentation included to distinguish this from the rest. +def long_function_name( + var_one, var_two, var_three, + var_four): + print (var_one) +" + (should (eq (car (python-indent-context)) 'no-indent)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "def long_function_name(") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "var_one, var_two, var_three,") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "var_four):") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "print (var_one)") + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 4)))) + +(ert-deftest python-indent-pep8-3 () + "Third pep8 case." + (python-tests-with-temp-buffer + "# Extra indentation is not necessary. +foo = long_function_name( + var_one, var_two, + var_three, var_four) +" + (should (eq (car (python-indent-context)) 'no-indent)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "foo = long_function_name(") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "var_one, var_two,") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "var_three, var_four)") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 4)))) + +(ert-deftest python-indent-inside-paren-1 () + "The most simple inside-paren case that shouldn't fail." + (python-tests-with-temp-buffer + " +data = { + 'key': + { + 'objlist': [ + { + 'pk': 1, + 'name': 'first', + }, + { + 'pk': 2, + 'name': 'second', + } + ] + } +} +" + (python-tests-look-at "data = {") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "'key':") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "{") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "'objlist': [") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "{") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 12)) + (python-tests-look-at "'pk': 1,") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 16)) + (python-tests-look-at "'name': 'first',") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 16)) + (python-tests-look-at "},") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 12)) + (python-tests-look-at "{") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 12)) + (python-tests-look-at "'pk': 2,") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 16)) + (python-tests-look-at "'name': 'second',") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 16)) + (python-tests-look-at "}") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 12)) + (python-tests-look-at "]") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "}") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "}") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 0)))) + +(ert-deftest python-indent-inside-paren-2 () + "Another more compact paren group style." + (python-tests-with-temp-buffer + " +data = {'key': { + 'objlist': [ + {'pk': 1, + 'name': 'first'}, + {'pk': 2, + 'name': 'second'} + ] +}} +" + (python-tests-look-at "data = {") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "'objlist': [") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "{'pk': 1,") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "'name': 'first'},") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 9)) + (python-tests-look-at "{'pk': 2,") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "'name': 'second'}") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 9)) + (python-tests-look-at "]") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "}}") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "}") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 0)))) + +(ert-deftest python-indent-after-block-1 () + "The most simple after-block case that shouldn't fail." + (python-tests-with-temp-buffer + " +def foo(a, b, c=True): +" + (should (eq (car (python-indent-context)) 'no-indent)) + (should (= (python-indent-calculate-indentation) 0)) + (goto-char (point-max)) + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 4)))) + +(ert-deftest python-indent-after-block-2 () + "A weird (malformed) multiline block statement." + (python-tests-with-temp-buffer + " +def foo(a, b, c={ + 'a': +}): +" + (goto-char (point-max)) + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 4)))) + +(ert-deftest python-indent-dedenters-1 () + "Check all dedenters." + (python-tests-with-temp-buffer + " +def foo(a, b, c): + if a: + print (a) + elif b: + print (b) + else: + try: + print (c.pop()) + except (IndexError, AttributeError): + print (c) + finally: + print ('nor a, nor b are true') +" + (python-tests-look-at "if a:") + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "print (a)") + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "elif b:") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "print (b)") + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "else:") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "try:") + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "print (c.pop())") + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 12)) + (python-tests-look-at "except (IndexError, AttributeError):") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "print (c)") + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 12)) + (python-tests-look-at "finally:") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 8)) + (python-tests-look-at "print ('nor a, nor b are true')") + (should (eq (car (python-indent-context)) 'after-beginning-of-block)) + (should (= (python-indent-calculate-indentation) 12)))) + +(ert-deftest python-indent-after-backslash-1 () + "The most common case." + (python-tests-with-temp-buffer + " +from foo.bar.baz import something, something_1 \\\\ + something_2 something_3, \\\\ + something_4, something_5 +" + (python-tests-look-at "from foo.bar.baz import something, something_1") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at "something_2 something_3,") + (should (eq (car (python-indent-context)) 'after-backslash)) + (should (= (python-indent-calculate-indentation) 4)) + (python-tests-look-at "something_4, something_5") + (should (eq (car (python-indent-context)) 'after-backslash)) + (should (= (python-indent-calculate-indentation) 4)) + (goto-char (point-max)) + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 0)))) + +(ert-deftest python-indent-after-backslash-2 () + "A pretty extreme complicated case." + (python-tests-with-temp-buffer + " +objects = Thing.objects.all() \\\\ + .filter( + type='toy', + status='bought' + ) \\\\ + .aggregate( + Sum('amount') + ) \\\\ + .values_list() +" + (python-tests-look-at "objects = Thing.objects.all()") + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 0)) + (python-tests-look-at ".filter(") + (should (eq (car (python-indent-context)) 'after-backslash)) + (should (= (python-indent-calculate-indentation) 23)) + (python-tests-look-at "type='toy',") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 27)) + (python-tests-look-at "status='bought'") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 27)) + (python-tests-look-at ") \\\\") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 23)) + (python-tests-look-at ".aggregate(") + (should (eq (car (python-indent-context)) 'after-backslash)) + (should (= (python-indent-calculate-indentation) 23)) + (python-tests-look-at "Sum('amount')") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 27)) + (python-tests-look-at ") \\\\") + (should (eq (car (python-indent-context)) 'inside-paren)) + (should (= (python-indent-calculate-indentation) 23)) + (python-tests-look-at ".values_list()") + (should (eq (car (python-indent-context)) 'after-backslash)) + (should (= (python-indent-calculate-indentation) 23)) + (forward-line 1) + (should (eq (car (python-indent-context)) 'after-line)) + (should (= (python-indent-calculate-indentation) 0)))) + + +;;; Navigation + +(ert-deftest python-nav-beginning-of-defun-1 () + (python-tests-with-temp-buffer + " +def decoratorFunctionWithArguments(arg1, arg2, arg3): + '''print decorated function call data to stdout. + + Usage: + + @decoratorFunctionWithArguments('arg1', 'arg2') + def func(a, b, c=True): + pass + ''' + + def wwrap(f): + print 'Inside wwrap()' + def wrapped_f(*args): + print 'Inside wrapped_f()' + print 'Decorator arguments:', arg1, arg2, arg3 + f(*args) + print 'After f(*args)' + return wrapped_f + return wwrap +" + (python-tests-look-at "return wrap") + (should (= (save-excursion + (python-nav-beginning-of-defun) + (point)) + (save-excursion + (python-tests-look-at "def wrapped_f(*args):" -1) + (beginning-of-line) + (point)))) + (python-tests-look-at "def wrapped_f(*args):" -1) + (should (= (save-excursion + (python-nav-beginning-of-defun) + (point)) + (save-excursion + (python-tests-look-at "def wwrap(f):" -1) + (beginning-of-line) + (point)))) + (python-tests-look-at "def wwrap(f):" -1) + (should (= (save-excursion + (python-nav-beginning-of-defun) + (point)) + (save-excursion + (python-tests-look-at "def decoratorFunctionWithArguments" -1) + (beginning-of-line) + (point)))))) + +(ert-deftest python-nav-beginning-of-defun-2 () + (python-tests-with-temp-buffer + " +class C(object): + + def m(self): + self.c() + + def b(): + pass + + def a(): + pass + + def c(self): + pass +" + ;; Nested defuns, are handled with care. + (python-tests-look-at "def c(self):") + (should (= (save-excursion + (python-nav-beginning-of-defun) + (point)) + (save-excursion + (python-tests-look-at "def m(self):" -1) + (beginning-of-line) + (point)))) + ;; Defuns on same levels should be respected. + (python-tests-look-at "def a():" -1) + (should (= (save-excursion + (python-nav-beginning-of-defun) + (point)) + (save-excursion + (python-tests-look-at "def b():" -1) + (beginning-of-line) + (point)))) + ;; Jump to a top level defun. + (python-tests-look-at "def b():" -1) + (should (= (save-excursion + (python-nav-beginning-of-defun) + (point)) + (save-excursion + (python-tests-look-at "def m(self):" -1) + (beginning-of-line) + (point)))) + ;; Jump to a top level defun again. + (python-tests-look-at "def m(self):" -1) + (should (= (save-excursion + (python-nav-beginning-of-defun) + (point)) + (save-excursion + (python-tests-look-at "class C(object):" -1) + (beginning-of-line) + (point)))))) + +(ert-deftest python-nav-end-of-defun-1 () + (python-tests-with-temp-buffer + " +class C(object): + + def m(self): + self.c() + + def b(): + pass + + def a(): + pass + + def c(self): + pass +" + (should (= (save-excursion + (python-tests-look-at "class C(object):") + (python-nav-end-of-defun) + (point)) + (save-excursion + (point-max)))) + (should (= (save-excursion + (python-tests-look-at "def m(self):") + (python-nav-end-of-defun) + (point)) + (save-excursion + (python-tests-look-at "def c(self):") + (forward-line -1) + (point)))) + (should (= (save-excursion + (python-tests-look-at "def b():") + (python-nav-end-of-defun) + (point)) + (save-excursion + (python-tests-look-at "def b():") + (forward-line 2) + (point)))) + (should (= (save-excursion + (python-tests-look-at "def c(self):") + (python-nav-end-of-defun) + (point)) + (save-excursion + (point-max)))))) + +(ert-deftest python-nav-end-of-defun-2 () + (python-tests-with-temp-buffer + " +def decoratorFunctionWithArguments(arg1, arg2, arg3): + '''print decorated function call data to stdout. + + Usage: + + @decoratorFunctionWithArguments('arg1', 'arg2') + def func(a, b, c=True): + pass + ''' + + def wwrap(f): + print 'Inside wwrap()' + def wrapped_f(*args): + print 'Inside wrapped_f()' + print 'Decorator arguments:', arg1, arg2, arg3 + f(*args) + print 'After f(*args)' + return wrapped_f + return wwrap +" + (should (= (save-excursion + (python-tests-look-at "def decoratorFunctionWithArguments") + (python-nav-end-of-defun) + (point)) + (save-excursion + (point-max)))) + (should (= (save-excursion + (python-tests-look-at "@decoratorFunctionWithArguments") + (python-nav-end-of-defun) + (point)) + (save-excursion + (point-max)))) + (should (= (save-excursion + (python-tests-look-at "def wwrap(f):") + (python-nav-end-of-defun) + (point)) + (save-excursion + (python-tests-look-at "return wwrap") + (line-beginning-position)))) + (should (= (save-excursion + (python-tests-look-at "def wrapped_f(*args):") + (python-nav-end-of-defun) + (point)) + (save-excursion + (python-tests-look-at "return wrapped_f") + (line-beginning-position)))) + (should (= (save-excursion + (python-tests-look-at "f(*args)") + (python-nav-end-of-defun) + (point)) + (save-excursion + (python-tests-look-at "return wrapped_f") + (line-beginning-position)))))) + + +(ert-deftest python-nav-beginning-of-statement-1 () + (python-tests-with-temp-buffer + " +v1 = 123 + \ + 456 + \ + 789 +v2 = (value1, + value2, + + value3, + value4) +v3 = ('this is a string' + + 'that is continued' + 'between lines' + 'within a paren', + # this is a comment, yo + 'continue previous line') +v4 = ''' +a very long +string +''' +" + (python-tests-look-at "v2 =") + (python-util-forward-comment -1) + (should (= (save-excursion + (python-nav-beginning-of-statement) + (point)) + (python-tests-look-at "v1 =" -1 t))) + (python-tests-look-at "v3 =") + (python-util-forward-comment -1) + (should (= (save-excursion + (python-nav-beginning-of-statement) + (point)) + (python-tests-look-at "v2 =" -1 t))) + (python-tests-look-at "v4 =") + (python-util-forward-comment -1) + (should (= (save-excursion + (python-nav-beginning-of-statement) + (point)) + (python-tests-look-at "v3 =" -1 t))) + (goto-char (point-max)) + (python-util-forward-comment -1) + (should (= (save-excursion + (python-nav-beginning-of-statement) + (point)) + (python-tests-look-at "v4 =" -1 t))))) + +(ert-deftest python-nav-end-of-statement-1 () + (python-tests-with-temp-buffer + " +v1 = 123 + \ + 456 + \ + 789 +v2 = (value1, + value2, + + value3, + value4) +v3 = ('this is a string' + + 'that is continued' + 'between lines' + 'within a paren', + # this is a comment, yo + 'continue previous line') +v4 = ''' +a very long +string +''' +" + (python-tests-look-at "v1 =") + (should (= (save-excursion + (python-nav-end-of-statement) + (point)) + (save-excursion + (python-tests-look-at "789") + (line-end-position)))) + (python-tests-look-at "v2 =") + (should (= (save-excursion + (python-nav-end-of-statement) + (point)) + (save-excursion + (python-tests-look-at "value4)") + (line-end-position)))) + (python-tests-look-at "v3 =") + (should (= (save-excursion + (python-nav-end-of-statement) + (point)) + (save-excursion + (python-tests-look-at + "'continue previous line')") + (line-end-position)))) + (python-tests-look-at "v4 =") + (should (= (save-excursion + (python-nav-end-of-statement) + (point)) + (save-excursion + (goto-char (point-max)) + (python-util-forward-comment -1) + (point)))))) + +(ert-deftest python-nav-forward-statement-1 () + (python-tests-with-temp-buffer + " +v1 = 123 + \ + 456 + \ + 789 +v2 = (value1, + value2, + + value3, + value4) +v3 = ('this is a string' + + 'that is continued' + 'between lines' + 'within a paren', + # this is a comment, yo + 'continue previous line') +v4 = ''' +a very long +string +''' +" + (python-tests-look-at "v1 =") + (should (= (save-excursion + (python-nav-forward-statement) + (point)) + (python-tests-look-at "v2 ="))) + (should (= (save-excursion + (python-nav-forward-statement) + (point)) + (python-tests-look-at "v3 ="))) + (should (= (save-excursion + (python-nav-forward-statement) + (point)) + (python-tests-look-at "v4 ="))) + (should (= (save-excursion + (python-nav-forward-statement) + (point)) + (point-max))))) + +(ert-deftest python-nav-backward-statement-1 () + (python-tests-with-temp-buffer + " +v1 = 123 + \ + 456 + \ + 789 +v2 = (value1, + value2, + + value3, + value4) +v3 = ('this is a string' + + 'that is continued' + 'between lines' + 'within a paren', + # this is a comment, yo + 'continue previous line') +v4 = ''' +a very long +string +''' +" + (goto-char (point-max)) + (should (= (save-excursion + (python-nav-backward-statement) + (point)) + (python-tests-look-at "v4 =" -1))) + (should (= (save-excursion + (python-nav-backward-statement) + (point)) + (python-tests-look-at "v3 =" -1))) + (should (= (save-excursion + (python-nav-backward-statement) + (point)) + (python-tests-look-at "v2 =" -1))) + (should (= (save-excursion + (python-nav-backward-statement) + (point)) + (python-tests-look-at "v1 =" -1))))) + +(ert-deftest python-nav-backward-statement-2 () + :expected-result :failed + (python-tests-with-temp-buffer + " +v1 = 123 + \ + 456 + \ + 789 +v2 = (value1, + value2, + + value3, + value4) +" + ;; FIXME: For some reason `python-nav-backward-statement' is moving + ;; back two sentences when starting from 'value4)'. + (goto-char (point-max)) + (python-util-forward-comment -1) + (should (= (save-excursion + (python-nav-backward-statement) + (point)) + (python-tests-look-at "v2 =" -1 t))))) + +(ert-deftest python-nav-beginning-of-block-1 () + (python-tests-with-temp-buffer + " +def decoratorFunctionWithArguments(arg1, arg2, arg3): + '''print decorated function call data to stdout. + + Usage: + + @decoratorFunctionWithArguments('arg1', 'arg2') + def func(a, b, c=True): + pass + ''' + + def wwrap(f): + print 'Inside wwrap()' + def wrapped_f(*args): + print 'Inside wrapped_f()' + print 'Decorator arguments:', arg1, arg2, arg3 + f(*args) + print 'After f(*args)' + return wrapped_f + return wwrap +" + (python-tests-look-at "return wwrap") + (should (= (save-excursion + (python-nav-beginning-of-block) + (point)) + (python-tests-look-at "def decoratorFunctionWithArguments" -1))) + (python-tests-look-at "print 'Inside wwrap()'") + (should (= (save-excursion + (python-nav-beginning-of-block) + (point)) + (python-tests-look-at "def wwrap(f):" -1))) + (python-tests-look-at "print 'After f(*args)'") + (end-of-line) + (should (= (save-excursion + (python-nav-beginning-of-block) + (point)) + (python-tests-look-at "def wrapped_f(*args):" -1))) + (python-tests-look-at "return wrapped_f") + (should (= (save-excursion + (python-nav-beginning-of-block) + (point)) + (python-tests-look-at "def wwrap(f):" -1))))) + +(ert-deftest python-nav-end-of-block-1 () + (python-tests-with-temp-buffer + " +def decoratorFunctionWithArguments(arg1, arg2, arg3): + '''print decorated function call data to stdout. + + Usage: + + @decoratorFunctionWithArguments('arg1', 'arg2') + def func(a, b, c=True): + pass + ''' + + def wwrap(f): + print 'Inside wwrap()' + def wrapped_f(*args): + print 'Inside wrapped_f()' + print 'Decorator arguments:', arg1, arg2, arg3 + f(*args) + print 'After f(*args)' + return wrapped_f + return wwrap +" + (python-tests-look-at "def decoratorFunctionWithArguments") + (should (= (save-excursion + (python-nav-end-of-block) + (point)) + (save-excursion + (goto-char (point-max)) + (python-util-forward-comment -1) + (point)))) + (python-tests-look-at "def wwrap(f):") + (should (= (save-excursion + (python-nav-end-of-block) + (point)) + (save-excursion + (python-tests-look-at "return wrapped_f") + (line-end-position)))) + (end-of-line) + (should (= (save-excursion + (python-nav-end-of-block) + (point)) + (save-excursion + (python-tests-look-at "return wrapped_f") + (line-end-position)))) + (python-tests-look-at "f(*args)") + (should (= (save-excursion + (python-nav-end-of-block) + (point)) + (save-excursion + (python-tests-look-at "print 'After f(*args)'") + (line-end-position)))))) + +(ert-deftest python-nav-forward-block-1 () + "This also accounts as a test for `python-nav-backward-block'." + (python-tests-with-temp-buffer + " +if request.user.is_authenticated(): + # def block(): + # pass + try: + profile = request.user.get_profile() + except Profile.DoesNotExist: + profile = Profile.objects.create(user=request.user) + else: + if profile.stats: + profile.recalculate_stats() + else: + profile.clear_stats() + finally: + profile.views += 1 + profile.save() +" + (should (= (save-excursion (python-nav-forward-block)) + (python-tests-look-at "if request.user.is_authenticated():"))) + (should (= (save-excursion (python-nav-forward-block)) + (python-tests-look-at "try:"))) + (should (= (save-excursion (python-nav-forward-block)) + (python-tests-look-at "except Profile.DoesNotExist:"))) + (should (= (save-excursion (python-nav-forward-block)) + (python-tests-look-at "else:"))) + (should (= (save-excursion (python-nav-forward-block)) + (python-tests-look-at "if profile.stats:"))) + (should (= (save-excursion (python-nav-forward-block)) + (python-tests-look-at "else:"))) + (should (= (save-excursion (python-nav-forward-block)) + (python-tests-look-at "finally:"))) + ;; When point is at the last block, leave it there and return nil + (should (not (save-excursion (python-nav-forward-block)))) + ;; Move backwards, and even if the number of moves is less than the + ;; provided argument return the point. + (should (= (save-excursion (python-nav-forward-block -10)) + (python-tests-look-at + "if request.user.is_authenticated():" -1))))) + +(ert-deftest python-nav-lisp-forward-sexp-safe-1 () + (python-tests-with-temp-buffer + " +profile = Profile.objects.create(user=request.user) +profile.notify() +" + (python-tests-look-at "profile =") + (python-nav-lisp-forward-sexp-safe 4) + (should (looking-at "(user=request.user)")) + (python-tests-look-at "user=request.user") + (python-nav-lisp-forward-sexp-safe -1) + (should (looking-at "(user=request.user)")) + (python-nav-lisp-forward-sexp-safe -4) + (should (looking-at "profile =")) + (python-tests-look-at "user=request.user") + (python-nav-lisp-forward-sexp-safe 3) + (should (looking-at ")")) + (python-nav-lisp-forward-sexp-safe 1) + (should (looking-at "$")) + (python-nav-lisp-forward-sexp-safe 1) + (should (looking-at ".notify()")))) + +(ert-deftest python-nav-forward-sexp-1 () + (python-tests-with-temp-buffer + " +a() +b() +c() +" + (python-tests-look-at "a()") + (python-nav-forward-sexp) + (should (looking-at "$")) + (should (save-excursion + (beginning-of-line) + (looking-at "a()"))) + (python-nav-forward-sexp) + (should (looking-at "$")) + (should (save-excursion + (beginning-of-line) + (looking-at "b()"))) + (python-nav-forward-sexp) + (should (looking-at "$")) + (should (save-excursion + (beginning-of-line) + (looking-at "c()"))) + ;; Movement next to a paren should do what lisp does and + ;; unfortunately It can't change, because otherwise + ;; `blink-matching-open' breaks. + (python-nav-forward-sexp -1) + (should (looking-at "()")) + (should (save-excursion + (beginning-of-line) + (looking-at "c()"))) + (python-nav-forward-sexp -1) + (should (looking-at "c()")) + (python-nav-forward-sexp -1) + (should (looking-at "b()")) + (python-nav-forward-sexp -1) + (should (looking-at "a()")))) + +(ert-deftest python-nav-forward-sexp-2 () + (python-tests-with-temp-buffer + " +def func(): + if True: + aaa = bbb + ccc = ddd + eee = fff + return ggg +" + (python-tests-look-at "aa =") + (python-nav-forward-sexp) + (should (looking-at " = bbb")) + (python-nav-forward-sexp) + (should (looking-at "$")) + (should (save-excursion + (back-to-indentation) + (looking-at "aaa = bbb"))) + (python-nav-forward-sexp) + (should (looking-at "$")) + (should (save-excursion + (back-to-indentation) + (looking-at "ccc = ddd"))) + (python-nav-forward-sexp) + (should (looking-at "$")) + (should (save-excursion + (back-to-indentation) + (looking-at "eee = fff"))) + (python-nav-forward-sexp) + (should (looking-at "$")) + (should (save-excursion + (back-to-indentation) + (looking-at "return ggg"))) + (python-nav-forward-sexp -1) + (should (looking-at "def func():")))) + +(ert-deftest python-nav-forward-sexp-3 () + (python-tests-with-temp-buffer + " +from some_module import some_sub_module +from another_module import another_sub_module + +def another_statement(): + pass +" + (python-tests-look-at "some_module") + (python-nav-forward-sexp) + (should (looking-at " import")) + (python-nav-forward-sexp) + (should (looking-at " some_sub_module")) + (python-nav-forward-sexp) + (should (looking-at "$")) + (should + (save-excursion + (back-to-indentation) + (looking-at + "from some_module import some_sub_module"))) + (python-nav-forward-sexp) + (should (looking-at "$")) + (should + (save-excursion + (back-to-indentation) + (looking-at + "from another_module import another_sub_module"))) + (python-nav-forward-sexp) + (should (looking-at "$")) + (should + (save-excursion + (back-to-indentation) + (looking-at + "pass"))) + (python-nav-forward-sexp -1) + (should (looking-at "def another_statement():")) + (python-nav-forward-sexp -1) + (should (looking-at "from another_module import another_sub_module")) + (python-nav-forward-sexp -1) + (should (looking-at "from some_module import some_sub_module")))) + +(ert-deftest python-nav-up-list-1 () + (python-tests-with-temp-buffer + " +def f(): + if True: + return [i for i in range(3)] +" + (python-tests-look-at "3)]") + (python-nav-up-list) + (should (looking-at "]")) + (python-nav-up-list) + (should (looking-at "$")))) + +(ert-deftest python-nav-backward-up-list-1 () + :expected-result :failed + (python-tests-with-temp-buffer + " +def f(): + if True: + return [i for i in range(3)] +" + (python-tests-look-at "3)]") + (python-nav-backward-up-list) + (should (looking-at "(3)\\]")) + (python-nav-backward-up-list) + (should (looking-at + "\\[i for i in range(3)\\]")) + ;; FIXME: Need to move to beginning-of-statement. + (python-nav-backward-up-list) + (should (looking-at + "return \\[i for i in range(3)\\]")) + (python-nav-backward-up-list) + (should (looking-at "if True:")) + (python-nav-backward-up-list) + (should (looking-at "def f():")))) + + +;;; Shell integration + + +;;; Shell completion + + +;;; PDB Track integration + + +;;; Symbol completion + + +;;; Fill paragraph + + +;;; Skeletons + + +;;; FFAP + + +;;; Code check + + +;;; Eldoc + + +;;; Imenu +(ert-deftest python-imenu-prev-index-position-1 () + (require 'imenu) + (python-tests-with-temp-buffer + " +def decoratorFunctionWithArguments(arg1, arg2, arg3): + '''print decorated function call data to stdout. + + Usage: + + @decoratorFunctionWithArguments('arg1', 'arg2') + def func(a, b, c=True): + pass + ''' + + def wwrap(f): + print 'Inside wwrap()' + def wrapped_f(*args): + print 'Inside wrapped_f()' + print 'Decorator arguments:', arg1, arg2, arg3 + f(*args) + print 'After f(*args)' + return wrapped_f + return wwrap + +def test(): # Some comment + 'This is a test function' + print 'test' + +class C(object): + + def m(self): + self.c() + + def b(): + pass + + def a(): + pass + + def c(self): + pass +" + (let ((expected + '(("*Rescan*" . -99) + ("decoratorFunctionWithArguments" . 2) + ("decoratorFunctionWithArguments.wwrap" . 224) + ("decoratorFunctionWithArguments.wwrap.wrapped_f" . 273) + ("test" . 500) + ("C" . 575) + ("C.m" . 593) + ("C.m.b" . 628) + ("C.m.a" . 663) + ("C.c" . 698)))) + (mapc + (lambda (elt) + (should (= (cdr (assoc-string (car elt) expected)) + (if (markerp (cdr elt)) + (marker-position (cdr elt)) + (cdr elt))))) + (imenu--make-index-alist))))) + + +;;; Misc helpers + +(ert-deftest python-info-current-defun-1 () + (python-tests-with-temp-buffer + " +def foo(a, b): +" + (forward-line 1) + (should (string= "foo" (python-info-current-defun))) + (should (string= "def foo" (python-info-current-defun t))) + (forward-line 1) + (should (not (python-info-current-defun))) + (indent-for-tab-command) + (should (string= "foo" (python-info-current-defun))) + (should (string= "def foo" (python-info-current-defun t))))) + +(ert-deftest python-info-current-defun-2 () + (python-tests-with-temp-buffer + " +class C(object): + + def m(self): + if True: + return [i for i in range(3)] + else: + return [] + + def b(): + pass + + def a(): + pass + + def c(self): + pass +" + (forward-line 1) + (should (string= "C" (python-info-current-defun))) + (should (string= "class C" (python-info-current-defun t))) + (python-tests-look-at "return [i for ") + (should (string= "C.m" (python-info-current-defun))) + (should (string= "def C.m" (python-info-current-defun t))) + (python-tests-look-at "def b():") + (should (string= "C.m.b" (python-info-current-defun))) + (should (string= "def C.m.b" (python-info-current-defun t))) + (forward-line 2) + (indent-for-tab-command) + (python-indent-dedent-line-backspace 1) + (should (string= "C.m" (python-info-current-defun))) + (should (string= "def C.m" (python-info-current-defun t))) + (python-tests-look-at "def c(self):") + (forward-line -1) + (indent-for-tab-command) + (should (string= "C.m.a" (python-info-current-defun))) + (should (string= "def C.m.a" (python-info-current-defun t))) + (python-indent-dedent-line-backspace 1) + (should (string= "C.m" (python-info-current-defun))) + (should (string= "def C.m" (python-info-current-defun t))) + (python-indent-dedent-line-backspace 1) + (should (string= "C" (python-info-current-defun))) + (should (string= "class C" (python-info-current-defun t))) + (python-tests-look-at "def c(self):") + (should (string= "C.c" (python-info-current-defun))) + (should (string= "def C.c" (python-info-current-defun t))) + (python-tests-look-at "pass") + (should (string= "C.c" (python-info-current-defun))) + (should (string= "def C.c" (python-info-current-defun t))))) + +(ert-deftest python-info-current-defun-3 () + (python-tests-with-temp-buffer + " +def decoratorFunctionWithArguments(arg1, arg2, arg3): + '''print decorated function call data to stdout. + + Usage: + + @decoratorFunctionWithArguments('arg1', 'arg2') + def func(a, b, c=True): + pass + ''' + + def wwrap(f): + print 'Inside wwrap()' + def wrapped_f(*args): + print 'Inside wrapped_f()' + print 'Decorator arguments:', arg1, arg2, arg3 + f(*args) + print 'After f(*args)' + return wrapped_f + return wwrap +" + (python-tests-look-at "def wwrap(f):") + (forward-line -1) + (should (not (python-info-current-defun))) + (indent-for-tab-command 1) + (should (string= (python-info-current-defun) + "decoratorFunctionWithArguments")) + (should (string= (python-info-current-defun t) + "def decoratorFunctionWithArguments")) + (python-tests-look-at "def wrapped_f(*args):") + (should (string= (python-info-current-defun) + "decoratorFunctionWithArguments.wwrap.wrapped_f")) + (should (string= (python-info-current-defun t) + "def decoratorFunctionWithArguments.wwrap.wrapped_f")) + (python-tests-look-at "return wrapped_f") + (should (string= (python-info-current-defun) + "decoratorFunctionWithArguments.wwrap")) + (should (string= (python-info-current-defun t) + "def decoratorFunctionWithArguments.wwrap")) + (end-of-line 1) + (python-tests-look-at "return wwrap") + (should (string= (python-info-current-defun) + "decoratorFunctionWithArguments")) + (should (string= (python-info-current-defun t) + "def decoratorFunctionWithArguments")))) + +(ert-deftest python-info-current-symbol-1 () + (python-tests-with-temp-buffer + " +class C(object): + + def m(self): + self.c() + + def c(self): + print ('a') +" + (python-tests-look-at "self.c()") + (should (string= "self.c" (python-info-current-symbol))) + (should (string= "C.c" (python-info-current-symbol t))))) + +(ert-deftest python-info-current-symbol-2 () + (python-tests-with-temp-buffer + " +class C(object): + + class M(object): + + def a(self): + self.c() + + def c(self): + pass +" + (python-tests-look-at "self.c()") + (should (string= "self.c" (python-info-current-symbol))) + (should (string= "C.M.c" (python-info-current-symbol t))))) + +(ert-deftest python-info-current-symbol-3 () + "Keywords should not be considered symbols." + :expected-result :failed + (python-tests-with-temp-buffer + " +class C(object): + pass +" + ;; FIXME: keywords are not symbols. + (python-tests-look-at "class C") + (should (not (python-info-current-symbol))) + (should (not (python-info-current-symbol t))) + (python-tests-look-at "C(object)") + (should (string= "C" (python-info-current-symbol))) + (should (string= "class C" (python-info-current-symbol t))))) + +(ert-deftest python-info-statement-starts-block-p-1 () + (python-tests-with-temp-buffer + " +def long_function_name( + var_one, var_two, var_three, + var_four): + print (var_one) +" + (python-tests-look-at "def long_function_name") + (should (python-info-statement-starts-block-p)) + (python-tests-look-at "print (var_one)") + (python-util-forward-comment -1) + (should (python-info-statement-starts-block-p)))) + +(ert-deftest python-info-statement-starts-block-p-2 () + (python-tests-with-temp-buffer + " +if width == 0 and height == 0 and \\\\ + color == 'red' and emphasis == 'strong' or \\\\ + highlight > 100: + raise ValueError('sorry, you lose') +" + (python-tests-look-at "if width == 0 and") + (should (python-info-statement-starts-block-p)) + (python-tests-look-at "raise ValueError(") + (python-util-forward-comment -1) + (should (python-info-statement-starts-block-p)))) + +(ert-deftest python-info-statement-ends-block-p-1 () + (python-tests-with-temp-buffer + " +def long_function_name( + var_one, var_two, var_three, + var_four): + print (var_one) +" + (python-tests-look-at "print (var_one)") + (should (python-info-statement-ends-block-p)))) + +(ert-deftest python-info-statement-ends-block-p-2 () + (python-tests-with-temp-buffer + " +if width == 0 and height == 0 and \\\\ + color == 'red' and emphasis == 'strong' or \\\\ + highlight > 100: + raise ValueError( +'sorry, you lose' + +) +" + (python-tests-look-at "raise ValueError(") + (should (python-info-statement-ends-block-p)))) + +(ert-deftest python-info-beginning-of-statement-p-1 () + (python-tests-with-temp-buffer + " +def long_function_name( + var_one, var_two, var_three, + var_four): + print (var_one) +" + (python-tests-look-at "def long_function_name") + (should (python-info-beginning-of-statement-p)) + (forward-char 10) + (should (not (python-info-beginning-of-statement-p))) + (python-tests-look-at "print (var_one)") + (should (python-info-beginning-of-statement-p)) + (goto-char (line-beginning-position)) + (should (not (python-info-beginning-of-statement-p))))) + +(ert-deftest python-info-beginning-of-statement-p-2 () + (python-tests-with-temp-buffer + " +if width == 0 and height == 0 and \\\\ + color == 'red' and emphasis == 'strong' or \\\\ + highlight > 100: + raise ValueError( +'sorry, you lose' + +) +" + (python-tests-look-at "if width == 0 and") + (should (python-info-beginning-of-statement-p)) + (forward-char 10) + (should (not (python-info-beginning-of-statement-p))) + (python-tests-look-at "raise ValueError(") + (should (python-info-beginning-of-statement-p)) + (goto-char (line-beginning-position)) + (should (not (python-info-beginning-of-statement-p))))) + +(ert-deftest python-info-end-of-statement-p-1 () + (python-tests-with-temp-buffer + " +def long_function_name( + var_one, var_two, var_three, + var_four): + print (var_one) +" + (python-tests-look-at "def long_function_name") + (should (not (python-info-end-of-statement-p))) + (end-of-line) + (should (not (python-info-end-of-statement-p))) + (python-tests-look-at "print (var_one)") + (python-util-forward-comment -1) + (should (python-info-end-of-statement-p)) + (python-tests-look-at "print (var_one)") + (should (not (python-info-end-of-statement-p))) + (end-of-line) + (should (python-info-end-of-statement-p)))) + +(ert-deftest python-info-end-of-statement-p-2 () + (python-tests-with-temp-buffer + " +if width == 0 and height == 0 and \\\\ + color == 'red' and emphasis == 'strong' or \\\\ + highlight > 100: + raise ValueError( +'sorry, you lose' + +) +" + (python-tests-look-at "if width == 0 and") + (should (not (python-info-end-of-statement-p))) + (end-of-line) + (should (not (python-info-end-of-statement-p))) + (python-tests-look-at "raise ValueError(") + (python-util-forward-comment -1) + (should (python-info-end-of-statement-p)) + (python-tests-look-at "raise ValueError(") + (should (not (python-info-end-of-statement-p))) + (end-of-line) + (should (not (python-info-end-of-statement-p))) + (goto-char (point-max)) + (python-util-forward-comment -1) + (should (python-info-end-of-statement-p)))) + +(ert-deftest python-info-beginning-of-block-p-1 () + (python-tests-with-temp-buffer + " +def long_function_name( + var_one, var_two, var_three, + var_four): + print (var_one) +" + (python-tests-look-at "def long_function_name") + (should (python-info-beginning-of-block-p)) + (python-tests-look-at "var_one, var_two, var_three,") + (should (not (python-info-beginning-of-block-p))) + (python-tests-look-at "print (var_one)") + (should (not (python-info-beginning-of-block-p))))) + +(ert-deftest python-info-beginning-of-block-p-2 () + (python-tests-with-temp-buffer + " +if width == 0 and height == 0 and \\\\ + color == 'red' and emphasis == 'strong' or \\\\ + highlight > 100: + raise ValueError( +'sorry, you lose' + +) +" + (python-tests-look-at "if width == 0 and") + (should (python-info-beginning-of-block-p)) + (python-tests-look-at "color == 'red' and emphasis") + (should (not (python-info-beginning-of-block-p))) + (python-tests-look-at "raise ValueError(") + (should (not (python-info-beginning-of-block-p))))) + +(ert-deftest python-info-end-of-block-p-1 () + (python-tests-with-temp-buffer + " +def long_function_name( + var_one, var_two, var_three, + var_four): + print (var_one) +" + (python-tests-look-at "def long_function_name") + (should (not (python-info-end-of-block-p))) + (python-tests-look-at "var_one, var_two, var_three,") + (should (not (python-info-end-of-block-p))) + (python-tests-look-at "var_four):") + (end-of-line) + (should (not (python-info-end-of-block-p))) + (python-tests-look-at "print (var_one)") + (should (not (python-info-end-of-block-p))) + (end-of-line 1) + (should (python-info-end-of-block-p)))) + +(ert-deftest python-info-end-of-block-p-2 () + (python-tests-with-temp-buffer + " +if width == 0 and height == 0 and \\\\ + color == 'red' and emphasis == 'strong' or \\\\ + highlight > 100: + raise ValueError( +'sorry, you lose' + +) +" + (python-tests-look-at "if width == 0 and") + (should (not (python-info-end-of-block-p))) + (python-tests-look-at "color == 'red' and emphasis == 'strong' or") + (should (not (python-info-end-of-block-p))) + (python-tests-look-at "highlight > 100:") + (end-of-line) + (should (not (python-info-end-of-block-p))) + (python-tests-look-at "raise ValueError(") + (should (not (python-info-end-of-block-p))) + (end-of-line 1) + (should (not (python-info-end-of-block-p))) + (goto-char (point-max)) + (python-util-forward-comment -1) + (should (python-info-end-of-block-p)))) + +(ert-deftest python-info-closing-block-1 () + (python-tests-with-temp-buffer + " +if request.user.is_authenticated(): + try: + profile = request.user.get_profile() + except Profile.DoesNotExist: + profile = Profile.objects.create(user=request.user) + else: + if profile.stats: + profile.recalculate_stats() + else: + profile.clear_stats() + finally: + profile.views += 1 + profile.save() +" + (python-tests-look-at "try:") + (should (not (python-info-closing-block))) + (python-tests-look-at "except Profile.DoesNotExist:") + (should (= (python-tests-look-at "try:" -1 t) + (python-info-closing-block))) + (python-tests-look-at "else:") + (should (= (python-tests-look-at "except Profile.DoesNotExist:" -1 t) + (python-info-closing-block))) + (python-tests-look-at "if profile.stats:") + (should (not (python-info-closing-block))) + (python-tests-look-at "else:") + (should (= (python-tests-look-at "if profile.stats:" -1 t) + (python-info-closing-block))) + (python-tests-look-at "finally:") + (should (= (python-tests-look-at "else:" -2 t) + (python-info-closing-block))))) + +(ert-deftest python-info-closing-block-2 () + (python-tests-with-temp-buffer + " +if request.user.is_authenticated(): + profile = Profile.objects.get_or_create(user=request.user) + if profile.stats: + profile.recalculate_stats() + +data = { + 'else': 'do it' +} + 'else' +" + (python-tests-look-at "'else': 'do it'") + (should (not (python-info-closing-block))) + (python-tests-look-at "'else'") + (should (not (python-info-closing-block))))) + +(ert-deftest python-info-line-ends-backslash-p-1 () + (python-tests-with-temp-buffer + " +objects = Thing.objects.all() \\\\ + .filter( + type='toy', + status='bought' + ) \\\\ + .aggregate( + Sum('amount') + ) \\\\ + .values_list() +" + (should (python-info-line-ends-backslash-p 2)) ; .filter(... + (should (python-info-line-ends-backslash-p 3)) + (should (python-info-line-ends-backslash-p 4)) + (should (python-info-line-ends-backslash-p 5)) + (should (python-info-line-ends-backslash-p 6)) ; ) \... + (should (python-info-line-ends-backslash-p 7)) + (should (python-info-line-ends-backslash-p 8)) + (should (python-info-line-ends-backslash-p 9)) + (should (not (python-info-line-ends-backslash-p 10))))) ; .values_list()... + +(ert-deftest python-info-beginning-of-backslash-1 () + (python-tests-with-temp-buffer + " +objects = Thing.objects.all() \\\\ + .filter( + type='toy', + status='bought' + ) \\\\ + .aggregate( + Sum('amount') + ) \\\\ + .values_list() +" + (let ((first 2) + (second (python-tests-look-at ".filter(")) + (third (python-tests-look-at ".aggregate("))) + (should (= first (python-info-beginning-of-backslash 2))) + (should (= second (python-info-beginning-of-backslash 3))) + (should (= second (python-info-beginning-of-backslash 4))) + (should (= second (python-info-beginning-of-backslash 5))) + (should (= second (python-info-beginning-of-backslash 6))) + (should (= third (python-info-beginning-of-backslash 7))) + (should (= third (python-info-beginning-of-backslash 8))) + (should (= third (python-info-beginning-of-backslash 9))) + (should (not (python-info-beginning-of-backslash 10)))))) + +(ert-deftest python-info-continuation-line-p-1 () + (python-tests-with-temp-buffer + " +if width == 0 and height == 0 and \\\\ + color == 'red' and emphasis == 'strong' or \\\\ + highlight > 100: + raise ValueError( +'sorry, you lose' + +) +" + (python-tests-look-at "if width == 0 and height == 0 and") + (should (not (python-info-continuation-line-p))) + (python-tests-look-at "color == 'red' and emphasis == 'strong' or") + (should (python-info-continuation-line-p)) + (python-tests-look-at "highlight > 100:") + (should (python-info-continuation-line-p)) + (python-tests-look-at "raise ValueError(") + (should (not (python-info-continuation-line-p))) + (python-tests-look-at "'sorry, you lose'") + (should (python-info-continuation-line-p)) + (forward-line 1) + (should (python-info-continuation-line-p)) + (python-tests-look-at ")") + (should (python-info-continuation-line-p)) + (forward-line 1) + (should (not (python-info-continuation-line-p))))) + +(ert-deftest python-info-block-continuation-line-p-1 () + (python-tests-with-temp-buffer + " +if width == 0 and height == 0 and \\\\ + color == 'red' and emphasis == 'strong' or \\\\ + highlight > 100: + raise ValueError( +'sorry, you lose' + +) +" + (python-tests-look-at "if width == 0 and") + (should (not (python-info-block-continuation-line-p))) + (python-tests-look-at "color == 'red' and emphasis == 'strong' or") + (should (= (python-info-block-continuation-line-p) + (python-tests-look-at "if width == 0 and" -1 t))) + (python-tests-look-at "highlight > 100:") + (should (not (python-info-block-continuation-line-p))))) + +(ert-deftest python-info-block-continuation-line-p-2 () + (python-tests-with-temp-buffer + " +def foo(a, + b, + c): + pass +" + (python-tests-look-at "def foo(a,") + (should (not (python-info-block-continuation-line-p))) + (python-tests-look-at "b,") + (should (= (python-info-block-continuation-line-p) + (python-tests-look-at "def foo(a," -1 t))) + (python-tests-look-at "c):") + (should (not (python-info-block-continuation-line-p))))) + +(ert-deftest python-info-assignment-continuation-line-p-1 () + (python-tests-with-temp-buffer + " +data = foo(), bar() \\\\ + baz(), 4 \\\\ + 5, 6 +" + (python-tests-look-at "data = foo(), bar()") + (should (not (python-info-assignment-continuation-line-p))) + (python-tests-look-at "baz(), 4") + (should (= (python-info-assignment-continuation-line-p) + (python-tests-look-at "foo()," -1 t))) + (python-tests-look-at "5, 6") + (should (not (python-info-assignment-continuation-line-p))))) + +(ert-deftest python-info-assignment-continuation-line-p-2 () + (python-tests-with-temp-buffer + " +data = (foo(), bar() + baz(), 4 + 5, 6) +" + (python-tests-look-at "data = (foo(), bar()") + (should (not (python-info-assignment-continuation-line-p))) + (python-tests-look-at "baz(), 4") + (should (= (python-info-assignment-continuation-line-p) + (python-tests-look-at "(foo()," -1 t))) + (python-tests-look-at "5, 6)") + (should (not (python-info-assignment-continuation-line-p))))) + +(ert-deftest python-info-looking-at-beginning-of-defun-1 () + (python-tests-with-temp-buffer + " +def decorat0r(deff): + '''decorates stuff. + + @decorat0r + def foo(arg): + ... + ''' + def wrap(): + deff() + return wwrap +" + (python-tests-look-at "def decorat0r(deff):") + (should (python-info-looking-at-beginning-of-defun)) + (python-tests-look-at "def foo(arg):") + (should (not (python-info-looking-at-beginning-of-defun))) + (python-tests-look-at "def wrap():") + (should (python-info-looking-at-beginning-of-defun)) + (python-tests-look-at "deff()") + (should (not (python-info-looking-at-beginning-of-defun))))) + +(ert-deftest python-info-current-line-comment-p-1 () + (python-tests-with-temp-buffer + " +# this is a comment +foo = True # another comment +'#this is a string' +if foo: + # more comments + print ('bar') # print bar +" + (python-tests-look-at "# this is a comment") + (should (python-info-current-line-comment-p)) + (python-tests-look-at "foo = True # another comment") + (should (not (python-info-current-line-comment-p))) + (python-tests-look-at "'#this is a string'") + (should (not (python-info-current-line-comment-p))) + (python-tests-look-at "# more comments") + (should (python-info-current-line-comment-p)) + (python-tests-look-at "print ('bar') # print bar") + (should (not (python-info-current-line-comment-p))))) + +(ert-deftest python-info-current-line-empty-p () + (python-tests-with-temp-buffer + " +# this is a comment + +foo = True # another comment +" + (should (python-info-current-line-empty-p)) + (python-tests-look-at "# this is a comment") + (should (not (python-info-current-line-empty-p))) + (forward-line 1) + (should (python-info-current-line-empty-p)))) + + +;;; Utility functions + +(ert-deftest python-util-goto-line-1 () + (python-tests-with-temp-buffer + (concat + "# a comment +# another comment +def foo(a, b, c): + pass" (make-string 20 ?\n)) + (python-util-goto-line 10) + (should (= (line-number-at-pos) 10)) + (python-util-goto-line 20) + (should (= (line-number-at-pos) 20)))) + +(ert-deftest python-util-clone-local-variables-1 () + (let ((buffer (generate-new-buffer + "python-util-clone-local-variables-1")) + (varcons + '((python-fill-docstring-style . django) + (python-shell-interpreter . "python") + (python-shell-interpreter-args . "manage.py shell") + (python-shell-prompt-regexp . "In \\[[0-9]+\\]: ") + (python-shell-prompt-output-regexp . "Out\\[[0-9]+\\]: ") + (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 + . "/home/user/.virtualenvs/project")))) + (with-current-buffer buffer + (kill-all-local-variables) + (dolist (ccons varcons) + (set (make-local-variable (car ccons)) (cdr ccons)))) + (python-tests-with-temp-buffer + "" + (python-util-clone-local-variables buffer) + (dolist (ccons varcons) + (should + (equal (symbol-value (car ccons)) (cdr ccons))))) + (kill-buffer buffer))) + +(ert-deftest python-util-forward-comment-1 () + (python-tests-with-temp-buffer + (concat + "# a comment +# another comment + # bad indented comment +# more comments" (make-string 9999 ?\n)) + (python-util-forward-comment 1) + (should (= (point) (point-max))) + (python-util-forward-comment -1) + (should (= (point) (point-min))))) + + +(provide 'python-tests) + +;; Local Variables: +;; coding: utf-8 +;; indent-tabs-mode: nil +;; End: + +;;; python-tests.el ends here ------------------------------------------------------------ revno: 111847 committer: Michael Albinus + * net/tramp.el (tramp-ssh-controlmaster-template): Make it a + defconst. Apply independent check for ControlPersist. + * net/tramp-sh.el (tramp-sh-handle-set-file-times): Set $UTC only temporarily, via "env". === modified file 'lisp/net/tramp.el' --- lisp/net/tramp.el 2013-02-14 13:32:04 +0000 +++ lisp/net/tramp.el 2013-02-21 14:23:12 +0000 @@ -281,16 +281,24 @@ useful only in combination with `tramp-default-proxies-alist'.") ;;;###tramp-autoload -(defvar tramp-ssh-controlmaster-template +(defconst tramp-ssh-controlmaster-template + (let (result) (ignore-errors (with-temp-buffer (call-process "ssh" nil t nil "-o" "ControlMaster") (goto-char (point-min)) (when (search-forward-regexp "Missing ControlMaster argument" nil t) - '("-o" "ControlPath=%t.%%r@%%h:%%p" - "-o" "ControlMaster=auto" - "-o" "ControlPersist=no")))) - "Call ssh to detect whether it supports the ControlMaster argument. + (setq result + '("-o" "ControlPath=%t.%%r@%%h:%%p" + "-o" "ControlMaster=auto")))) + (when result + (with-temp-buffer + (call-process "ssh" nil t nil "-o" "ControlPersist") + (goto-char (point-min)) + (when (search-forward-regexp "Missing ControlPersist argument" nil t) + (setq result (append result '("-o" "ControlPersist=no"))))))) + result) + "Call ssh to detect whether it supports the Control* arguments. Return a template to be used in `tramp-methods'.") (defcustom tramp-default-method ------------------------------------------------------------ revno: 111846 committer: Michael Albinus + + * net/tramp-sh.el (tramp-sh-handle-set-file-times): Set $UTC only + temporarily, via "env". + 2013-02-21 Glenn Morris * info.el (Info-enable-edit): Remove. === modified file 'lisp/net/tramp-sh.el' --- lisp/net/tramp-sh.el 2013-02-19 03:29:28 +0000 +++ lisp/net/tramp-sh.el 2013-02-21 13:36:16 +0000 @@ -1410,7 +1410,7 @@ (utc (not (featurep 'xemacs)))) (tramp-send-command-and-check v (format "%s touch -t %s %s" - (if utc "TZ=UTC; export TZ;" "") + (if utc "env TZ=UTC" "") (if utc (format-time-string "%Y%m%d%H%M.%S" time t) (format-time-string "%Y%m%d%H%M.%S" time)) ------------------------------------------------------------ revno: 111845 committer: Glenn Morris branch nick: trunk timestamp: Wed 2013-02-20 22:55:19 -0800 message: Make Info-edit obsolete Ref: http://lists.gnu.org/archive/html/emacs-devel/2012-01/msg00374.html (Warning: interminable bikeshedding in thread) * lisp/info.el (Info-enable-edit): Remove. (Info-edit): Disable it rather than using Info-enable. (Info-edit-mode-hook, Info-edit-map, Info-edit-mode, Info-edit) (Info-cease-edit): Make editing of Info files obsolete. * etc/NEWS: Mention this. diff: === modified file 'etc/NEWS' --- etc/NEWS 2013-02-21 06:03:02 +0000 +++ etc/NEWS 2013-02-21 06:55:19 +0000 @@ -218,6 +218,10 @@ +++ *** yow.el is obsolete; use fortune.el or cookie1.el instead. +--- +*** The Info-edit command is obsolete. Editing Info nodes by hand +has not been relevant for some time. + * New Modes and Packages in Emacs 24.4 ** New nadvice.el package offering lighter-weight advice facilities. === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-02-21 06:39:04 +0000 +++ lisp/ChangeLog 2013-02-21 06:55:19 +0000 @@ -1,5 +1,10 @@ 2013-02-21 Glenn Morris + * info.el (Info-enable-edit): Remove. + (Info-edit): Disable it rather than using Info-enable. + (Info-edit-mode-hook, Info-edit-map, Info-edit-mode, Info-edit) + (Info-cease-edit): Make editing of Info files obsolete. + * informat.el (Info-tagify): Handle buffers not visiting files. (Bug#13763) === modified file 'lisp/info.el' --- lisp/info.el 2013-02-14 09:15:55 +0000 +++ lisp/info.el 2013-02-21 06:55:19 +0000 @@ -59,15 +59,6 @@ :group 'info :version "24.1") -(defcustom Info-enable-edit nil - "Non-nil means the \\\\[Info-edit] command in Info can edit the current node. -This is convenient if you want to write Info files by hand. -However, we recommend that you not do this. -It is better to write a Texinfo file and generate the Info file from that, -because that gives you a printed manual as well." - :type 'boolean - :group 'info) - (defvar Info-enable-active-nodes nil "Non-nil allows Info to execute Lisp code associated with nodes. The Lisp code is executed when the node is selected.") @@ -375,6 +366,9 @@ (defvar Info-edit-mode-hook nil "Hooks run when `Info-edit-mode' is called.") +(make-obsolete-variable 'Info-edit-mode-hook + "editing Info nodes by hand is not recommended." "24.4") + (defvar Info-current-file nil "Info file that Info is now looking at, or nil. This is the name that was specified in Info, not the actual file name. @@ -4253,6 +4247,10 @@ map) "Local keymap used within `e' command of Info.") +(make-obsolete-variable 'Info-edit-map + "editing Info nodes by hand is not recommended." + "24.4") + ;; Info-edit mode is suitable only for specially formatted data. (put 'Info-edit-mode 'mode-class 'special) @@ -4270,16 +4268,22 @@ (buffer-enable-undo (current-buffer)) (run-mode-hooks 'Info-edit-mode-hook)) +(make-obsolete 'Info-edit-mode + "editing Info nodes by hand is not recommended." "24.4") + (defun Info-edit () - "Edit the contents of this Info node. -Allowed only if variable `Info-enable-edit' is non-nil." + "Edit the contents of this Info node." (interactive) - (or Info-enable-edit - (error "Editing Info nodes is not enabled")) (Info-edit-mode) (message "%s" (substitute-command-keys "Editing: Type \\\\[Info-cease-edit] to return to info"))) +(put 'Info-edit 'disabled "Editing Info nodes by hand is not recommended. +This feature will be removed in future.") + +(make-obsolete 'Info-edit + "editing Info nodes by hand is not recommended." "24.4") + (defun Info-cease-edit () "Finish editing Info node; switch back to Info proper." (interactive) @@ -4296,6 +4300,9 @@ (and (marker-position Info-tag-table-marker) (buffer-modified-p) (message "Tags may have changed. Use Info-tagify if necessary"))) + +(make-obsolete 'Info-cease-edit + "editing Info nodes by hand is not recommended." "24.4") (defvar Info-file-list-for-emacs '("ediff" "eudc" "forms" "gnus" "info" ("Info" . "info") ("mh" . "mh-e") ------------------------------------------------------------ Use --include-merged or -n0 to see merged revisions.