aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabián Ezequiel Gallina2015-02-07 16:43:47 -0300
committerFabián Ezequiel Gallina2015-02-07 16:43:47 -0300
commit2d467a0ff0cd446ec0d83044a0be819cbf874cdf (patch)
treef719433f1e65da7a6a70f4bd3f1d9231eb626f9d
parent86c50b9af1e68ca87bfc9e6d0cdb28ae2e53cc32 (diff)
downloademacs-2d467a0ff0cd446ec0d83044a0be819cbf874cdf.tar.gz
emacs-2d467a0ff0cd446ec0d83044a0be819cbf874cdf.zip
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.
-rw-r--r--lisp/ChangeLog10
-rw-r--r--lisp/progmodes/python.el26
-rw-r--r--test/ChangeLog9
-rw-r--r--test/automated/python-tests.el198
4 files changed, 193 insertions, 50 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index a02f9642e55..655ae574468 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,15 @@
12015-02-07 Fabián Ezequiel Gallina <fgallina@gnu.org> 12015-02-07 Fabián Ezequiel Gallina <fgallina@gnu.org>
2 2
3 Fix hideshow integration. (Bug#19761)
4
5 * progmodes/python.el
6 (python-hideshow-forward-sexp-function): New function based on
7 Carlos Pita <carlosjosepita@gmail.com> patch.
8 (python-mode): Make `hs-special-modes-alist` use it and initialize
9 the end regexp with the empty string to avoid skipping parens.
10
112015-02-07 Fabián Ezequiel Gallina <fgallina@gnu.org>
12
3 * progmodes/python.el (python-check-custom-command): Do not use 13 * progmodes/python.el (python-check-custom-command): Do not use
4 defvar-local for compat with Emacs<24.3. 14 defvar-local for compat with Emacs<24.3.
5 15
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index de251181c14..3399429538f 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -3958,6 +3958,17 @@ Interactively, prompt for symbol."
3958 (message (python-eldoc--get-doc-at-point symbol))) 3958 (message (python-eldoc--get-doc-at-point symbol)))
3959 3959
3960 3960
3961;;; Hideshow
3962
3963(defun python-hideshow-forward-sexp-function (arg)
3964 "Python specific `forward-sexp' function for `hs-minor-mode'.
3965Argument ARG is ignored."
3966 arg ; Shut up, byte compiler.
3967 (python-nav-end-of-defun)
3968 (unless (python-info-current-line-empty-p)
3969 (backward-char)))
3970
3971
3961;;; Imenu 3972;;; Imenu
3962 3973
3963(defvar python-imenu-format-item-label-function 3974(defvar python-imenu-format-item-label-function
@@ -4693,11 +4704,16 @@ Arguments START and END narrow the buffer region to work on."
4693 (add-function :before-until (local 'eldoc-documentation-function) 4704 (add-function :before-until (local 'eldoc-documentation-function)
4694 #'python-eldoc-function)) 4705 #'python-eldoc-function))
4695 4706
4696 (add-to-list 'hs-special-modes-alist 4707 (add-to-list
4697 `(python-mode "^\\s-*\\(?:def\\|class\\)\\>" nil "#" 4708 'hs-special-modes-alist
4698 ,(lambda (_arg) 4709 `(python-mode
4699 (python-nav-end-of-defun)) 4710 "\\s-*\\(?:def\\|class\\)\\>"
4700 nil)) 4711 ;; Use the empty string as end regexp so it doesn't default to
4712 ;; "\\s)". This way parens at end of defun are properly hidden.
4713 ""
4714 "#"
4715 python-hideshow-forward-sexp-function
4716 nil))
4701 4717
4702 (set (make-local-variable 'outline-regexp) 4718 (set (make-local-variable 'outline-regexp)
4703 (python-rx (* space) block-start)) 4719 (python-rx (* space) block-start))
diff --git a/test/ChangeLog b/test/ChangeLog
index e0d4eeb323a..b1e21511d65 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,12 @@
12015-02-07 Fabián Ezequiel Gallina <fgallina@gnu.org>
2
3 * automated/python-tests.el
4 (python-tests-visible-string): New function.
5 (python-parens-electric-indent-1)
6 (python-triple-quote-pairing): Fix indentation, move require calls.
7 (python-hideshow-hide-levels-1)
8 (python-hideshow-hide-levels-2): New tests.
9
12015-02-07 Dmitry Gutov <dgutov@yandex.ru> 102015-02-07 Dmitry Gutov <dgutov@yandex.ru>
2 11
3 * automated/vc-tests.el (vc-test--working-revision): Fix 12 * automated/vc-tests.el (vc-test--working-revision): Fix
diff --git a/test/automated/python-tests.el b/test/automated/python-tests.el
index 672b05c39de..e5fcda95012 100644
--- a/test/automated/python-tests.el
+++ b/test/automated/python-tests.el
@@ -24,6 +24,11 @@
24(require 'ert) 24(require 'ert)
25(require 'python) 25(require 'python)
26 26
27;; Dependencies for testing:
28(require 'electric)
29(require 'hideshow)
30
31
27(defmacro python-tests-with-temp-buffer (contents &rest body) 32(defmacro python-tests-with-temp-buffer (contents &rest body)
28 "Create a `python-mode' enabled temp buffer with CONTENTS. 33 "Create a `python-mode' enabled temp buffer with CONTENTS.
29BODY is code to be executed within the temp buffer. Point is 34BODY 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."
104 (call-interactively 'self-insert-command))) 109 (call-interactively 'self-insert-command)))
105 chars))) 110 chars)))
106 111
112(defun python-tests-visible-string (&optional min max)
113 "Return the buffer string excluding invisible overlays.
114Argument MIN and MAX delimit the region to be returned and
115default to `point-min' and `point-max' respectively."
116 (let* ((min (or min (point-min)))
117 (max (or max (point-max)))
118 (buffer (current-buffer))
119 (buffer-contents (buffer-substring-no-properties min max))
120 (overlays
121 (sort (overlays-in min max)
122 (lambda (a b)
123 (let ((overlay-end-a (overlay-end a))
124 (overlay-end-b (overlay-end b)))
125 (> overlay-end-a overlay-end-b))))))
126 (with-temp-buffer
127 (insert buffer-contents)
128 (dolist (overlay overlays)
129 (if (overlay-get overlay 'invisible)
130 (delete-region (overlay-start overlay)
131 (overlay-end overlay))))
132 (buffer-substring-no-properties (point-min) (point-max)))))
133
107 134
108;;; Tests for your tests, so you can test while you test. 135;;; Tests for your tests, so you can test while you test.
109 136
@@ -4358,12 +4385,11 @@ def foo(a, b, c):
4358;;; Electricity 4385;;; Electricity
4359 4386
4360(ert-deftest python-parens-electric-indent-1 () 4387(ert-deftest python-parens-electric-indent-1 ()
4361 (require 'electric)
4362 (let ((eim electric-indent-mode)) 4388 (let ((eim electric-indent-mode))
4363 (unwind-protect 4389 (unwind-protect
4364 (progn 4390 (progn
4365 (python-tests-with-temp-buffer 4391 (python-tests-with-temp-buffer
4366 " 4392 "
4367from django.conf.urls import patterns, include, url 4393from django.conf.urls import patterns, include, url
4368 4394
4369from django.contrib import admin 4395from django.contrib import admin
@@ -4375,66 +4401,148 @@ urlpatterns = patterns('',
4375 url(r'^$', views.index 4401 url(r'^$', views.index
4376) 4402)
4377" 4403"
4378 (electric-indent-mode 1) 4404 (electric-indent-mode 1)
4379 (python-tests-look-at "views.index") 4405 (python-tests-look-at "views.index")
4380 (end-of-line) 4406 (end-of-line)
4381 4407
4382 ;; Inserting commas within the same line should leave 4408 ;; Inserting commas within the same line should leave
4383 ;; indentation unchanged. 4409 ;; indentation unchanged.
4384 (python-tests-self-insert ",") 4410 (python-tests-self-insert ",")
4385 (should (= (current-indentation) 4)) 4411 (should (= (current-indentation) 4))
4386 4412
4387 ;; As well as any other input happening within the same 4413 ;; As well as any other input happening within the same
4388 ;; set of parens. 4414 ;; set of parens.
4389 (python-tests-self-insert " name='index')") 4415 (python-tests-self-insert " name='index')")
4390 (should (= (current-indentation) 4)) 4416 (should (= (current-indentation) 4))
4391 4417
4392 ;; But a comma outside it, should trigger indentation. 4418 ;; But a comma outside it, should trigger indentation.
4393 (python-tests-self-insert ",") 4419 (python-tests-self-insert ",")
4394 (should (= (current-indentation) 23)) 4420 (should (= (current-indentation) 23))
4395 4421
4396 ;; Newline indents to the first argument column 4422 ;; Newline indents to the first argument column
4397 (python-tests-self-insert "\n") 4423 (python-tests-self-insert "\n")
4398 (should (= (current-indentation) 23)) 4424 (should (= (current-indentation) 23))
4399 4425
4400 ;; All this input must not change indentation 4426 ;; All this input must not change indentation
4401 (indent-line-to 4) 4427 (indent-line-to 4)
4402 (python-tests-self-insert "url(r'^/login$', views.login)") 4428 (python-tests-self-insert "url(r'^/login$', views.login)")
4403 (should (= (current-indentation) 4)) 4429 (should (= (current-indentation) 4))
4404 4430
4405 ;; But this comma does 4431 ;; But this comma does
4406 (python-tests-self-insert ",") 4432 (python-tests-self-insert ",")
4407 (should (= (current-indentation) 23)))) 4433 (should (= (current-indentation) 23))))
4408 (or eim (electric-indent-mode -1))))) 4434 (or eim (electric-indent-mode -1)))))
4409 4435
4410(ert-deftest python-triple-quote-pairing () 4436(ert-deftest python-triple-quote-pairing ()
4411 (require 'electric)
4412 (let ((epm electric-pair-mode)) 4437 (let ((epm electric-pair-mode))
4413 (unwind-protect 4438 (unwind-protect
4414 (progn 4439 (progn
4415 (python-tests-with-temp-buffer 4440 (python-tests-with-temp-buffer
4416 "\"\"\n" 4441 "\"\"\n"
4417 (or epm (electric-pair-mode 1)) 4442 (or epm (electric-pair-mode 1))
4418 (goto-char (1- (point-max))) 4443 (goto-char (1- (point-max)))
4419 (python-tests-self-insert ?\") 4444 (python-tests-self-insert ?\")
4420 (should (string= (buffer-string) 4445 (should (string= (buffer-string)
4421 "\"\"\"\"\"\"\n")) 4446 "\"\"\"\"\"\"\n"))
4422 (should (= (point) 4))) 4447 (should (= (point) 4)))
4423 (python-tests-with-temp-buffer 4448 (python-tests-with-temp-buffer
4424 "\n" 4449 "\n"
4425 (python-tests-self-insert (list ?\" ?\" ?\")) 4450 (python-tests-self-insert (list ?\" ?\" ?\"))
4426 (should (string= (buffer-string) 4451 (should (string= (buffer-string)
4427 "\"\"\"\"\"\"\n")) 4452 "\"\"\"\"\"\"\n"))
4428 (should (= (point) 4))) 4453 (should (= (point) 4)))
4429 (python-tests-with-temp-buffer 4454 (python-tests-with-temp-buffer
4430 "\"\n\"\"\n" 4455 "\"\n\"\"\n"
4431 (goto-char (1- (point-max))) 4456 (goto-char (1- (point-max)))
4432 (python-tests-self-insert ?\") 4457 (python-tests-self-insert ?\")
4433 (should (= (point) (1- (point-max)))) 4458 (should (= (point) (1- (point-max))))
4434 (should (string= (buffer-string) 4459 (should (string= (buffer-string)
4435 "\"\n\"\"\"\n")))) 4460 "\"\n\"\"\"\n"))))
4436 (or epm (electric-pair-mode -1))))) 4461 (or epm (electric-pair-mode -1)))))
4437 4462
4463
4464;;; Hideshow support
4465
4466(ert-deftest python-hideshow-hide-levels-1 ()
4467 "Should hide all methods when called after class start."
4468 (let ((enabled hs-minor-mode))
4469 (unwind-protect
4470 (progn
4471 (python-tests-with-temp-buffer
4472 "
4473class SomeClass:
4474
4475 def __init__(self, arg, kwarg=1):
4476 self.arg = arg
4477 self.kwarg = kwarg
4478
4479 def filter(self, nums):
4480 def fn(item):
4481 return item in [self.arg, self.kwarg]
4482 return filter(fn, nums)
4483
4484 def __str__(self):
4485 return '%s-%s' % (self.arg, self.kwarg)
4486"
4487 (hs-minor-mode 1)
4488 (python-tests-look-at "class SomeClass:")
4489 (forward-line)
4490 (hs-hide-level 1)
4491 (should
4492 (string=
4493 (python-tests-visible-string)
4494 "
4495class SomeClass:
4496
4497 def __init__(self, arg, kwarg=1):
4498 def filter(self, nums):
4499 def __str__(self):"))))
4500 (or enabled (hs-minor-mode -1)))))
4501
4502(ert-deftest python-hideshow-hide-levels-2 ()
4503 "Should hide nested methods and parens at end of defun."
4504 (let ((enabled hs-minor-mode))
4505 (unwind-protect
4506 (progn
4507 (python-tests-with-temp-buffer
4508 "
4509class SomeClass:
4510
4511 def __init__(self, arg, kwarg=1):
4512 self.arg = arg
4513 self.kwarg = kwarg
4514
4515 def filter(self, nums):
4516 def fn(item):
4517 return item in [self.arg, self.kwarg]
4518 return filter(fn, nums)
4519
4520 def __str__(self):
4521 return '%s-%s' % (self.arg, self.kwarg)
4522"
4523 (hs-minor-mode 1)
4524 (python-tests-look-at "def fn(item):")
4525 (hs-hide-block)
4526 (should
4527 (string=
4528 (python-tests-visible-string)
4529 "
4530class SomeClass:
4531
4532 def __init__(self, arg, kwarg=1):
4533 self.arg = arg
4534 self.kwarg = kwarg
4535
4536 def filter(self, nums):
4537 def fn(item):
4538 return filter(fn, nums)
4539
4540 def __str__(self):
4541 return '%s-%s' % (self.arg, self.kwarg)
4542"))))
4543 (or enabled (hs-minor-mode -1)))))
4544
4545
4438 4546
4439(provide 'python-tests) 4547(provide 'python-tests)
4440 4548