* lisp/org.el: (org-auto-emphasis-unhide-at-point): Parameter that controls the behavior of Org Auto Emphasis mode. It can be one of the values nil, t, and 'right-edge, and works similarly to the parameter `prettify-symbols-unprettify-at-point' for `prettify-symbols-mode'. (org-do-emphasis-faces): When hiding emphasis markers, add additional text properties 'org-emph-start and org-emph-end to the emphasized region. (org-auto-emphasis--current-region-bounds): Local variable containing the bounds of the region whose emphasis markers are currently unhidden. (org-auto-emphasis--get-prop-as-list): Helper function that returns Org Auto Emphasis properties as a list. (org-auto-emphasis--post-command-hook): Function added to `post-command-hook' that rehides emphasis markers for the previous region and unhides emphasis marks for the current region. (org-auto-emphasis-mode): Toggles Org Auto Emphasis mode. Can be added to `org-mode-hook' to be enabled for all org-mode files. This code was adapted from prettify-symbols-mode in prog-mode.el I have not yet signed the papers assigning copyright to the FSF. I sent a request for the papers to assign@gnu.org, but have not yet received a response. Shankar Rao --- lisp/org.el | 98 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 11 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index 7ff7ec685..870c5c958 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -3644,6 +3644,19 @@ following symbols: :type 'boolean :safe #'booleanp) +(defcustom org-auto-emphasis-unhide-at-point nil + "If non-nil, unhide the emphasis markers for the region when point is on it. +If set to the symbol `right-edge', also unhide the emphasis +markers if point is immediately after the emphasized region. The +emphasis markers will be rehidden as soon as point moves away +from the region. If set to nil, the emphasis markers remain +hidden even when point is in the region." + :version "25.1" + :type '(choice (const :tag "Never unhide emphasis markers" nil) + (const :tag "Unhide emphasis markers when point is inside" t) + (const :tag "Unhide emphasis markers when point is inside or at right edge" right-edge)) + :group 'org-appearance) + (defcustom org-hide-macro-markers nil "Non-nil mean font-lock should hide the brackets marking macro calls." :group 'org-appearance @@ -5056,12 +5069,77 @@ stacked delimiters is N. Escaping delimiters is not possible." '(font-lock-multiline t org-emphasis t)) (when (and org-hide-emphasis-markers (not (org-at-comment-p))) - (add-text-properties (match-end 4) (match-beginning 5) - '(invisible org-link)) - (add-text-properties (match-beginning 3) (match-end 3) - '(invisible org-link))) + (let ((s1 (match-beginning 3)) + (e1 (match-end 3)) + (s2 (match-end 4)) + (e2 (match-beginning 5))) + (add-text-properties s2 e2 '(invisible org-link)) + (add-text-properties s1 e1 '(invisible org-link)) + (add-text-properties s1 e2 + `(org-emph-start ,s1 org-emph-end ,e2)))) (throw :exit t)))))))) +(defvar-local org-auto-emphasis--current-region-bounds nil) + +(defun org-auto-emphasis--get-prop-as-list (prop) + "Helper function to get org-auto-emphasis properties as a list. +If `org-auto-emphasis-unhide-at-point' is set to `t' then return +the text property PROP at point in a list. If +`org-auto-emphasis-unhide-at-point' is set to `right-edge', the +also include the text property PROP at point-1 unless we are at +the beginning of the buffer." + (remove nil + (list (get-text-property (point) prop) + (when (and (eq org-auto-emphasis-unhide-at-point 'right-edge) + (not (bobp))) + (get-text-property (1- (point)) prop))))) + +(defun org-auto-emphasis--post-command-hook () + ;; Rehide emphasis markers for the previous region. + (when (and org-auto-emphasis--current-region-bounds + (or (< (point) (car org-auto-emphasis--current-region-bounds)) + (> (point) (cadr org-auto-emphasis--current-region-bounds)) + (and (not (eq org-auto-emphasis-unhide-at-point 'right-edge)) + (= (point) (cadr org-auto-emphasis--current-region-bounds))))) + (apply #'font-lock-flush org-auto-emphasis--current-region-bounds) + (setq org-auto-emphasis--current-region-bounds nil)) + ;; Unhide emphasis markers for the current region. + (when-let* ((s (org-auto-emphasis--get-prop-as-list 'org-emph-start)) + (e (org-auto-emphasis--get-prop-as-list 'org-emph-end)) + (s (apply #'min s)) + (e (apply #'max e))) + (with-silent-modifications + (setq org-auto-emphasis--current-region-bounds (list s e)) + (remove-text-properties s (1+ s) '(invisible org-link)) + (remove-text-properties (1- e) e '(invisible org-link))))) + +(define-minor-mode org-auto-emphasis-mode + "Toggle Org Auto Emphasis mode. +This mode, when enabled, unhides emphasis markers for the region +at point, depending on the value of +`org-auto-emphasis-unhide-at-point'. With a prefix argument ARG, +enable Org Auto Emphasis mode if ARG is positive, and disable it +otherwise. If called from Lisp, enable the mode if ARG is +omitted or nil. + +To enable this in all org-mode files, add the following line to init.el: + + (add-hook 'org-mode #'org-auto-emphasis-mode) +" + :init-value nil + (if org-auto-emphasis-mode + ;; Turn on + (progn + (setq-local font-lock-extra-managed-props + (append font-lock-extra-managed-props + '(org-emph-start org-emph-end))) + (when org-auto-emphasis-unhide-at-point + (add-hook 'post-command-hook + #'org-auto-emphasis--post-command-hook nil t)) + (font-lock-flush)) + ;; Turn off + (remove-hook 'post-command-hook #'org-auto-emphasis--post-command-hook t))) + (defun org-emphasize (&optional char) "Insert or change an emphasis, i.e. a font like bold or italic. If there is an active region, change that region to a new emphasis. @@ -20482,16 +20560,15 @@ With ARG, repeats or can move backward if negative." (beginning-of-line)) (_ nil))) (cl-incf arg)) - (while (and (> arg 0) (re-search-forward regexp nil t)) + (while (and (> arg 0) (re-search-forward regexp nil :move)) (pcase (get-char-property-and-overlay (point) 'invisible) (`(outline . ,o) (goto-char (overlay-end o)) - (skip-chars-forward " \t\n") - (end-of-line)) + (end-of-line 2)) (_ (end-of-line))) (cl-decf arg)) - (if (> arg 0) (goto-char (point-max)) (beginning-of-line)))) + (when (/= arg initial-arg) (beginning-of-line)))) (defun org-previous-visible-heading (arg) "Move to the previous visible heading. @@ -20830,11 +20907,10 @@ ones already marked." (set-mark (save-excursion (goto-char (mark)) - (goto-char (org-element-property :end (org-element-at-point))) - (point))) + (goto-char (org-element-property :end (org-element-at-point))))) (let ((element (org-element-at-point))) (end-of-line) - (push-mark (min (point-max) (org-element-property :end element)) t t) + (push-mark (org-element-property :end element) t t) (goto-char (org-element-property :begin element)))))) (defun org-narrow-to-element () -- 2.17.1