瀏覽代碼

Drawer visibility tooling mimics blocks'

* lisp/org.el (org-hide-drawer-toggle): New function.
(org-flag-drawer): Assume either a parser drawer or buffer positions
are provided.  Remove unnecessary checks, since this is a low-level function.
* testing/lisp/test-org.el (test-org/hide-drawer-toggle): New test.
(test-org/flag-drawer):
(test-org/show-set-visibility): Update tests.
Nicolas Goaziou 5 年之前
父節點
當前提交
e6cd5a50d1
共有 2 個文件被更改,包括 101 次插入43 次删除
  1. 55 20
      lisp/org.el
  2. 46 23
      testing/lisp/test-org.el

+ 55 - 20
lisp/org.el

@@ -6042,33 +6042,68 @@ a list of strings specifying which drawers should not be hidden."
 		;; `org-drawer-regexp'.
 		(goto-char (org-element-property :end drawer))))))))))
 
-(defun org-flag-drawer (flag &optional element beg end)
+(defun org-flag-drawer (flag &optional drawer beg end)
   "When FLAG is non-nil, hide the drawer we are at.
 Otherwise make it visible.
 
-When optional argument ELEMENT is a parsed drawer, as returned by
+When optional argument DRAWER is a parsed drawer, as returned by
 `org-element-at-point', hide or show that drawer instead.
 
 When buffer positions BEG and END are provided, hide or show that
-region as a drawer without further ado."
-  (if (and beg end) (org-flag-region beg end flag 'org-hide-drawer)
-    (let ((drawer (or element
-		      (and (save-excursion
-			     (beginning-of-line)
-			     (looking-at-p org-drawer-regexp))
-			   (org-element-at-point)))))
-      (when (memq (org-element-type drawer) '(drawer property-drawer))
-	(let ((post (org-element-property :post-affiliated drawer)))
-	  (org-flag-region
-	   (save-excursion (goto-char post) (line-end-position))
-	   (save-excursion (goto-char (org-element-property :end drawer))
-			   (skip-chars-backward " \t\n")
-			   (line-end-position))
-	   flag 'org-hide-drawer)
-	  ;; When the drawer is hidden away, make sure point lies in
-	  ;; a visible part of the buffer.
+region as a drawer without further ado.
+
+The function assumes either DRAWER, or BEG and END are non-nil."
+  (let ((beg (save-excursion
+	       (goto-char (or beg
+			      (org-element-property :post-affiliated drawer)))
+	       (line-end-position)))
+	(end (save-excursion
+	       (goto-char (or end (org-element-property :end drawer)))
+	       (skip-chars-backward " \t\n")
+	       (line-end-position))))
+    (org-flag-region beg end flag 'org-hide-drawer)))
+
+(defun org-hide-drawer-toggle (&optional force no-error element)
+  "Toggle the visibility of the current drawer.
+
+When optional argument FORCE is `off', make drawer visible.  If
+it is non-nil, hide it unconditionally.  Throw an error when not
+at a drawer, unless NO-ERROR is non-nil.  When optional argument
+ELEMENT is provided, consider it instead of the current drawer.
+
+Return a non-nil value when toggling is successful."
+  (interactive)
+  (let ((element (or element (org-element-at-point))))
+    (cond
+     ((memq (org-element-type element) '(drawer property-drawer))
+      (let* ((post (org-element-property :post-affiliated element))
+	     (start (save-excursion
+		      (goto-char post)
+		      (line-end-position)))
+	     (end (save-excursion
+		    (goto-char (org-element-property :end element))
+		    (skip-chars-backward " \t\n")
+		    (line-end-position))))
+	;; Do nothing when not before or at the block opening line or at
+	;; the block closing line.
+	(unless (let ((eol (line-end-position)))
+		  (and (> eol start) (/= eol end)))
+	  (let ((flag
+		 (cond ((eq force 'off) nil)
+		       (force t)
+		       ((eq (get-char-property start 'invisible)
+			    'org-hide-drawer)
+			nil)
+		       (t t))))
+	    (org-flag-drawer flag element))
+	  ;; When the drawer is hidden away, make sure point is left
+	  ;; in a visible part of the buffer.
 	  (when (invisible-p (max (1- (point)) (point-min)))
-	    (goto-char post)))))))
+	    (goto-char post))
+	  ;; Signal success.
+	  t)))
+     (no-error nil)
+     (t (user-error "Not at a drawer")))))
 
 ;;;; Visibility cycling
 

+ 46 - 23
testing/lisp/test-org.el

@@ -7240,15 +7240,24 @@ CLOCK: [2012-03-29 Thu 10:00]--[2012-03-29 Thu 16:40] =>  6:40"
   ;; Hide drawer.
   (should
    (org-test-with-temp-text ":DRAWER:\ncontents\n:END:"
-     (org-flag-drawer t)
+     (org-flag-drawer t (org-element-at-point))
+     (get-char-property (line-end-position) 'invisible)))
+  (should
+   (org-test-with-temp-text ":DRAWER:\ncontents\n:END:"
+     (org-flag-drawer t nil (point-min) (point-max))
      (get-char-property (line-end-position) 'invisible)))
   ;; Show drawer.
   (should-not
    (org-test-with-temp-text ":DRAWER:\ncontents\n:END:"
-     (org-flag-drawer t)
-     (org-flag-drawer nil)
+     (org-flag-drawer t nil (point-min) (point-max))
+     (org-flag-drawer nil nil (point-min) (point-max))
+     (get-char-property (line-end-position) 'invisible)))
+  (should-not
+   (org-test-with-temp-text ":DRAWER:\ncontents\n:END:"
+     (org-flag-drawer t nil (point-min) (point-max))
+     (org-flag-drawer nil (org-element-at-point))
      (get-char-property (line-end-position) 'invisible)))
-  ;; Test optional argument.
+  ;; Hide drawer remotely.
   (should
    (org-test-with-temp-text "Text\n:D1:\nc1\n:END:\n\n:D2:\nc2\n:END:"
      (let ((drawer (save-excursion (search-forward ":D2")
@@ -7261,32 +7270,46 @@ CLOCK: [2012-03-29 Thu 10:00]--[2012-03-29 Thu 16:40] =>  6:40"
      (let ((drawer (save-excursion (search-forward ":D2")
 				   (org-element-at-point))))
        (org-flag-drawer t drawer)
-       (get-char-property (line-end-position) 'invisible))))
-  ;; Do not hide fake drawers.
-  (should-not
-   (org-test-with-temp-text "#+begin_example\n:D:\nc\n:END:\n#+end_example"
-     (forward-line 1)
-     (org-flag-drawer t)
+       (get-char-property (line-end-position) 'invisible)))))
+
+(ert-deftest test-org/hide-drawer-toggle ()
+  "Test `org-hide-drawer-toggle' specifications."
+  ;; Error when not at a drawer.
+  (should-error
+   (org-test-with-temp-text ":fake-drawer:\ncontents"
+     (org-hide-drawer-toggle 'off)
      (get-char-property (line-end-position) 'invisible)))
-  ;; Do not hide incomplete drawers.
+  (should-error
+   (org-test-with-temp-text
+       "#+begin_example\n<point>:D:\nc\n:END:\n#+end_example"
+     (org-hide-drawer-toggle t)))
+  ;; Hide drawer.
+  (should
+   (org-test-with-temp-text ":drawer:\ncontents\n:end:"
+     (org-hide-drawer-toggle)
+     (get-char-property (line-end-position) 'invisible)))
+  ;; Show drawer unconditionally when optional argument is `off'.
   (should-not
-   (org-test-with-temp-text ":D:\nparagraph"
-     (forward-line 1)
-     (org-flag-drawer t)
+   (org-test-with-temp-text ":drawer:\ncontents\n:end:"
+     (org-hide-drawer-toggle)
+     (org-hide-drawer-toggle 'off)
      (get-char-property (line-end-position) 'invisible)))
-  ;; Do not hide drawers when called from final blank lines.
+  ;; Hide drawer unconditionally when optional argument is non-nil.
+  (should
+   (org-test-with-temp-text ":drawer:\ncontents\n:end:"
+     (org-hide-drawer-toggle t)
+     (get-char-property (line-end-position) 'invisible)))
+  ;; Do not hide drawer when called from final blank lines.
   (should-not
-   (org-test-with-temp-text ":DRAWER:\nA\n:END:\n\n"
-     (goto-char (point-max))
-     (org-flag-drawer t)
+   (org-test-with-temp-text ":drawer:\ncontents\n:end:\n\n<point>"
+     (org-hide-drawer-toggle)
      (goto-char (point-min))
      (get-char-property (line-end-position) 'invisible)))
   ;; Don't leave point in an invisible part of the buffer when hiding
   ;; a drawer away.
   (should-not
-   (org-test-with-temp-text ":DRAWER:\ncontents\n:END:"
-     (goto-char (point-max))
-     (org-flag-drawer t)
+   (org-test-with-temp-text ":drawer:\ncontents\n<point>:end:"
+     (org-hide-drawer-toggle)
      (get-char-property (point) 'invisible))))
 
 (ert-deftest test-org/hide-block-toggle ()
@@ -7406,14 +7429,14 @@ CLOCK: [2012-03-29 Thu 10:00]--[2012-03-29 Thu 16:40] =>  6:40"
      (org-invisible-p2)))
   (should-not
    (org-test-with-temp-text ":DRAWER:\nText\n:END:"
-     (org-flag-drawer t)
+     (org-hide-drawer-toggle)
      (search-forward "Text")
      (org-show-set-visibility 'minimal)
      (org-invisible-p2)))
   (should-not
    (org-test-with-temp-text
        "#+BEGIN_QUOTE\n<point>:DRAWER:\nText\n:END:\n#+END_QUOTE"
-     (org-flag-drawer t)
+     (org-hide-drawer-toggle)
      (forward-line -1)
      (org-hide-block-toggle)
      (search-forward "Text")