Fix hideshow integration.
Fixes: debbugs:19761 * lisp/progmodes/python.el (python-hideshow-forward-sexp-function): New function based on Carlos Pita <carlosjosepita@gmail.com> patch. (python-mode): Make `hs-special-modes-alist` use it and initialize the end regexp with the empty string to avoid skipping parens. * test/automated/python-tests.el (python-tests-visible-string): New function. (python-parens-electric-indent-1) (python-triple-quote-pairing): Fix indentation, move require calls. (python-hideshow-hide-levels-1) (python-hideshow-hide-levels-2): New tests.
This commit is contained in:
parent
86c50b9af1
commit
2d467a0ff0
4 changed files with 193 additions and 50 deletions
|
@ -1,3 +1,13 @@
|
|||
2015-02-07 Fabián Ezequiel Gallina <fgallina@gnu.org>
|
||||
|
||||
Fix hideshow integration. (Bug#19761)
|
||||
|
||||
* progmodes/python.el
|
||||
(python-hideshow-forward-sexp-function): New function based on
|
||||
Carlos Pita <carlosjosepita@gmail.com> patch.
|
||||
(python-mode): Make `hs-special-modes-alist` use it and initialize
|
||||
the end regexp with the empty string to avoid skipping parens.
|
||||
|
||||
2015-02-07 Fabián Ezequiel Gallina <fgallina@gnu.org>
|
||||
|
||||
* progmodes/python.el (python-check-custom-command): Do not use
|
||||
|
|
|
@ -3957,6 +3957,17 @@ Interactively, prompt for symbol."
|
|||
nil nil symbol))))
|
||||
(message (python-eldoc--get-doc-at-point symbol)))
|
||||
|
||||
|
||||
;;; Hideshow
|
||||
|
||||
(defun python-hideshow-forward-sexp-function (arg)
|
||||
"Python specific `forward-sexp' function for `hs-minor-mode'.
|
||||
Argument ARG is ignored."
|
||||
arg ; Shut up, byte compiler.
|
||||
(python-nav-end-of-defun)
|
||||
(unless (python-info-current-line-empty-p)
|
||||
(backward-char)))
|
||||
|
||||
|
||||
;;; Imenu
|
||||
|
||||
|
@ -4693,11 +4704,16 @@ Arguments START and END narrow the buffer region to work on."
|
|||
(add-function :before-until (local 'eldoc-documentation-function)
|
||||
#'python-eldoc-function))
|
||||
|
||||
(add-to-list 'hs-special-modes-alist
|
||||
`(python-mode "^\\s-*\\(?:def\\|class\\)\\>" nil "#"
|
||||
,(lambda (_arg)
|
||||
(python-nav-end-of-defun))
|
||||
nil))
|
||||
(add-to-list
|
||||
'hs-special-modes-alist
|
||||
`(python-mode
|
||||
"\\s-*\\(?:def\\|class\\)\\>"
|
||||
;; Use the empty string as end regexp so it doesn't default to
|
||||
;; "\\s)". This way parens at end of defun are properly hidden.
|
||||
""
|
||||
"#"
|
||||
python-hideshow-forward-sexp-function
|
||||
nil))
|
||||
|
||||
(set (make-local-variable 'outline-regexp)
|
||||
(python-rx (* space) block-start))
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
2015-02-07 Fabián Ezequiel Gallina <fgallina@gnu.org>
|
||||
|
||||
* automated/python-tests.el
|
||||
(python-tests-visible-string): New function.
|
||||
(python-parens-electric-indent-1)
|
||||
(python-triple-quote-pairing): Fix indentation, move require calls.
|
||||
(python-hideshow-hide-levels-1)
|
||||
(python-hideshow-hide-levels-2): New tests.
|
||||
|
||||
2015-02-07 Dmitry Gutov <dgutov@yandex.ru>
|
||||
|
||||
* automated/vc-tests.el (vc-test--working-revision): Fix
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
(require 'ert)
|
||||
(require 'python)
|
||||
|
||||
;; Dependencies for testing:
|
||||
(require 'electric)
|
||||
(require 'hideshow)
|
||||
|
||||
|
||||
(defmacro python-tests-with-temp-buffer (contents &rest body)
|
||||
"Create a `python-mode' enabled temp buffer with CONTENTS.
|
||||
BODY is code to be executed within the temp buffer. Point is
|
||||
|
@ -104,6 +109,28 @@ STRING, it is skipped so the next STRING occurrence is selected."
|
|||
(call-interactively 'self-insert-command)))
|
||||
chars)))
|
||||
|
||||
(defun python-tests-visible-string (&optional min max)
|
||||
"Return the buffer string excluding invisible overlays.
|
||||
Argument MIN and MAX delimit the region to be returned and
|
||||
default to `point-min' and `point-max' respectively."
|
||||
(let* ((min (or min (point-min)))
|
||||
(max (or max (point-max)))
|
||||
(buffer (current-buffer))
|
||||
(buffer-contents (buffer-substring-no-properties min max))
|
||||
(overlays
|
||||
(sort (overlays-in min max)
|
||||
(lambda (a b)
|
||||
(let ((overlay-end-a (overlay-end a))
|
||||
(overlay-end-b (overlay-end b)))
|
||||
(> overlay-end-a overlay-end-b))))))
|
||||
(with-temp-buffer
|
||||
(insert buffer-contents)
|
||||
(dolist (overlay overlays)
|
||||
(if (overlay-get overlay 'invisible)
|
||||
(delete-region (overlay-start overlay)
|
||||
(overlay-end overlay))))
|
||||
(buffer-substring-no-properties (point-min) (point-max)))))
|
||||
|
||||
|
||||
;;; Tests for your tests, so you can test while you test.
|
||||
|
||||
|
@ -4358,12 +4385,11 @@ def foo(a, b, c):
|
|||
;;; Electricity
|
||||
|
||||
(ert-deftest python-parens-electric-indent-1 ()
|
||||
(require 'electric)
|
||||
(let ((eim electric-indent-mode))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(python-tests-with-temp-buffer
|
||||
"
|
||||
"
|
||||
from django.conf.urls import patterns, include, url
|
||||
|
||||
from django.contrib import admin
|
||||
|
@ -4375,66 +4401,148 @@ urlpatterns = patterns('',
|
|||
url(r'^$', views.index
|
||||
)
|
||||
"
|
||||
(electric-indent-mode 1)
|
||||
(python-tests-look-at "views.index")
|
||||
(end-of-line)
|
||||
(electric-indent-mode 1)
|
||||
(python-tests-look-at "views.index")
|
||||
(end-of-line)
|
||||
|
||||
;; Inserting commas within the same line should leave
|
||||
;; indentation unchanged.
|
||||
(python-tests-self-insert ",")
|
||||
(should (= (current-indentation) 4))
|
||||
;; Inserting commas within the same line should leave
|
||||
;; indentation unchanged.
|
||||
(python-tests-self-insert ",")
|
||||
(should (= (current-indentation) 4))
|
||||
|
||||
;; As well as any other input happening within the same
|
||||
;; set of parens.
|
||||
(python-tests-self-insert " name='index')")
|
||||
(should (= (current-indentation) 4))
|
||||
;; As well as any other input happening within the same
|
||||
;; set of parens.
|
||||
(python-tests-self-insert " name='index')")
|
||||
(should (= (current-indentation) 4))
|
||||
|
||||
;; But a comma outside it, should trigger indentation.
|
||||
(python-tests-self-insert ",")
|
||||
(should (= (current-indentation) 23))
|
||||
;; But a comma outside it, should trigger indentation.
|
||||
(python-tests-self-insert ",")
|
||||
(should (= (current-indentation) 23))
|
||||
|
||||
;; Newline indents to the first argument column
|
||||
(python-tests-self-insert "\n")
|
||||
(should (= (current-indentation) 23))
|
||||
;; Newline indents to the first argument column
|
||||
(python-tests-self-insert "\n")
|
||||
(should (= (current-indentation) 23))
|
||||
|
||||
;; All this input must not change indentation
|
||||
(indent-line-to 4)
|
||||
(python-tests-self-insert "url(r'^/login$', views.login)")
|
||||
(should (= (current-indentation) 4))
|
||||
;; All this input must not change indentation
|
||||
(indent-line-to 4)
|
||||
(python-tests-self-insert "url(r'^/login$', views.login)")
|
||||
(should (= (current-indentation) 4))
|
||||
|
||||
;; But this comma does
|
||||
(python-tests-self-insert ",")
|
||||
(should (= (current-indentation) 23))))
|
||||
;; But this comma does
|
||||
(python-tests-self-insert ",")
|
||||
(should (= (current-indentation) 23))))
|
||||
(or eim (electric-indent-mode -1)))))
|
||||
|
||||
(ert-deftest python-triple-quote-pairing ()
|
||||
(require 'electric)
|
||||
(let ((epm electric-pair-mode))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(python-tests-with-temp-buffer
|
||||
"\"\"\n"
|
||||
(or epm (electric-pair-mode 1))
|
||||
(goto-char (1- (point-max)))
|
||||
(python-tests-self-insert ?\")
|
||||
(should (string= (buffer-string)
|
||||
"\"\"\"\"\"\"\n"))
|
||||
(should (= (point) 4)))
|
||||
"\"\"\n"
|
||||
(or epm (electric-pair-mode 1))
|
||||
(goto-char (1- (point-max)))
|
||||
(python-tests-self-insert ?\")
|
||||
(should (string= (buffer-string)
|
||||
"\"\"\"\"\"\"\n"))
|
||||
(should (= (point) 4)))
|
||||
(python-tests-with-temp-buffer
|
||||
"\n"
|
||||
(python-tests-self-insert (list ?\" ?\" ?\"))
|
||||
(should (string= (buffer-string)
|
||||
"\"\"\"\"\"\"\n"))
|
||||
(should (= (point) 4)))
|
||||
"\n"
|
||||
(python-tests-self-insert (list ?\" ?\" ?\"))
|
||||
(should (string= (buffer-string)
|
||||
"\"\"\"\"\"\"\n"))
|
||||
(should (= (point) 4)))
|
||||
(python-tests-with-temp-buffer
|
||||
"\"\n\"\"\n"
|
||||
(goto-char (1- (point-max)))
|
||||
(python-tests-self-insert ?\")
|
||||
(should (= (point) (1- (point-max))))
|
||||
(should (string= (buffer-string)
|
||||
"\"\n\"\"\"\n"))))
|
||||
"\"\n\"\"\n"
|
||||
(goto-char (1- (point-max)))
|
||||
(python-tests-self-insert ?\")
|
||||
(should (= (point) (1- (point-max))))
|
||||
(should (string= (buffer-string)
|
||||
"\"\n\"\"\"\n"))))
|
||||
(or epm (electric-pair-mode -1)))))
|
||||
|
||||
|
||||
;;; Hideshow support
|
||||
|
||||
(ert-deftest python-hideshow-hide-levels-1 ()
|
||||
"Should hide all methods when called after class start."
|
||||
(let ((enabled hs-minor-mode))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(python-tests-with-temp-buffer
|
||||
"
|
||||
class SomeClass:
|
||||
|
||||
def __init__(self, arg, kwarg=1):
|
||||
self.arg = arg
|
||||
self.kwarg = kwarg
|
||||
|
||||
def filter(self, nums):
|
||||
def fn(item):
|
||||
return item in [self.arg, self.kwarg]
|
||||
return filter(fn, nums)
|
||||
|
||||
def __str__(self):
|
||||
return '%s-%s' % (self.arg, self.kwarg)
|
||||
"
|
||||
(hs-minor-mode 1)
|
||||
(python-tests-look-at "class SomeClass:")
|
||||
(forward-line)
|
||||
(hs-hide-level 1)
|
||||
(should
|
||||
(string=
|
||||
(python-tests-visible-string)
|
||||
"
|
||||
class SomeClass:
|
||||
|
||||
def __init__(self, arg, kwarg=1):
|
||||
def filter(self, nums):
|
||||
def __str__(self):"))))
|
||||
(or enabled (hs-minor-mode -1)))))
|
||||
|
||||
(ert-deftest python-hideshow-hide-levels-2 ()
|
||||
"Should hide nested methods and parens at end of defun."
|
||||
(let ((enabled hs-minor-mode))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(python-tests-with-temp-buffer
|
||||
"
|
||||
class SomeClass:
|
||||
|
||||
def __init__(self, arg, kwarg=1):
|
||||
self.arg = arg
|
||||
self.kwarg = kwarg
|
||||
|
||||
def filter(self, nums):
|
||||
def fn(item):
|
||||
return item in [self.arg, self.kwarg]
|
||||
return filter(fn, nums)
|
||||
|
||||
def __str__(self):
|
||||
return '%s-%s' % (self.arg, self.kwarg)
|
||||
"
|
||||
(hs-minor-mode 1)
|
||||
(python-tests-look-at "def fn(item):")
|
||||
(hs-hide-block)
|
||||
(should
|
||||
(string=
|
||||
(python-tests-visible-string)
|
||||
"
|
||||
class SomeClass:
|
||||
|
||||
def __init__(self, arg, kwarg=1):
|
||||
self.arg = arg
|
||||
self.kwarg = kwarg
|
||||
|
||||
def filter(self, nums):
|
||||
def fn(item):
|
||||
return filter(fn, nums)
|
||||
|
||||
def __str__(self):
|
||||
return '%s-%s' % (self.arg, self.kwarg)
|
||||
"))))
|
||||
(or enabled (hs-minor-mode -1)))))
|
||||
|
||||
|
||||
|
||||
(provide 'python-tests)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue