emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Ihor Radchenko <yantar92@gmail.com>
To: Bastien <bzg@gnu.org>, Kyle Meyer <kyle@kyleam.com>,
	Nicolas Goaziou <mail@nicolasgoaziou.fr>,
	Karl Voit <devnull@Karl-Voit.at>,
	Christian Heinrich <christian@gladbachcity.de>,
	emacs-orgmode@gnu.org
Cc: Ihor Radchenko <yantar92@gmail.com>
Subject: [PATCH 02/35] Separate folding functions from org.el into new library: org-fold
Date: Sat, 29 Jan 2022 19:37:54 +0800	[thread overview]
Message-ID: <a36ac8670ea6eda6b25b0be5ff1ee4afdd46e34a.1643454546.git.yantar92@gmail.com> (raw)
In-Reply-To: <cover.1643454545.git.yantar92@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 150 bytes --]

---
 lisp/org-fold.el | 1135 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1135 insertions(+)
 create mode 100644 lisp/org-fold.el


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0002-Separate-folding-functions-from-org.el-into-new-libr.patch --]
[-- Type: text/x-patch; name="0002-Separate-folding-functions-from-org.el-into-new-libr.patch", Size: 49902 bytes --]

diff --git a/lisp/org-fold.el b/lisp/org-fold.el
new file mode 100644
index 000000000..52717fd86
--- /dev/null
+++ b/lisp/org-fold.el
@@ -0,0 +1,1135 @@
+;;; org-fold.el --- Folding of Org entries -*- lexical-binding: t; -*-
+;;
+;; Copyright (C) 2020-2020 Free Software Foundation, Inc.
+;;
+;; Author: Ihor Radchenko <yantar92 at gmail dot com>
+;; Keywords: folding, invisible text
+;; Homepage: https://orgmode.org
+;;
+;; 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 <https://www.gnu.org/licenses/>.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+
+;; This file contains code handling temporary invisibility (folding
+;; and unfolding) of text in org buffers.
+
+;; The folding is implemented using generic org-fold-core library.  This file
+;; contains org-specific implementation of the folding.  Also, various
+;; useful functions from org-fold-core are aliased under shorted `org-fold'
+;; prefix.
+
+;; The following features are implemented:
+;; - Folding/unfolding various Org mode elements and regions of Org buffers:
+;;   + Region before first heading;
+;;   + Org headings, their text, children (subtree), siblings, parents, etc;
+;;   + Org blocks and drawers
+;; - Revealing Org structure around invisible point location
+;; - Revealing folded Org elements broken by user edits
+
+;;; Code:
+
+(require 'org-macs)
+(require 'org-fold-core)
+
+(defvar org-inlinetask-min-level)
+(defvar org-link--link-folding-spec)
+(defvar org-link--description-folding-spec)
+(defvar org-odd-levels-only)
+(defvar org-drawer-regexp)
+(defvar org-property-end-re)
+(defvar org-link-descriptive)
+(defvar org-outline-regexp-bol)
+(defvar org-custom-properties-hidden-p)
+(defvar org-archive-tag)
+
+;; Needed for overlays only
+(defvar org-custom-properties-overlays)
+
+(declare-function isearch-filter-visible "isearch" (beg end))
+(declare-function org-element-type "org-element" (element))
+(declare-function org-element-at-point "org-element" (&optional pom cached-only))
+(declare-function org-element-property "org-element" (property element))
+(declare-function org-element--current-element "org-element" (limit &optional granularity mode structure))
+(declare-function org-element--cache-active-p "org-element" ())
+(declare-function org-toggle-custom-properties-visibility "org" ())
+(declare-function org-item-re "org-list" ())
+(declare-function org-up-heading-safe "org" ())
+(declare-function org-get-tags "org" (&optional pos local fontify))
+(declare-function org-get-valid-level "org" (level &optional change))
+(declare-function org-before-first-heading-p "org" ())
+(declare-function org-goto-sibling "org" (&optional previous))
+(declare-function org-block-map "org" (function &optional start end))
+(declare-function org-map-region "org" (fun beg end))
+(declare-function org-end-of-subtree "org" (&optional invisible-ok to-heading))
+(declare-function org-back-to-heading-or-point-min "org" (&optional invisible-ok))
+(declare-function org-back-to-heading "org" (&optional invisible-ok))
+(declare-function org-at-heading-p "org" (&optional invisible-not-ok))
+(declare-function org-cycle-hide-drawers "org-cycle" (state))
+
+(declare-function outline-show-branches "outline" ())
+(declare-function outline-hide-sublevels "outline" (levels))
+(declare-function outline-get-next-sibling "outline" ())
+(declare-function outline-invisible-p "outline" (&optional pos))
+(declare-function outline-next-heading "outline" ())
+
+;;; Customization
+
+(defgroup org-fold-reveal-location nil
+  "Options about how to make context of a location visible."
+  :tag "Org Reveal Location"
+  :group 'org-structure)
+
+(defcustom org-fold-show-context-detail '((agenda . local)
+				  (bookmark-jump . lineage)
+				  (isearch . lineage)
+				  (default . ancestors))
+  "Alist between context and visibility span when revealing a location.
+
+\\<org-mode-map>Some actions may move point into invisible
+locations.  As a consequence, Org always exposes a neighborhood
+around point.  How much is shown depends on the initial action,
+or context.  Valid contexts are
+
+  agenda         when exposing an entry from the agenda
+  org-goto       when using the command `org-goto' (`\\[org-goto]')
+  occur-tree     when using the command `org-occur' (`\\[org-sparse-tree] /')
+  tags-tree      when constructing a sparse tree based on tags matches
+  link-search    when exposing search matches associated with a link
+  mark-goto      when exposing the jump goal of a mark
+  bookmark-jump  when exposing a bookmark location
+  isearch        when exiting from an incremental search
+  default        default for all contexts not set explicitly
+
+Allowed visibility spans are
+
+  minimal        show current headline; if point is not on headline,
+                 also show entry
+
+  local          show current headline, entry and next headline
+
+  ancestors      show current headline and its direct ancestors; if
+                 point is not on headline, also show entry
+
+  ancestors-full show current subtree and its direct ancestors
+
+  lineage        show current headline, its direct ancestors and all
+                 their children; if point is not on headline, also show
+                 entry and first child
+
+  tree           show current headline, its direct ancestors and all
+                 their children; if point is not on headline, also show
+                 entry and all children
+
+  canonical      show current headline, its direct ancestors along with
+                 their entries and children; if point is not located on
+                 the headline, also show current entry and all children
+
+As special cases, a nil or t value means show all contexts in
+`minimal' or `canonical' view, respectively.
+
+Some views can make displayed information very compact, but also
+make it harder to edit the location of the match.  In such
+a case, use the command `org-fold-reveal' (`\\[org-fold-reveal]') to show
+more context."
+  :group 'org-fold-reveal-location
+  :version "26.1"
+  :package-version '(Org . "9.0")
+  :type '(choice
+	  (const :tag "Canonical" t)
+	  (const :tag "Minimal" nil)
+	  (repeat :greedy t :tag "Individual contexts"
+		  (cons
+		   (choice :tag "Context"
+			   (const agenda)
+			   (const org-goto)
+			   (const occur-tree)
+			   (const tags-tree)
+			   (const link-search)
+			   (const mark-goto)
+			   (const bookmark-jump)
+			   (const isearch)
+			   (const default))
+		   (choice :tag "Detail level"
+			   (const minimal)
+			   (const local)
+			   (const ancestors)
+                           (const ancestors-full)
+			   (const lineage)
+			   (const tree)
+			   (const canonical))))))
+
+(defvar org-fold-reveal-start-hook nil
+  "Hook run before revealing a location.")
+
+(defcustom org-fold-catch-invisible-edits 'smart
+  "Check if in invisible region before inserting or deleting a character.
+Valid values are:
+
+nil              Do not check, so just do invisible edits.
+error            Throw an error and do nothing.
+show             Make point visible, and do the requested edit.
+show-and-error   Make point visible, then throw an error and abort the edit.
+smart            Make point visible, and do insertion/deletion if it is
+                 adjacent to visible text and the change feels predictable.
+                 Never delete a previously invisible character or add in the
+                 middle or right after an invisible region.  Basically, this
+                 allows insertion and backward-delete right before ellipses.
+                 FIXME: maybe in this case we should not even show?"
+  :group 'org-edit-structure
+  :version "24.1"
+  :type '(choice
+	  (const :tag "Do not check" nil)
+	  (const :tag "Throw error when trying to edit" error)
+	  (const :tag "Unhide, but do not do the edit" show-and-error)
+	  (const :tag "Show invisible part and do the edit" show)
+	  (const :tag "Be smart and do the right thing" smart)))
+
+;;; Core functionality
+
+;;; API
+
+;;;; Modifying folding specs
+
+(defalias 'org-fold-folding-spec-p #'org-fold-core-folding-spec-p)
+(defalias 'org-fold-add-folding-spec #'org-fold-core-add-folding-spec)
+(defalias 'org-fold-remove-folding-spec #'org-fold-core-remove-folding-spec)
+
+(defun org-fold-initialize (ellipsis)
+  "Setup folding in current Org buffer."
+  (setq-local org-fold-core-isearch-open-function #'org-fold--isearch-reveal)
+  (setq-local org-fold-core-extend-changed-region-functions (list #'org-fold--extend-changed-region))
+  ;; FIXME: Converting org-link + org-description to overlays when
+  ;; search matches hidden "[[" part of the link, reverses priority of
+  ;; link and description and hides the whole link.  Working around
+  ;; this until there will be no need to convert text properties to
+  ;; overlays for isearch.
+  (setq-local org-fold-core--isearch-special-specs '(org-link))
+  (org-fold-core-initialize `((org-fold-outline
+                       (:ellipsis . ,ellipsis)
+                       (:fragile . ,#'org-fold--reveal-outline-maybe)
+                       (:isearch-open . t)
+                       ;; This is needed to make sure that inserting a
+                       ;; new planning line in folded heading is not
+                       ;; revealed.
+                       (:front-sticky . t)
+                       (:rear-sticky . t)
+                       (:font-lock-skip . t)
+                       (:alias . (headline heading outline inlinetask plain-list)))
+                      (org-fold-block
+                       (:ellipsis . ,ellipsis)
+                       (:fragile . ,#'org-fold--reveal-drawer-or-block-maybe)
+                       (:isearch-open . t)
+                       (:front-sticky . t)
+                       (:alias . ( block center-block comment-block
+                                   dynamic-block example-block export-block
+                                   quote-block special-block src-block
+                                   verse-block)))
+                      (org-fold-drawer
+                       (:ellipsis . ,ellipsis)
+                       (:fragile . ,#'org-fold--reveal-drawer-or-block-maybe)
+                       (:isearch-open . t)
+                       (:front-sticky . t)
+                       (:alias . (drawer property-drawer)))
+                      ,org-link--description-folding-spec
+                      ,org-link--link-folding-spec)))
+
+;;;; Searching and examining folded text
+
+(defalias 'org-fold-folded-p #'org-fold-core-folded-p)
+(defalias 'org-fold-get-folding-spec #'org-fold-core-get-folding-spec)
+(defalias 'org-fold-get-folding-specs-in-region #'org-fold-core-get-folding-specs-in-region)
+(defalias 'org-fold-get-region-at-point #'org-fold-core-get-region-at-point)
+(defalias 'org-fold-next-visibility-change #'org-fold-core-next-visibility-change)
+(defalias 'org-fold-previous-visibility-change #'org-fold-core-previous-visibility-change)
+(defalias 'org-fold-next-folding-state-change #'org-fold-core-next-folding-state-change)
+(defalias 'org-fold-previous-folding-state-change #'org-fold-core-previous-folding-state-change)
+(defalias 'org-fold-search-forward #'org-fold-core-search-forward)
+
+;;;;; Macros
+
+(defmacro org-fold-save-outline-visibility--overlays (use-markers &rest body)
+  "Save and restore outline visibility around BODY.
+If USE-MARKERS is non-nil, use markers for the positions.  This
+means that the buffer may change while running BODY, but it also
+means that the buffer should stay alive during the operation,
+because otherwise all these markers will point to nowhere."
+  (declare (debug (form body)) (indent 1))
+  (org-with-gensyms (data invisible-types markers?)
+    `(let* ((,invisible-types '(org-hide-block outline))
+	    (,markers? ,use-markers)
+	    (,data
+	     (mapcar (lambda (o)
+		       (let ((beg (overlay-start o))
+			     (end (overlay-end o))
+			     (type (overlay-get o 'invisible)))
+			 (and beg end
+			      (> end beg)
+			      (memq type ,invisible-types)
+			      (list (if ,markers? (copy-marker beg) beg)
+				    (if ,markers? (copy-marker end t) end)
+				    type))))
+		     (org-with-wide-buffer
+		      (overlays-in (point-min) (point-max))))))
+       (unwind-protect (progn ,@body)
+	 (org-with-wide-buffer
+	  (dolist (type ,invisible-types)
+	    (remove-overlays (point-min) (point-max) 'invisible type))
+	  (pcase-dolist (`(,beg ,end ,type) (delq nil ,data))
+	    (org-fold-region beg end t type)
+	    (when ,markers?
+	      (set-marker beg nil)
+	      (set-marker end nil))))))))
+(defmacro org-fold-save-outline-visibility--text-properties (use-markers &rest body)
+  "Save and restore outline visibility around BODY.
+If USE-MARKERS is non-nil, use markers for the positions.  This
+means that the buffer may change while running BODY, but it also
+means that the buffer should stay alive during the operation,
+because otherwise all these markers will point to nowhere."
+  (declare (debug (form body)) (indent 1))
+  (org-with-gensyms (data specs markers?)
+    `(let* ((,specs ',(org-fold-core-folding-spec-list))
+	    (,markers? ,use-markers)
+	    (,data
+             (org-with-wide-buffer
+              (let ((pos (point-min))
+		    data-val)
+		(while (< pos (point-max))
+                  (dolist (spec (org-fold-get-folding-spec 'all pos))
+                    (let ((region (org-fold-get-region-at-point spec pos)))
+		      (if ,markers?
+			  (push (list (copy-marker (car region))
+				      (copy-marker (cdr region) t)
+                                      spec)
+                                data-val)
+                        (push (list (car region) (cdr region) spec)
+			      data-val))))
+                  (setq pos (org-fold-next-folding-state-change nil pos)))))))
+       (unwind-protect (progn ,@body)
+	 (org-with-wide-buffer
+	  (dolist (spec ,specs)
+	    (org-fold-region (point-min) (point-max) nil spec))
+	  (pcase-dolist (`(,beg ,end ,spec) (delq nil ,data))
+	    (org-fold-region beg end t spec)
+	    (when ,markers?
+	      (set-marker beg nil)
+	      (set-marker end nil))))))))
+(defmacro org-fold-save-outline-visibility (use-markers &rest body)
+  "Save and restore outline visibility around BODY.
+If USE-MARKERS is non-nil, use markers for the positions.  This
+means that the buffer may change while running BODY, but it also
+means that the buffer should stay alive during the operation,
+because otherwise all these markers will point to nowhere."
+  (declare (debug (form body)) (indent 1))
+  `(when (eq org-fold-core-style 'text-properties)
+     (org-fold-save-outline-visibility--text-properties ,use-markers ,@body)
+     (org-fold-save-outline-visibility--overlays ,use-markers ,@body)))
+
+;;;; Changing visibility (regions, blocks, drawers, headlines)
+
+;;;;; Region visibility
+
+;; (defalias 'org-fold-region #'org-fold-core-region)
+(defun org-fold-region--overlays (from to flag spec)
+  "Hide or show lines from FROM to TO, according to FLAG.
+SPEC is the invisibility spec, as a symbol."
+  (remove-overlays from to 'invisible spec)
+  ;; Use `front-advance' since text right before to the beginning of
+  ;; the overlay belongs to the visible line than to the contents.
+  (when flag
+    (let ((o (make-overlay from to nil 'front-advance)))
+      (overlay-put o 'evaporate t)
+      (overlay-put o 'invisible spec)
+      (overlay-put o
+                   'isearch-open-invisible
+                   (lambda (&rest _) (org-fold-show-context 'isearch))))))
+(defsubst org-fold-region (from to flag &optional spec)
+  "Hide or show lines from FROM to TO, according to FLAG.
+SPEC is the invisibility spec, as a symbol."
+  (if (eq org-fold-core-style 'text-properties)
+      (org-fold-core-region from to flag spec)
+    (org-fold-region--overlays from to flag spec)))
+
+(defun org-fold-show-all--text-properties (&optional types)
+  "Show all contents in the visible part of the buffer.
+By default, the function expands headings, blocks and drawers.
+When optional argument TYPES is a list of symbols among `blocks',
+`drawers' and `headings', to only expand one specific type."
+  (interactive)
+  (dolist (type (or types '(blocks drawers headings)))
+    (org-fold-region (point-min) (point-max) nil
+	             (pcase type
+	               (`blocks 'block)
+	               (`drawers 'drawer)
+	               (`headings 'headline)
+	               (_ (error "Invalid type: %S" type))))))
+(defun org-fold-show-all--overlays (&optional types)
+  "Show all contents in the visible part of the buffer.
+By default, the function expands headings, blocks and drawers.
+When optional argument TYPE is a list of symbols among `blocks',
+`drawers' and `headings', to only expand one specific type."
+  (interactive)
+  (let ((types (or types '(blocks drawers headings))))
+    (when (memq 'blocks types)
+      (org-fold-region (point-min) (point-max) nil 'org-hide-block))
+    (cond
+     ;; Fast path.  Since headings and drawers share the same
+     ;; invisible spec, clear everything in one go.
+     ((and (memq 'headings types)
+           (memq 'drawers types))
+      (org-fold-region (point-min) (point-max) nil 'outline))
+     ((memq 'headings types)
+      (org-fold-region (point-min) (point-max) nil 'outline)
+      (org-cycle-hide-drawers 'all))
+     ((memq 'drawers types)
+      (save-excursion
+        (goto-char (point-min))
+        (while (re-search-forward org-drawer-regexp nil t)
+          (let* ((pair (get-char-property-and-overlay (line-beginning-position)
+                                                      'invisible))
+                 (o (cdr-safe pair)))
+            (if (overlayp o) (goto-char (overlay-end o))
+              (pcase (get-char-property-and-overlay (point) 'invisible)
+                (`(outline . ,o)
+                 (goto-char (overlay-end o))
+                 (delete-overlay o))
+                (_ nil))))))))))
+(defsubst org-fold-show-all (&optional types)
+  "Show all contents in the visible part of the buffer.
+By default, the function expands headings, blocks and drawers.
+When optional argument TYPES is a list of symbols among `blocks',
+`drawers' and `headings', to only expand one specific type."
+  (interactive)
+  (if (eq org-fold-core-style 'text-properties)
+      (org-fold-show-all--text-properties types)
+    (org-fold-show-all--overlays types)))
+
+(defun org-fold-flag-above-first-heading (&optional arg)
+  "Hide from bob up to the first heading.
+Move point to the beginning of first heading or end of buffer."
+  (goto-char (point-min))
+  (unless (org-at-heading-p)
+    (outline-next-heading))
+  (unless (bobp)
+    (org-fold-region 1 (1- (point)) (not arg) 'outline)))
+
+;;;;; Heading visibility
+
+(defun org-fold-heading (flag &optional entry)
+  "Fold/unfold the current heading.  FLAG non-nil means make invisible.
+When ENTRY is non-nil, show the entire entry."
+  (save-excursion
+    (org-back-to-heading t)
+    ;; Check if we should show the entire entry
+    (if (not entry)
+	(org-fold-region
+	 (line-end-position 0) (line-end-position) flag 'outline)
+      (org-fold-show-entry)
+      (save-excursion
+	;; FIXME: potentially catches inlinetasks
+	(and (outline-next-heading)
+	     (org-fold-heading nil))))))
+
+(defun org-fold-hide-entry ()
+  "Hide the body directly following this heading."
+  (interactive)
+  (save-excursion
+    (org-back-to-heading-or-point-min t)
+    (when (org-at-heading-p) (forward-line))
+    (unless (eobp) ; Current headline is empty and ends at the end of buffer.
+      (org-fold-region
+       (line-end-position 0)
+       (save-excursion
+         (if (re-search-forward
+ 	      (concat "[\r\n]" (org-get-limited-outline-regexp)) nil t)
+             (line-end-position 0)
+ 	   (point-max)))
+       t
+       'outline))))
+
+(defun org-fold-subtree (flag)
+  (save-excursion
+    (org-back-to-heading t)
+    (org-fold-region (line-end-position)
+	     (progn (org-end-of-subtree t) (point))
+	     flag
+	     'outline)))
+
+;; Replaces `outline-hide-subtree'.
+(defun org-fold-hide-subtree ()
+  "Hide everything after this heading at deeper levels."
+  (interactive)
+  (org-fold-subtree t))
+
+;; Replaces `outline-hide-sublevels'
+(defun org-fold-hide-sublevels (levels)
+  "Hide everything but the top LEVELS levels of headers, in whole buffer.
+This also unhides the top heading-less body, if any.
+
+Interactively, the prefix argument supplies the value of LEVELS.
+When invoked without a prefix argument, LEVELS defaults to the level
+of the current heading, or to 1 if the current line is not a heading."
+  (interactive (list
+		(cond
+		 (current-prefix-arg (prefix-numeric-value current-prefix-arg))
+		 ((save-excursion (beginning-of-line)
+				  (looking-at outline-regexp))
+		  (funcall outline-level))
+		 (t 1))))
+  (if (< levels 1)
+      (error "Must keep at least one level of headers"))
+  (save-excursion
+    (let* ((beg (progn
+                  (goto-char (point-min))
+                  ;; Skip the prelude, if any.
+                  (unless (org-at-heading-p) (outline-next-heading))
+                  (point)))
+           (end (progn
+                  (goto-char (point-max))
+                  ;; Keep empty last line, if available.
+                  (max (point-min) (if (bolp) (1- (point)) (point))))))
+      (if (< end beg)
+	  (setq beg (prog1 end (setq end beg))))
+      ;; First hide everything.
+      (org-fold-region beg end t 'headline)
+      ;; Then unhide the top level headers.
+      (org-map-region
+       (lambda ()
+	 (when (<= (funcall outline-level) levels)
+           (org-fold-heading nil)))
+       beg end)
+      ;; Finally unhide any trailing newline.
+      (goto-char (point-max))
+      (if (and (bolp) (not (bobp)) (outline-invisible-p (1- (point))))
+          (org-fold-region (max (point-min) (1- (point))) (point) nil)))))
+
+(defun org-fold-show-entry ()
+  "Show the body directly following its heading.
+Show the heading too, if it is currently invisible."
+  (interactive)
+  (save-excursion
+    (org-back-to-heading-or-point-min t)
+    (org-fold-region
+     (line-end-position 0)
+     (save-excursion
+       (if (re-search-forward
+ 	    (concat "[\r\n]\\(" (org-get-limited-outline-regexp) "\\)") nil t)
+ 	   (match-beginning 1)
+ 	 (point-max)))
+     nil
+     'outline)
+    (org-cycle-hide-drawers 'children)))
+
+(defalias 'org-fold-show-hidden-entry #'org-fold-show-entry
+  "Show an entry where even the heading is hidden.")
+
+(defun org-fold-show-siblings ()
+  "Show all siblings of the current headline."
+  (save-excursion
+    (while (org-goto-sibling) (org-fold-heading nil)))
+  (save-excursion
+    (while (org-goto-sibling 'previous)
+      (org-fold-heading nil))))
+
+(defun org-fold-show-children (&optional level)
+  "Show all direct subheadings of this heading.
+Prefix arg LEVEL is how many levels below the current level
+should be shown.  Default is enough to cause the following
+heading to appear."
+  (interactive "p")
+  (unless (org-before-first-heading-p)
+    (save-excursion
+      (org-with-limited-levels (org-back-to-heading t))
+      (let* ((current-level (funcall outline-level))
+             (max-level (org-get-valid-level
+                         current-level
+                         (if level (prefix-numeric-value level) 1)))
+             (end (save-excursion (org-end-of-subtree t t)))
+             (regexp-fmt "^\\*\\{%d,%s\\}\\(?: \\|$\\)")
+             (past-first-child nil)
+             ;; Make sure to skip inlinetasks.
+             (re (format regexp-fmt
+                         current-level
+                         (cond
+                          ((not (featurep 'org-inlinetask)) "")
+                          (org-odd-levels-only (- (* 2 org-inlinetask-min-level)
+                                                  3))
+                          (t (1- org-inlinetask-min-level))))))
+        ;; Display parent heading.
+        (org-fold-heading nil)
+        (forward-line)
+        ;; Display children.  First child may be deeper than expected
+        ;; MAX-LEVEL.  Since we want to display it anyway, adjust
+        ;; MAX-LEVEL accordingly.
+        (while (re-search-forward re end t)
+          (unless past-first-child
+            (setq re (format regexp-fmt
+                             current-level
+                             (max (funcall outline-level) max-level)))
+            (setq past-first-child t))
+          (org-fold-heading nil))))))
+
+(defun org-fold-show-subtree ()
+  "Show everything after this heading at deeper levels."
+  (interactive)
+  (org-fold-region
+   (point) (save-excursion (org-end-of-subtree t t)) nil 'outline))
+
+(defun org-fold-show-branches ()
+  "Show all subheadings of this heading, but not their bodies."
+  (interactive)
+  (org-fold-show-children 1000))
+
+(defun org-fold-show-branches-buffer--text-properties ()
+  "Show all branches in the buffer."
+  (org-fold-flag-above-first-heading)
+  (org-fold-hide-sublevels 1)
+  (unless (eobp)
+    (org-fold-show-branches)
+    (while (outline-get-next-sibling)
+      (org-fold-show-branches)))
+  (goto-char (point-min)))
+(defun org-fold-show-branches-buffer--overlays ()
+  "Show all branches in the buffer."
+  (org-fold-flag-above-first-heading)
+  (outline-hide-sublevels 1)
+  (unless (eobp)
+    (outline-show-branches)
+    (while (outline-get-next-sibling)
+      (outline-show-branches)))
+  (goto-char (point-min)))
+(defsubst org-fold-show-branches-buffer ()
+  "Show all branches in the buffer."
+  (if (eq org-fold-core-style 'text-properties)
+      (org-fold-show-branches-buffer--text-properties)
+    (org-fold-show-branches-buffer--overlays)))
+
+;;;;; Blocks and drawers visibility
+
+(defun org-fold--hide-wrapper-toggle (element category force no-error)
+  "Toggle visibility for ELEMENT.
+
+ELEMENT is a block or drawer type parsed element.  CATEGORY is
+either `block' or `drawer'.  When FORCE is `off', show the block
+or drawer.  If it is non-nil, hide it unconditionally.  Throw an
+error when not at a block or drawer, unless NO-ERROR is non-nil.
+
+Return a non-nil value when toggling is successful."
+  (let ((type (org-element-type element)))
+    (cond
+     ((memq type
+            (pcase category
+              (`drawer '(drawer property-drawer))
+              (`block '(center-block
+                        comment-block dynamic-block example-block export-block
+                        quote-block special-block src-block verse-block))
+              (_ (error "Unknown category: %S" category))))
+      (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* ((spec (if (eq org-fold-core-style 'text-properties)
+                           category
+                         (if (eq category 'block) 'org-hide-block 'outline)))
+                 (flag
+                  (cond ((eq force 'off) nil)
+                        (force t)
+                        ((if (eq org-fold-core-style 'text-properties)
+                             (org-fold-folded-p start spec)
+                           (eq spec (get-char-property start 'invisible)))
+                         nil)
+                        (t t))))
+            (org-fold-region start end flag spec))
+          ;; When the block 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))
+          ;; Signal success.
+          t)))
+     (no-error nil)
+     (t
+      (user-error (format "%s@%s: %s"
+                          (buffer-file-name (buffer-base-buffer))
+                          (point)
+                          (if (eq category 'drawer)
+	                      "Not at a drawer"
+	                    "Not at a block")))))))
+
+(defun org-fold-hide-block-toggle (&optional force no-error element)
+  "Toggle the visibility of the current block.
+
+When optional argument FORCE is `off', make block visible.  If it
+is non-nil, hide it unconditionally.  Throw an error when not at
+a block, unless NO-ERROR is non-nil.  When optional argument
+ELEMENT is provided, consider it instead of the current block.
+
+Return a non-nil value when toggling is successful."
+  (interactive)
+  (org-fold--hide-wrapper-toggle
+   (or element (org-element-at-point)) 'block force no-error))
+
+(defun org-fold-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)
+  (org-fold--hide-wrapper-toggle
+   (or element (org-element-at-point)) 'drawer force no-error))
+
+(defun org-fold-hide-block-all ()
+  "Fold all blocks in the current buffer."
+  (interactive)
+  (org-block-map (apply-partially #'org-fold-hide-block-toggle 'hide)))
+
+(defun org-fold-hide-drawer-all ()
+  "Fold all drawers in the current buffer."
+  (let ((begin (point-min))
+        (end (point-max)))
+    (org-fold--hide-drawers begin end)))
+
+(defun org-fold--hide-drawers--overlays (begin end)
+  "Hide all drawers between BEGIN and END."
+  (save-excursion
+    (goto-char begin)
+    (while (re-search-forward org-drawer-regexp end t)
+      (let* ((pair (get-char-property-and-overlay (line-beginning-position)
+                                                  'invisible))
+             (o (cdr-safe pair)))
+        (if (overlayp o) (goto-char (overlay-end o)) ;invisible drawer
+          (pcase (get-char-property-and-overlay (point) 'invisible)
+            (`(outline . ,o) (goto-char (overlay-end o))) ;already folded
+            (_
+             (let* ((drawer (org-element-at-point))
+                    (type (org-element-type drawer)))
+               (when (memq type '(drawer property-drawer))
+                 (org-fold-hide-drawer-toggle t nil drawer)
+                 ;; Make sure to skip drawer entirely or we might flag it
+                 ;; another time when matching its ending line with
+                 ;; `org-drawer-regexp'.
+                 (goto-char (org-element-property :end drawer)))))))))))
+(defun org-fold--hide-drawers--text-properties (begin end)
+  "Hide all drawers between BEGIN and END."
+  (save-excursion
+    (goto-char begin)
+    (while (and (< (point) end)
+                (re-search-forward org-drawer-regexp end t))
+      ;; Skip folded drawers
+      (if (org-fold-folded-p nil 'drawer)
+          (goto-char (org-fold-next-folding-state-change 'drawer nil end))
+        (let* ((drawer (org-element-at-point))
+               (type (org-element-type drawer)))
+          (when (memq type '(drawer property-drawer))
+            (org-fold-hide-drawer-toggle t nil drawer)
+            ;; Make sure to skip drawer entirely or we might flag it
+            ;; another time when matching its ending line with
+            ;; `org-drawer-regexp'.
+            (goto-char (org-element-property :end drawer))))))))
+(defun org-fold--hide-drawers (begin end)
+  "Hide all drawers between BEGIN and END."
+  (if (eq org-fold-core-style 'text-properties)
+      (org-fold--hide-drawers--text-properties begin end)
+    (org-fold--hide-drawers--overlays begin end)))
+
+(defun org-fold-hide-archived-subtrees (beg end)
+  "Re-hide all archived subtrees after a visibility state change."
+  (org-with-wide-buffer
+   (let ((case-fold-search nil)
+	 (re (concat org-outline-regexp-bol ".*:" org-archive-tag ":")))
+     (goto-char beg)
+     ;; Include headline point is currently on.
+     (beginning-of-line)
+     (while (and (< (point) end) (re-search-forward re end t))
+       (when (member org-archive-tag (org-get-tags nil t))
+	 (org-fold-subtree t)
+	 (org-end-of-subtree t))))))
+
+;;;;; Reveal point location
+
+(defun org-fold-show-context (&optional key)
+  "Make sure point and context are visible.
+Optional argument KEY, when non-nil, is a symbol.  See
+`org-fold-show-context-detail' for allowed values and how much is to
+be shown."
+  (org-fold-show-set-visibility
+   (cond ((symbolp org-fold-show-context-detail) org-fold-show-context-detail)
+	 ((cdr (assq key org-fold-show-context-detail)))
+	 (t (cdr (assq 'default org-fold-show-context-detail))))))
+
+(defun org-fold-show-set-visibility--overlays (detail)
+  "Set visibility around point according to DETAIL.
+DETAIL is either nil, `minimal', `local', `ancestors',
+`ancestors-full', `lineage', `tree', `canonical' or t.  See
+`org-show-context-detail' for more information."
+  ;; Show current heading and possibly its entry, following headline
+  ;; or all children.
+  (if (and (org-at-heading-p) (not (eq detail 'local)))
+      (org-fold-heading nil)
+    (org-fold-show-entry)
+    ;; If point is hidden within a drawer or a block, make sure to
+    ;; expose it.
+    (dolist (o (overlays-at (point)))
+      (when (memq (overlay-get o 'invisible) '(org-hide-block outline))
+        (delete-overlay o)))
+    (unless (org-before-first-heading-p)
+      (org-with-limited-levels
+       (cl-case detail
+         ((tree canonical t) (org-fold-show-children))
+         ((nil minimal ancestors ancestors-full))
+         (t (save-excursion
+              (outline-next-heading)
+              (org-fold-heading nil)))))))
+  ;; Show whole subtree.
+  (when (eq detail 'ancestors-full) (org-fold-show-subtree))
+  ;; Show all siblings.
+  (when (eq detail 'lineage) (org-fold-show-siblings))
+  ;; Show ancestors, possibly with their children.
+  (when (memq detail '(ancestors ancestors-full lineage tree canonical t))
+    (save-excursion
+      (while (org-up-heading-safe)
+        (org-fold-heading nil)
+        (when (memq detail '(canonical t)) (org-fold-show-entry))
+        (when (memq detail '(tree canonical t)) (org-fold-show-children))))))
+(defvar org-hide-emphasis-markers); Defined in org.el
+(defvar org-pretty-entities); Defined in org.el
+(defun org-fold-show-set-visibility--text-properties (detail)
+  "Set visibility around point according to DETAIL.
+DETAIL is either nil, `minimal', `local', `ancestors',
+`ancestors-full', `lineage', `tree', `canonical' or t.  See
+`org-show-context-detail' for more information."
+  ;; Show current heading and possibly its entry, following headline
+  ;; or all children.
+  (if (and (org-at-heading-p) (not (eq detail 'local)))
+      (org-fold-heading nil)
+    (org-fold-show-entry)
+    ;; If point is hidden make sure to expose it.
+    (when (org-invisible-p)
+      ;; FIXME: No clue why, but otherwise the following might not work.
+      (redisplay)
+      (let ((region (org-fold-get-region-at-point)))
+        ;; Reveal emphasis markers.
+        (let (org-hide-emphasis-markers
+              org-link-descriptive
+              org-pretty-entities
+              (region (or (org-find-text-property-region (point) 'org-emphasis)
+                          (org-find-text-property-region (point) 'invisible)
+                          region)))
+          (when region
+            (org-with-point-at (car region)
+              (beginning-of-line)
+              (let (font-lock-extend-region-functions)
+                (font-lock-fontify-region (1- (car region)) (cdr region))))))
+        (when region
+          (org-fold-region (car region) (cdr region) nil))))
+    (unless (org-before-first-heading-p)
+      (org-with-limited-levels
+       (cl-case detail
+	 ((tree canonical t) (org-fold-show-children))
+	 ((nil minimal ancestors ancestors-full))
+	 (t (save-excursion
+	      (outline-next-heading)
+	      (org-fold-heading nil)))))))
+  ;; Show whole subtree.
+  (when (eq detail 'ancestors-full) (org-fold-show-subtree))
+  ;; Show all siblings.
+  (when (eq detail 'lineage) (org-fold-show-siblings))
+  ;; Show ancestors, possibly with their children.
+  (when (memq detail '(ancestors ancestors-full lineage tree canonical t))
+    (save-excursion
+      (while (org-up-heading-safe)
+	(org-fold-heading nil)
+	(when (memq detail '(canonical t)) (org-fold-show-entry))
+	(when (memq detail '(tree canonical t)) (org-fold-show-children))))))
+(defun org-fold-show-set-visibility (detail)
+  "Set visibility around point according to DETAIL.
+DETAIL is either nil, `minimal', `local', `ancestors', `lineage',
+`tree', `canonical' or t.  See `org-fold-show-context-detail' for more
+information."
+  (if (eq org-fold-core-style 'text-properties)
+      (org-fold-show-set-visibility--text-properties detail)
+    (org-fold-show-set-visibility--overlays detail)))
+
+(defun org-fold-reveal (&optional siblings)
+  "Show current entry, hierarchy above it, and the following headline.
+
+This can be used to show a consistent set of context around
+locations exposed with `org-fold-show-context'.
+
+With optional argument SIBLINGS, on each level of the hierarchy all
+siblings are shown.  This repairs the tree structure to what it would
+look like when opened with hierarchical calls to `org-cycle'.
+
+With a \\[universal-argument] \\[universal-argument] prefix, \
+go to the parent and show the entire tree."
+  (interactive "P")
+  (run-hooks 'org-fold-reveal-start-hook)
+  (cond ((equal siblings '(4)) (org-fold-show-set-visibility 'canonical))
+	((equal siblings '(16))
+	 (save-excursion
+	   (when (org-up-heading-safe)
+	     (org-fold-show-subtree)
+	     (run-hook-with-args 'org-cycle-hook 'subtree))))
+	(t (org-fold-show-set-visibility 'lineage))))
+
+;;; Make isearch search in some text hidden via text propertoes
+
+(defun org-fold--isearch-reveal (&rest _)
+  "Reveal text at POS found by isearch."
+  (org-fold-show-set-visibility 'isearch))
+
+;;; Handling changes in folded elements
+
+(defun org-fold--extend-changed-region (from to)
+  "Consider folded regions in the next/previous line when fixing
+region visibility.
+This function is intended to be used as a member of
+`org-fold-core-extend-changed-region-functions'."
+  ;; If the edit is done in the first line of a folded drawer/block,
+  ;; the folded text is only starting from the next line and needs to
+  ;; be checked.
+  (setq to (save-excursion (goto-char to) (line-beginning-position 2)))
+  ;; If the ":END:" line of the drawer is deleted, the folded text is
+  ;; only ending at the previous line and needs to be checked.
+  (setq from (save-excursion (goto-char from) (line-beginning-position 0)))
+  (cons from to))
+
+(defun org-fold--reveal-outline-maybe (region _)
+  "Reveal folded outline in REGION when needed.
+
+This function is intended to be used as :fragile property of
+`org-fold-outline' spec.  See `org-fold-core--specs' for details."
+  (save-match-data
+    (save-excursion
+      (goto-char (car region))
+      ;; The line before beginning of the fold should be either a
+      ;; headline or a list item.
+      (backward-char)
+      (beginning-of-line)
+      ;; Make sure that headline is not partially hidden
+      (unless (org-fold-folded-p nil 'headline) (org-fold-region (max (point-min) (1- (point))) (line-end-position) nil 'headline))
+      ;; Check the validity of headline
+      (unless (let ((case-fold-search t))
+	        (looking-at (rx-to-string `(or (regex ,(org-item-re))
+			                       (regex ,org-outline-regexp-bol))))) ; the match-data will be used later
+	t))))
+
+(defun org-fold--reveal-drawer-or-block-maybe (region spec)
+  "Reveal folded drawer/block (according to SPEC) in REGION when needed.
+
+This function is intended to be used as :fragile property of
+`org-fold-drawer' or `org-fold-block' spec."
+  (let ((begin-re (cond
+		   ((eq spec (org-fold-core-get-folding-spec-from-alias 'drawer))
+		    org-drawer-regexp)
+		   ;; Group one below contains the type of the block.
+		   ((eq spec (org-fold-core-get-folding-spec-from-alias 'block))
+		    (rx bol (zero-or-more (any " " "\t"))
+			"#+begin"
+			(or ":"
+			    (seq "_"
+				 (group (one-or-more (not (syntax whitespace))))))))))
+        ;; To be determined later. May depend on `begin-re' match (i.e. for blocks).
+        end-re)
+    (save-match-data ; we should not clobber match-data in after-change-functions
+      (let ((fold-begin (car region))
+	    (fold-end (cdr region)))
+	(let (unfold?)
+	  (catch :exit
+	    ;; The line before folded text should be beginning of
+	    ;; the drawer/block.
+	    (save-excursion
+	      (goto-char fold-begin)
+	      ;; The line before beginning of the fold should be the
+	      ;; first line of the drawer/block.
+	      (backward-char)
+	      (beginning-of-line)
+	      (unless (let ((case-fold-search t))
+			(looking-at begin-re)) ; the match-data will be used later
+		(throw :exit (setq unfold? t))))
+            ;; Set `end-re' for the current drawer/block.
+            (setq end-re
+		  (cond
+		   ((eq spec (org-fold-core-get-folding-spec-from-alias 'drawer))
+                    org-property-end-re)
+		   ((eq spec (org-fold-core-get-folding-spec-from-alias 'block))
+		    (let ((block-type (match-string 1))) ; the last match is from `begin-re'
+		      (concat (rx bol (zero-or-more (any " " "\t")) "#+end")
+			      (if block-type
+				  (concat "_"
+					  (regexp-quote block-type)
+					  (rx (zero-or-more (any " " "\t")) eol))
+				(rx (opt ":") (zero-or-more (any " " "\t")) eol)))))))
+	    ;; The last line of the folded text should match `end-re'.
+	    (save-excursion
+	      (goto-char fold-end)
+	      (beginning-of-line)
+	      (unless (let ((case-fold-search t))
+			(looking-at end-re))
+		(throw :exit (setq unfold? t))))
+	    ;; There should be no `end-re' or
+	    ;; `org-outline-regexp-bol' anywhere in the
+	    ;; drawer/block body.
+	    (save-excursion
+	      (goto-char fold-begin)
+	      (when (save-excursion
+		      (let ((case-fold-search t))
+			(re-search-forward (rx-to-string `(or (regex ,end-re)
+						              (regex ,org-outline-regexp-bol)))
+					   (max (point)
+						(1- (save-excursion
+						      (goto-char fold-end)
+						      (line-beginning-position))))
+					   t)))
+		(throw :exit (setq unfold? t)))))
+          unfold?)))))
+
+;; Catching user edits inside invisible text
+(defun org-fold-check-before-invisible-edit--overlays (kind)
+  "Check if editing KIND is dangerous with invisible text around.
+The detailed reaction depends on the user option
+`org-fold-catch-invisible-edits'."
+  ;; First, try to get out of here as quickly as possible, to reduce overhead
+  (when (and org-fold-catch-invisible-edits
+             (or (not (boundp 'visible-mode)) (not visible-mode))
+             (or (get-char-property (point) 'invisible)
+                 (get-char-property (max (point-min) (1- (point))) 'invisible)))
+    ;; OK, we need to take a closer look.  Do not consider
+    ;; invisibility obtained through text properties (e.g., link
+    ;; fontification), as it cannot be toggled.
+    (let* ((invisible-at-point
+            (pcase (get-char-property-and-overlay (point) 'invisible)
+              (`(,_ . ,(and (pred overlayp) o)) o)))
+           ;; Assume that point cannot land in the middle of an
+           ;; overlay, or between two overlays.
+           (invisible-before-point
+            (and (not invisible-at-point)
+                 (not (bobp))
+                 (pcase (get-char-property-and-overlay (1- (point)) 'invisible)
+                   (`(,_ . ,(and (pred overlayp) o)) o))))
+           (border-and-ok-direction
+            (or
+             ;; Check if we are acting predictably before invisible
+             ;; text.
+             (and invisible-at-point
+                  (memq kind '(insert delete-backward)))
+             ;; Check if we are acting predictably after invisible text
+             ;; This works not well, and I have turned it off.  It seems
+             ;; better to always show and stop after invisible text.
+             ;; (and (not invisible-at-point) invisible-before-point
+             ;;  (memq kind '(insert delete)))
+             )))
+      (when (or invisible-at-point invisible-before-point)
+        (when (eq org-fold-catch-invisible-edits 'error)
+          (user-error "Editing in invisible areas is prohibited, make them visible first"))
+        (if (and org-custom-properties-overlays
+                 (y-or-n-p "Display invisible properties in this buffer? "))
+            (org-toggle-custom-properties-visibility)
+          ;; Make the area visible
+          (save-excursion
+            (when invisible-before-point
+              (goto-char
+               (previous-single-char-property-change (point) 'invisible)))
+            ;; Remove whatever overlay is currently making yet-to-be
+            ;; edited text invisible.  Also remove nested invisibility
+            ;; related overlays.
+            (delete-overlay (or invisible-at-point invisible-before-point))
+            (let ((origin (if invisible-at-point (point) (1- (point)))))
+              (while (pcase (get-char-property-and-overlay origin 'invisible)
+                       (`(,_ . ,(and (pred overlayp) o))
+                        (delete-overlay o)
+                        t)))))
+          (cond
+           ((eq org-fold-catch-invisible-edits 'show)
+            ;; That's it, we do the edit after showing
+            (message
+             "Unfolding invisible region around point before editing")
+            (sit-for 1))
+           ((and (eq org-fold-catch-invisible-edits 'smart)
+                 border-and-ok-direction)
+            (message "Unfolding invisible region around point before editing"))
+           (t
+            ;; Don't do the edit, make the user repeat it in full visibility
+            (user-error "Edit in invisible region aborted, repeat to confirm with text visible"))))))))
+(defun org-fold-check-before-invisible-edit--text-properties (kind)
+  "Check if editing KIND is dangerous with invisible text around.
+The detailed reaction depends on the user option
+`org-fold-catch-invisible-edits'."
+  ;; First, try to get out of here as quickly as possible, to reduce overhead
+  (when (and org-fold-catch-invisible-edits
+	     (or (not (boundp 'visible-mode)) (not visible-mode))
+	     (or (org-invisible-p)
+		 (org-invisible-p (max (point-min) (1- (point))))))
+    ;; OK, we need to take a closer look.  Only consider invisibility
+    ;; caused by folding.
+    (let* ((invisible-at-point (org-invisible-p))
+	   (invisible-before-point
+	    (and (not (bobp))
+	         (org-invisible-p (1- (point)))))
+	   (border-and-ok-direction
+	    (or
+	     ;; Check if we are acting predictably before invisible
+	     ;; text.
+	     (and invisible-at-point (not invisible-before-point)
+		  (memq kind '(insert delete-backward)))
+	     (and (not invisible-at-point) invisible-before-point
+		  (memq kind '(insert delete))))))
+      (when (or invisible-at-point invisible-before-point)
+	(when (eq org-fold-catch-invisible-edits 'error)
+	  (user-error "Editing in invisible areas is prohibited, make them visible first"))
+	(if (and org-custom-properties-hidden-p
+		 (y-or-n-p "Display invisible properties in this buffer? "))
+	    (org-toggle-custom-properties-visibility)
+	  ;; Make the area visible
+          (save-excursion
+	    (org-fold-show-set-visibility 'local))
+          (when invisible-before-point
+            (org-with-point-at (1- (point)) (org-fold-show-set-visibility 'local)))
+	  (cond
+	   ((eq org-fold-catch-invisible-edits 'show)
+	    ;; That's it, we do the edit after showing
+	    (message
+	     "Unfolding invisible region around point before editing")
+	    (sit-for 1))
+	   ((and (eq org-fold-catch-invisible-edits 'smart)
+		 border-and-ok-direction)
+	    (message "Unfolding invisible region around point before editing"))
+	   (t
+	    ;; Don't do the edit, make the user repeat it in full visibility
+	    (user-error "Edit in invisible region aborted, repeat to confirm with text visible"))))))))
+(defsubst org-fold-check-before-invisible-edit (kind)
+  "Check if editing KIND is dangerous with invisible text around.
+The detailed reaction depends on the user option
+`org-fold-catch-invisible-edits'."
+  ;; First, try to get out of here as quickly as possible, to reduce overhead
+  (if (eq org-fold-core-style 'text-properties)
+      (org-fold-check-before-invisible-edit--text-properties kind)
+    (org-fold-check-before-invisible-edit--overlays kind)))
+
+(provide 'org-fold)
+
+;;; org-fold.el ends here

  parent reply	other threads:[~2022-01-29 11:36 UTC|newest]

Thread overview: 192+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-24  6:55 [patch suggestion] Mitigating the poor Emacs performance on huge org files: Do not use overlays for PROPERTY and LOGBOOK drawers Ihor Radchenko
2020-04-24  8:02 ` Nicolas Goaziou
2020-04-25  0:29   ` stardiviner
2020-04-26 16:04   ` Ihor Radchenko
2020-05-04 16:56     ` Karl Voit
2020-05-07  7:18       ` Karl Voit
2020-05-09 15:43       ` Ihor Radchenko
2020-05-07 11:04     ` Christian Heinrich
2020-05-09 15:46       ` Ihor Radchenko
2020-05-08 16:38     ` Nicolas Goaziou
2020-05-09 13:58       ` Nicolas Goaziou
2020-05-09 16:22         ` Ihor Radchenko
2020-05-09 17:21           ` Nicolas Goaziou
2020-05-10  5:25             ` Ihor Radchenko
2020-05-10  9:47               ` Nicolas Goaziou
2020-05-10 13:29                 ` Ihor Radchenko
2020-05-10 14:46                   ` Nicolas Goaziou
2020-05-10 16:21                     ` Ihor Radchenko
2020-05-10 16:38                       ` Nicolas Goaziou
2020-05-10 17:08                         ` Ihor Radchenko
2020-05-10 19:38                           ` Nicolas Goaziou
2020-05-09 15:40       ` Ihor Radchenko
2020-05-09 16:30         ` Ihor Radchenko
2020-05-09 17:32           ` Nicolas Goaziou
2020-05-09 18:06             ` Ihor Radchenko
2020-05-10 14:59               ` Nicolas Goaziou
2020-05-10 15:15                 ` Kyle Meyer
2020-05-10 16:30                 ` Ihor Radchenko
2020-05-10 19:32                   ` Nicolas Goaziou
2020-05-12 10:03                     ` Nicolas Goaziou
2020-05-17 15:00                     ` Ihor Radchenko
2020-05-17 15:40                       ` Ihor Radchenko
2020-05-18 14:35                         ` Nicolas Goaziou
2020-05-18 16:52                           ` Ihor Radchenko
2020-05-19 13:07                             ` Nicolas Goaziou
2020-05-23 13:52                               ` Ihor Radchenko
2020-05-23 13:53                                 ` Ihor Radchenko
2020-05-23 15:26                                   ` Ihor Radchenko
2020-05-26  8:33                                 ` Nicolas Goaziou
2020-06-02  9:21                                   ` Ihor Radchenko
2020-06-02  9:23                                     ` Ihor Radchenko
2020-06-02 12:10                                       ` Bastien
2020-06-02 13:12                                         ` Ihor Radchenko
2020-06-02 13:23                                           ` Bastien
2020-06-02 13:30                                             ` Ihor Radchenko
2020-06-02  9:25                                     ` Ihor Radchenko
2020-06-05  7:26                                     ` Nicolas Goaziou
2020-06-05  8:18                                       ` Ihor Radchenko
2020-06-05 13:50                                         ` Nicolas Goaziou
2020-06-08  5:05                                           ` Ihor Radchenko
2020-06-08  5:06                                             ` Ihor Radchenko
2020-06-08  5:08                                             ` Ihor Radchenko
2020-06-10 17:14                                             ` Nicolas Goaziou
2020-06-21  9:52                                               ` Ihor Radchenko
2020-06-21 15:01                                                 ` Nicolas Goaziou
2020-08-11  6:45                                               ` Ihor Radchenko
2020-08-11 23:07                                                 ` Kyle Meyer
2020-08-12  6:29                                                   ` Ihor Radchenko
2020-09-20  5:53                                                     ` Ihor Radchenko
2020-09-20 11:45                                                       ` Kévin Le Gouguec
2020-09-22  9:05                                                         ` Ihor Radchenko
2020-09-22 10:00                                                           ` Ihor Radchenko
2020-09-23  6:16                                                             ` Kévin Le Gouguec
2020-09-23  6:48                                                               ` Ihor Radchenko
2020-09-23  7:09                                                                 ` Bastien
2020-09-23  7:30                                                                   ` Ihor Radchenko
2020-09-24 18:07                                                                 ` Kévin Le Gouguec
2020-09-25  2:16                                                                   ` Ihor Radchenko
2020-12-15 17:38                                                                     ` [9.4] Fixing logbook visibility during isearch Kévin Le Gouguec
2020-12-16  3:15                                                                       ` Ihor Radchenko
2020-12-16 18:05                                                                         ` Kévin Le Gouguec
2020-12-17  3:18                                                                           ` Ihor Radchenko
2020-12-17 14:50                                                                             ` Kévin Le Gouguec
2020-12-18  2:23                                                                               ` Ihor Radchenko
2020-12-24 23:37                                                                                 ` Kévin Le Gouguec
2020-12-25  2:51                                                                                   ` Ihor Radchenko
2020-12-25 10:59                                                                                     ` Kévin Le Gouguec
2020-12-25 12:32                                                                                       ` Ihor Radchenko
2020-12-25 21:35                                                                                     ` Kévin Le Gouguec
2020-12-26  4:14                                                                                       ` Ihor Radchenko
2020-12-26 11:44                                                                                         ` Kévin Le Gouguec
2020-12-26 12:22                                                                                           ` Ihor Radchenko
2020-12-04  5:58                                                       ` [patch suggestion] Mitigating the poor Emacs performance on huge org files: Do not use overlays for PROPERTY and LOGBOOK drawers Ihor Radchenko
2021-03-21  9:09                                                         ` Ihor Radchenko
2021-05-03 17:28                                                           ` Bastien
2021-09-21 13:32                                                             ` Timothy
2021-10-26 17:25                                                               ` Matt Price
2021-10-27  6:27                                                                 ` Ihor Radchenko
2022-01-29 11:37                                                             ` [PATCH 00/35] Merge org-fold feature branch Ihor Radchenko
2022-01-29 11:37                                                               ` [PATCH 01/35] Add org-fold-core: new folding engine Ihor Radchenko
2022-01-29 11:37                                                               ` Ihor Radchenko [this message]
2022-01-29 11:37                                                               ` [PATCH 03/35] Separate cycling functions from org.el into new library: org-cycle Ihor Radchenko
2022-01-29 11:37                                                               ` [PATCH 04/35] Remove functions from org.el that are now moved elsewhere Ihor Radchenko
2022-01-29 11:37                                                               ` [PATCH 05/35] Disable native-comp in agenda Ihor Radchenko
2022-01-29 11:37                                                               ` [PATCH 06/35] org-macs: New function org-find-text-property-region Ihor Radchenko
2022-01-29 11:37                                                               ` [PATCH 07/35] org-at-heading-p: Accept optional argument Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 08/35] org-string-width: Reimplement to work with new folding Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 09/35] Rename old function call to use org-fold Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 10/35] Implement link folding Ihor Radchenko
2022-05-04  6:13                                                                 ` [BUG] 67275f4 broke evil-search " Tom Gillespie
2022-05-04  6:38                                                                   ` Ihor Radchenko
2022-05-28  2:17                                                                     ` Tom Gillespie
2022-05-28  2:37                                                                       ` Ihor Radchenko
2022-05-28  2:42                                                                         ` Tom Gillespie
2022-05-28  3:09                                                                           ` Ihor Radchenko
2022-05-28  3:11                                                                           ` Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 11/35] Implement overlay- and text-property-based versions of some functions Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 12/35] org-fold: Handle indirect buffer visibility Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 13/35] Fix subtle differences between overlays and invisible text properties Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 14/35] Support extra org-fold optimisations for huge buffers Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 15/35] Alias new org-fold functions to their old shorter names Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 16/35] Obsolete old function names that are now in org-fold Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 17/35] org-compat: Work around some third-party packages using outline-* functions Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 18/35] Move `org-buffer-list' to org-macs.el Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 19/35] Restore old visibility behaviour of org-refile Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 20/35] Add org-fold-related tests Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 21/35] org-manual: Update to new org-fold function names Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 22/35] ORG-NEWS: Add list of changes Ihor Radchenko
2022-01-29 20:31                                                                 ` New folding backend & outline (was: [PATCH 22/35] ORG-NEWS: Add list of changes) Kévin Le Gouguec
2022-01-30  2:15                                                                   ` Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 23/35] Backport contributed commits Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 24/35] Fix typo: delete-duplicates → delete-dups Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 25/35] Fix bug in org-get-heading Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 26/35] Rename remaining org-force-cycle-archived → org-cycle-force-archived Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 27/35] Fix org-fold--hide-drawers--overlays Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 28/35] org-string-width: Handle undefined behaviour in older Emacs Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 29/35] org-string-width: Work around `window-pixel-width' bug in old Emacs Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 30/35] org-fold-show-set-visibility: Fix edge case when folded region is at BOB Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 31/35] org-fold-core: Fix fontification inside folded regions Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 32/35] test-org/string-width: Add tests for strings with prefix properties Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 33/35] org--string-from-props: Fix handling folds in Emacs <28 Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 34/35] org-link-make-string: Throw error when both LINK and DESCRIPTION are empty Ihor Radchenko
2022-01-29 11:38                                                               ` [PATCH 35/35] test-ol/org-toggle-link-display: Fix compatibility with old Emacs Ihor Radchenko
2022-02-03  6:27                                                               ` [PATCH 00/35] Merge org-fold feature branch Bastien
2022-02-03  7:07                                                                 ` Ihor Radchenko
2022-04-20 13:23                                                                   ` [PATCH v2 00/38] Final call for comments: " Ihor Radchenko
2022-04-20 13:23                                                                     ` [PATCH v2 01/38] Add org-fold-core: new folding engine--- Ihor Radchenko
2022-04-20 13:24                                                                     ` [PATCH v2 02/38] Separate folding functions from org.el into new library: org-fold Ihor Radchenko
2022-04-20 13:24                                                                     ` [PATCH v2 03/38] Separate cycling functions from org.el into new library: org-cycle Ihor Radchenko
2022-04-20 13:24                                                                     ` [PATCH v2 04/38] Remove functions from org.el that are now moved elsewhere Ihor Radchenko
2022-04-20 13:24                                                                     ` [PATCH v2 05/38] Disable native-comp in agendaIt caused cryptic bugs in the past Ihor Radchenko
2022-04-20 13:24                                                                     ` [PATCH v2 06/38] org-macs: New function org-find-text-property-region--- Ihor Radchenko
2022-04-20 13:24                                                                     ` [PATCH v2 07/38] org-at-heading-p: Accept optional argument* lisp/org.el (org-at-heading-p): Use second argument to allow Ihor Radchenko
2022-04-20 13:25                                                                     ` [PATCH v2 08/38] org-string-width: Reimplement to work with new folding Ihor Radchenko
2022-04-20 13:25                                                                     ` [PATCH v2 09/38] Rename old function call to use org-fold--- Ihor Radchenko
2022-04-20 13:25                                                                     ` [PATCH v2 10/38] Implement link folding* lisp/ol.el (org-link--link-folding-spec): Ihor Radchenko
2022-04-20 13:25                                                                     ` [PATCH v2 11/38] Implement overlay- and text-property-based versions of some functions Ihor Radchenko
2022-04-20 13:25                                                                     ` [PATCH v2 12/38] org-fold: Handle indirect buffer visibility--- Ihor Radchenko
2022-04-20 13:25                                                                     ` [PATCH v2 13/38] Fix subtle differences between overlays and invisible text properties Ihor Radchenko
2022-04-20 13:25                                                                     ` [PATCH v2 14/38] Support extra org-fold optimisations for huge buffers Ihor Radchenko
2022-04-20 13:25                                                                     ` [PATCH v2 15/38] Alias new org-fold functions to their old shorter names Ihor Radchenko
2022-04-20 13:25                                                                     ` [PATCH v2 16/38] Obsolete old function names that are now in org-fold--- Ihor Radchenko
2022-04-20 13:26                                                                     ` [PATCH v2 17/38] org-compat: Work around some third-party packages using outline-* functions Ihor Radchenko
2022-04-20 13:26                                                                     ` [PATCH v2 18/38] Move `org-buffer-list' to org-macs.el--- Ihor Radchenko
2022-04-20 13:26                                                                     ` [PATCH v2 19/38] Restore old visibility behaviour of org-refile--- Ihor Radchenko
2022-04-20 13:26                                                                     ` [PATCH v2 20/38] Add org-fold-related tests--- Ihor Radchenko
2022-04-20 13:26                                                                     ` [PATCH v2 21/38] org-manual: Update to new org-fold function names--- Ihor Radchenko
2022-04-20 13:26                                                                     ` [PATCH v2 22/38] ORG-NEWS: Add list of changes--- Ihor Radchenko
2022-04-20 13:26                                                                     ` [PATCH v2 23/38] Backport contributed commits--- Ihor Radchenko
2022-04-20 13:26                                                                     ` [PATCH v2 24/38] Fix typo: delete-duplicates → delete-dups Anders Johansson
2022-04-20 13:26                                                                     ` [PATCH v2 25/38] Fix bug in org-get-headingFixes #26, where fontification could make the matching and extraction of heading Anders Johansson
2022-04-20 13:27                                                                     ` [PATCH v2 26/38] Rename remaining org-force-cycle-archived Anders Johansson
2022-04-20 13:27                                                                     ` [PATCH v2 27/38] Fix org-fold--hide-drawers--overlays--- Ihor Radchenko
2022-04-20 13:27                                                                     ` [PATCH v2 28/38] org-string-width: Handle undefined behaviour in older Emacs Ihor Radchenko
2022-04-20 13:27                                                                     ` [PATCH v2 29/38] org-string-width: Work around `window-pixel-width' bug in old Emacs Ihor Radchenko
2022-04-20 13:27                                                                     ` [PATCH v2 30/38] org-fold-show-set-visibility: Fix edge case when folded region is at BOB Ihor Radchenko
2022-04-20 13:28                                                                     ` [PATCH v2 31/38] org-fold-core: Fix fontification inside folded regions Ihor Radchenko
2022-04-20 13:28                                                                     ` [PATCH v2 32/38] test-org/string-width: Add tests for strings with prefix properties Ihor Radchenko
2022-04-20 13:28                                                                     ` [PATCH v2 33/38] org--string-from-props: Fix handling folds in Emacs <28 Ihor Radchenko
2022-04-20 13:28                                                                     ` [PATCH v2 34/38] org-link-make-string: Throw error when both LINK and DESCRIPTION are empty Ihor Radchenko
2022-04-20 13:28                                                                     ` [PATCH v2 35/38] test-ol/org-toggle-link-display: Fix compatibility with old Emacs Ihor Radchenko
2022-04-20 13:28                                                                     ` [PATCH v2 36/38] org-macs.el: Fix fontification checks take 2--- Ihor Radchenko
2022-04-20 13:28                                                                     ` [PATCH v2 37/38] org-fold-core-fontify-region: Fix cases when fontification is not registered Ihor Radchenko
2022-04-20 13:28                                                                     ` [PATCH v2 38/38] org-agenda.el: Re-enable native compilation* lisp/org-agenda.el: Re-enable native compilation as it does not Ihor Radchenko
2022-04-20 14:47                                                                     ` [PATCH v2 00/38] Final call for comments: Merge org-fold feature branch Bastien
2022-04-20 15:38                                                                       ` Ihor Radchenko
2022-04-20 16:22                                                                         ` Bastien
2022-04-21  6:01                                                                           ` Ihor Radchenko
2022-04-21  6:55                                                                             ` Bastien
2022-04-21  9:27                                                                               ` Ihor Radchenko
2022-04-21  9:43                                                                                 ` Bastien
2022-04-22 18:54                                                                     ` Kévin Le Gouguec
2022-04-25 11:44                                                                       ` Ihor Radchenko
2022-04-25 13:02                                                                         ` Bastien
2022-04-25 13:25                                                                           ` Ihor Radchenko
2022-04-25 14:05                                                                             ` Bastien
2022-04-26 11:48                                                                               ` Ihor Radchenko
2022-04-25 11:45                                                                       ` Ihor Radchenko
2022-04-26  6:10                                                                         ` Kévin Le Gouguec
2022-05-03  4:44                                                                     ` [ISSUE] org-fold does not support auto-reveal for some external package commands Christopher M. Miles
     [not found]                                                                     ` <6270b43a.1c69fb81.835d4.54a6SMTPIN_ADDED_BROKEN@mx.google.com>
2022-05-03  6:33                                                                       ` Ihor Radchenko
2022-05-03 10:19                                                                         ` [DONE] " Christopher M. Miles

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a36ac8670ea6eda6b25b0be5ff1ee4afdd46e34a.1643454546.git.yantar92@gmail.com \
    --to=yantar92@gmail.com \
    --cc=bzg@gnu.org \
    --cc=christian@gladbachcity.de \
    --cc=devnull@Karl-Voit.at \
    --cc=emacs-orgmode@gnu.org \
    --cc=kyle@kyleam.com \
    --cc=mail@nicolasgoaziou.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).