branch: externals/org-modern commit 8cad2c3d839a720be32b25e12946572b8e569ca2 Merge: 3cc432dc99 fe226e8bc1 Author: Daniel Mendler <m...@daniel-mendler.de> Commit: GitHub <nore...@github.com>
Merge pull request #281 from minad/org-modern-indent Org modern indent --- CHANGELOG.org | 33 ++++- README.org | 91 ++++++++++++- org-modern-indent.el | 374 +++++++++++++++++++++++++++++++++++++++++++++++++++ org-modern.el | 17 ++- 4 files changed, 508 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.org b/CHANGELOG.org index 59f4d9acf3..c25a84ba62 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -1,9 +1,11 @@ #+title: org-modern.el - Changelog -#+author: Daniel Mendler +#+author: Daniel Mendler & J.D. Smith #+language: en * Development +- Merged [[https://github.com/jdtsmith/org-modern-indent][org-modern-indent]] as a new extension. +- Automatically provide code block bracket styling when ~org-indent~ is enabled using ~org-modern-indent-mode~. - Add ~org-modern-habit~ face to improve habit progress fontification. * Version 1.7 (2025-03-11) @@ -67,3 +69,32 @@ * Version 0.8 (2023-02-15) - Start of changelog. + +* org-modern-indent change history + +~org-modern-indent~ was incorporated as an extension to ~org-modern~ in v2.0. The prior change history for ~org-modern-indent~ is as follows, based on its release versions as a separate package: + +- **v0.6**: Merged as an ~org-modern~ extension. +- **v0.5.1**: Small simplifications for block drawing. +- **v0.5**: Another complete rewrite which substantially improves + performance and accuracy. Now block detection uses ~org-element~ + and the block styling is implemented in + ~before/after-change-functions~. Benefits include: + 1. Higher performance and more reliable fontification. + 2. Ability to detect and correctly treat _damaged_ blocks + (header/footer line altered or removed) as well as _merged_ blocks. + 2. Caches all prefix strings for lower memory usage/GC churn. + 3. No more "runaway" formatting when partial blocks are created: + only _real_ blocks (according to ~org-element~) are + + Note that v0.5 implements indented block styling using display + properties on the indentation text, so navigation will "skip over" + it. +- **v0.1**: features a complete re-write to use font-lock directly. This + has a few benefits: + 1. No longer relies on org-mode face names for recognizing + blocks, so ~org-src-block-faces~ can have arbitrary faces + applied, e.g. for different ~src~ languages, as in the screenshot. + 2. Eliminates the "race" between font-locking and applying the prefix text properties. + 3. Enables in-text bracket decorations for "bulk-indented" blocks, for example blocks situated + in an arbitrarily-nested plain list item. diff --git a/README.org b/README.org index 1409c4983c..1c87a05c18 100644 --- a/README.org +++ b/README.org @@ -33,6 +33,16 @@ recommend variants of the [[https://github.com/be5invis/Iosevka][Iosevka]] font, the Org buffer. Larger values of =line-spacing= are not recommended, since Emacs does not center the text vertically (see Emacs [[https://debbugs.gnu.org/cgi/bugreport.cgi?bug=76390][bug#76390]]). +* Indent + +Since version 2.0, this package also incorporates ~org-modern-indent~, which provides block bracket styling when ~org-indent~ is enabled, including support for "bulk-indented" blocks nested within plain lists: + +#+html: <img width="716" alt="image" src="https://github.com/user-attachments/assets/7ca42ce7-dcfb-4c66-b5f4-1798a4fd4df5" /> + +~org-modern-indent~ is enabled by ~org-modern~ by default if you use ~org-indent~; configure ~org-modern-indent-block=nil~ to disable this behavior. To activate ~org-indent-mode~ in all org files, set ~org-startup-indented=t~. + +*Note*: Non-nil ~line-spacing~ is not recommended with ~org-modern-indent~, as it leads to gaps in the vertical bars drawn to indicate blocks. + * Configuration The package is available on GNU ELPA and MELPA. You can install the package with @@ -93,14 +103,89 @@ screenshot above after the installation of =org-modern=. (global-org-modern-mode) #+end_src +An alternative setup, using ~use-package~ and modifying some of the display entities: + +#+begin_src emacs-lisp + (use-package org-modern + :custom + (org-modern-hide-stars nil) + (org-modern-todo-faces + '(("STARTED" :foreground "yellow") + ("CANCELED" org-special-keyword :inverse-video t :weight bold))) + (org-modern-list + '((?* . "•") + (?+ . "‣"))) + (org-modern-fold-stars + '(("▶" . "▼") + ("▷" . "▽") + ("▸" . "▾") + ("▹" . "▿"))) + (org-modern-checkbox + '((?X . "✔") + (?- . "┅") + (?\s . " "))) + (org-modern-label-border 1) + :hook + (org-mode . org-modern-mode) + (org-agenda-finalize . org-modern-agenda)) +#+end_src + + * Incompatibilities -- =org-indent-mode= is not compatible with the block prettification in the fringe. - If =org-indent-mode= is enabled, =org-modern= will disable the block prettification. - =org-num-mode= interferes with the =org-modern= prettification of TODO keywords. - =visual-wrap-prefix-mode= relies on the =wrap-prefix= text property which is also used by =org-modern=. +* Block Indentation Hints + +A few hints for managing indented blocks. + +** Bulk-indented blocks (e.g. within plain lists): + +Bulk-indented blocks have "real" (space/tab) indentation applied and managed by org. This extra indentation is applied by org on _top_ of the (fake, prefix-based) indentation used by org-indent. To nest blocks properly within such indented content, e.g. in plain list items, you only have to begin the ~#+begin~ at the same level as the list element's text. + +As an important principle, ~org-modern-indent~ does not alter the contents of the text in your org documents, not even indentation. It just styles what is there. To help achieve proper block bulk-indented alignment, here are a few ways to alter blocks indentation using org and other commands: + +- **Start things right**: Hit return after your last line of text (e.g in a list item), then immediately hit =C-c C,= to create the desired block. It will be indented at the right level: + + #+begin_src org + - This list item contains a: + - sublist, which holds a block: + [C-c C-,] here + #+end_src + +- *Move flush left*: Note: =M-{= will get you to the start of a block quickly. =M-\= at block start will move the block's first header line to column 0. Then =M-S-left= (or =right=) will indent the full block. +- *Indent rigidly*: =M-h= selects the entire block. Then =C-x TAB= enters "rigid indent" mode, after which left/right moves the entire block. +- *Re-indent a block*: If you have a block that is partially aligned, perhaps with a "hanging end", like so: + + #+begin_src org + + - List 1 + - List 2 + ,#+begin_src lang + foo_lang(x) + ,#+end_src + #+end_src + + you can simply use =M-S-left/right= at block start (or in fact anywhere on the block header/footer) to ~org-indent-block~. Note that ~org-src-preserve-indentation=nil~ is an important setting, to allow org to (re-)indent blocks to respect the local indentation inside list and other elements. Also note that (from ~org-indent-region~): + + #+begin_quote + The function will not indent contents of example blocks, verse blocks and export blocks as leading white spaces are assumed to be significant there. + #+end_quote + +** Font spacing and faces + +The default ~fixed-pitch~ font (from which ~org-meta-line~ inherits) has line spacing >1.0 on some systems. This will introduce gaps _even if your default font is changed_, and ~line-space~ is nil. To correct it, add: + +#+begin_src emacs-lisp +(set-face-attribute 'fixed-pitch nil :family "Hack" :height 1.0) ; or whatever font family +#+end_src + +*** The bracket style + +If you'd like a different face than ~org-meta-line~ for the "bracket", configure the ~org-modern-indent-bracket-line~ face. + * Alternatives The tag style of =org-modern= is inspired by Nicholas Rougier's [[https://github.com/rougier/svg-tag-mode][svg-tag-mode]]. In @@ -116,7 +201,7 @@ table and block styling from =org-modern=. If you are interested in further tweaks, Emacs comes with the builtin =prettify-symbols-mode= which can be used for individual styling of custom keywords. -Alternatives are the older =org-superstar= and =org-bullets= packages, which are +Alternatives are the older [[https://github.com/integral-dw/org-superstar-mode][=org-superstar=]] and [[https://github.com/sabof/org-bullets][=org-bullets=]] packages, which are more limited and mainly adjust headlines and lists. =org-superstar= relies on character composition, while =org-modern= uses text properties, which are considered more future-proof. Note that =org-modern= is a full replacement for diff --git a/org-modern-indent.el b/org-modern-indent.el new file mode 100644 index 0000000000..0f70513852 --- /dev/null +++ b/org-modern-indent.el @@ -0,0 +1,374 @@ +;;; org-modern-indent.el --- Style indented blocks -*- lexical-binding: t -*- + +;; Copyright (C) 2022-2025 J.D. Smith + +;; Author: J.D. Smith +;; Created 2022 +;; Keywords: convenience, text + +;; This file is part of GNU Emacs. + +;; This program 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. + +;; This program 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 this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; `org-modern-indent' is an `org-modern' extension which approximates +;; the block highlighting style of `org-modern'. By default, it is +;; activated when `org-indent' is is active in the buffer. It was +;; merged into `org-modern' as of v2.0. + +;;; Code: +(require 'compat) +(require 'org-indent) +(require 'org-element) +(eval-when-compile (require 'cl-lib)) + +;;;; Face and style +(defgroup org-modern-indent nil + "Org-modern style blocks which works with org-indent." + :group 'org + :prefix "org-modern-indent-") + +;; Face for org-modern-indent line +(defface omi/bracket-line + '((t (:inherit (org-meta-line) :weight light))) + "Face for bracket line in org-modern-indent." + :group 'faces) + +(defconst omi/begin (propertize "╭" 'face 'omi/bracket-line)) +(defconst omi/guide (propertize "│" 'face 'omi/bracket-line)) +(defconst omi/end (propertize "╰" 'face 'omi/bracket-line)) + +(defvar omi/begin-re + "\\([ \t]*\\)\\(#\\+\\)\\(?:begin\\|BEGIN\\)_\\S-") + +;;;; Utility +(defsubst omi/-lbp (p &optional n) + "Return the line beginning position N at point P." + (save-excursion (goto-char p) (pos-bol n))) + +;;;; Block prefix cache +(defvar omi/-prefixes (make-hash-table :test #'equal) + "A hash table of cached line prefixes. +The hash index is a combination of the (unstyled) `org-indent' length +and the \"real\" (space) indentation at the block beginning. Each hash +value is a vector of length 3: + + [BEGIN GUIDE END] + +holding the wrap/indent prefix strings for the block begin, end, and +guide (body).") + +(defun omi/-prefix (org-indent extra-indent) + "Cache and return prefix strings based on the indent levels. +There are 2 types of indentation: ORG-INDENT (styled with `org-indent' +face), and EXTRA-INDENT (unstyled). See `org-modern-indent--prefix' for +the contents." + (unless (and (= org-indent 0) (= extra-indent 0)) + (let* ((key (+ org-indent (* 1000 extra-indent))) + (cached (gethash key omi/-prefixes))) + (or cached + (puthash key + (cl-loop for type in '("begin" "guide" "end") + for tstr = (symbol-value + (intern (concat "org-modern-indent-" type))) + with olen = (if (> extra-indent 0) org-indent + (1- org-indent)) + with ostr = (and (> olen 0) + (propertize (make-string olen ?\s) + 'face '(org-indent default))) + with pstr = (and (> extra-indent 0) + (make-string (1- extra-indent) ?\s)) + collect (concat ostr pstr tstr)) + omi/-prefixes))))) + +;;;; Finding and operating on blocks +(defsubst omi/-block-p (el) + "Return non-nil if EL is an org block element." + (when-let ((el) (type (car el))) + (memq type + '(center-block comment-block dynamic-block + example-block export-block quote-block + special-block src-block verse-block)))) + +(defun omi/-block-at-point (&optional pos) + "Return the org block element at POS, if any. +Considers both the element at point, and its parent. Does not consider +affiliated content like title as part of the block." + (let ((pos (or pos (point)))) + (when-let ((element (org-element-at-point pos))) + (when (or (omi/-block-p element) + (omi/-block-p + (setq element (org-element-property :parent element)))) + (unless (< pos (org-element-property :post-affiliated element)) + element))))) + +(defsubst omi/-block-beg-end (node) + "Return a cons of NODE's (BEG . END). +BEG is at the beginning of the #+BEGIN line, and END is at the end of +the #+END line." + (let* ((bbeg (org-element-property :post-affiliated node)) ; on #+begin + (bend (save-excursion + (goto-char (org-element-property :end node)) + (skip-chars-backward "\n\t ") + (point)))) + (cons bbeg bend))) + +(defun omi/-walk-blocks (beg end fun) + "Walk all org blocks intersecting the region from BEG..END. +FUN is called on each block with the beginning and end positions of the +block (at the beginning and end of the lines containing the header and +footer, respectively). Note that the first block's beginning may lie +prior to BEG, and the last block's end my fall past END, if either only +partially overlaps the region." + (org-with-wide-buffer + (goto-char beg) + (let ((node (omi/-block-at-point)) finished) + (while (not finished) + (when node + (cl-destructuring-bind (bbeg . bend) (omi/-block-beg-end node) + (funcall fun bbeg bend) + (goto-char bend) + (when (>= bend end) (setq finished t)))) ; last block + (unless finished + (if (re-search-forward omi/begin-re end t) + (setq node (omi/-block-at-point)) + (setq finished t))))))) + +;;;; Drawing block brackets +(defun omi/-draw-block (beg end beg0 end0 org-indent real-indent) + "Insert brackets for block between BEG and END. +BEG0 and END0 represents the block's full range, corresponding to the +line beginning/end positions of the block's #+BEGIN/END header/footer +lines. The `org-indent' prefix length at block header is ORG-INDENT, +and REAL-INDENT is the amount of \"real\" (hard space) block +indentation. REAL-INDENT may be zero." + (with-silent-modifications + (pcase-let* (((seq beg-prefix guide-prefix end-prefix) + (omi/-prefix org-indent real-indent)) + ((seq beg-display guide-display end-display) + (and (> real-indent 0) (omi/-prefix real-indent 0))) + (beg-bol (omi/-lbp beg)) + (body-start (max (omi/-lbp beg0 2) beg-bol))) + (cl-macrolet ((add-prefixes (pbeg pend line-prefix wrap-prefix) + `(add-text-properties ,pbeg ,pend + `(,@(and (= real-indent 0) `(line-prefix ,,line-prefix)) + wrap-prefix ,,wrap-prefix))) + (add-guides (pbeg pend display-str) + `(add-text-properties ,pbeg ,pend + `( omi/display ,,display-str rear-nonsticky t)))) + (when (> body-start beg) ;; BEGIN + (add-prefixes beg-bol body-start beg-prefix guide-prefix) + (when (> real-indent 0) + (add-guides beg-bol (+ beg-bol real-indent) beg-display))) + (when (> end body-start) ;; GUIDE BODY + (let* ((end-bol (omi/-lbp end)) + (end0-bol (omi/-lbp end0)) + (after-end (omi/-lbp end 2)) + (body-final (if (= end-bol end0-bol) end-bol after-end))) + (add-prefixes body-start body-final guide-prefix guide-prefix) + (when (> real-indent 0) + (goto-char body-start) + (while (< (point) body-final) + (when (>= (current-indentation) real-indent) + (add-guides (point) (+ (point) real-indent) guide-display)) + (forward-line))) + (when (= end-bol end0-bol) ;; END + (if (= real-indent 0) + (add-prefixes end-bol after-end end-prefix end-prefix) + (goto-char end-bol) + (when (>= (current-indentation) real-indent) + (add-guides end-bol (+ end-bol real-indent) end-display)))))))))) + +;;;; org-indent interfacing +(defvar-local omi/-level-change-end nil) +(defun omi/-refresh-maybe-watch (fun beg end &rest r) + "Watch for org-indent heading refreshes and record the new end position. +FUN is the wrapped function `org-indent-refresh-maybe', and BEG, +END, and R are its arguments." + ;; sadly org-indent-refresh-maybe modifies beg/end but does not return + (let ((oiap-orig (symbol-function 'org-indent-add-properties))) + (cl-letf (((symbol-function 'org-indent-add-properties) + (lambda (b e &optional delay) + (setq omi/-level-change-end (and (> e end) e)) + (funcall oiap-orig b e delay)))) + (apply fun beg end r)))) + +(defun omi/-strip-display (beg end) + (with-silent-modifications + (remove-text-properties beg end '(omi/display nil)))) + +(defvar-local omi/-init nil) +(defun omi/-wait-and-refresh (buf) + "Wait for org-indent to finish initializing BUF, then refresh." + (if (or (not (bound-and-true-p org-indent-agentized-buffers)) + (not (memq buf org-indent-agentized-buffers))) + (omi/init buf) + ;; still waiting + (when (buffer-live-p buf) + (with-current-buffer buf + (if omi/-init + (let ((cnt (cl-incf (cadr omi/-init)))) + (if (> cnt 5) + (user-error + "org-modern-indent: Gave up waiting for %s to initialize" + buf) + (timer-activate + (timer-set-time (car omi/-init) + (time-add (current-time) 0.2))))) + (setq omi/-init + (list (run-at-time 0.1 nil #'omi/-wait-and-refresh buf) + 1))))))) + +(defun omi/-refresh () + "Strip custom display property and refresh line prefix in entire buffer." + (with-silent-modifications + (org-with-wide-buffer + (when org-indent-mode + (omi/-strip-display (point-min) (point-max)) + (org-indent-refresh-maybe (point-min) (point-max) nil))))) + +;;;; Before/after change +(defun omi/-intersects-leader-at (target beg end) + "Return non-nil if BEG..END intersects initial non-blank text at TARGET." + (save-excursion + (goto-char target) + (back-to-indentation) + (let ((beg-targ (point)) + (end-targ (progn (skip-chars-forward "^[:blank:]\n") (point)))) + (and (<= beg end-targ) (<= beg-targ end))))) + +(defun omi/-before-change (beg end) + "Check the BEG..END range for modified block header/footer lines. +Adds an `:org-modern-indent-block' text property to the block, with +value `damaged' for damaged block." + (cl-labels + ((detect-block-damage (bl-beg bl-end) + "Detect and mark damaged blocks." + (unless (and (<= beg bl-beg) (>= end bl-end)) ; entire block replaced/deleted + (with-silent-modifications + (if (or (omi/-intersects-leader-at bl-beg beg end) + (omi/-intersects-leader-at bl-end beg end)) + (progn + (put-text-property bl-beg (1+ bl-beg) :omi/indent nil) ; now unknown! + (put-text-property bl-beg (omi/-lbp bl-end 2) :omi/block 'damaged)) + (put-text-property bl-beg (omi/-lbp bl-end 2) :omi/block t)))))) + (omi/-walk-blocks beg end #'detect-block-damage))) + +(defun omi/-pos-in-leader-p (pos) + "Return non-nil if a block's header/footer leader text encompasses POS." + (when-let ((node (omi/-block-at-point pos))) + (org-with-wide-buffer + (cl-destructuring-bind (bbeg . bend) (omi/-block-beg-end node) + (or (omi/-intersects-leader-at bbeg pos pos) + (omi/-intersects-leader-at bend pos pos)))))) + +(defun omi/-after-change (beg end _len) + "Perform after-change operations on changed text from BEG..END. +To be added after `org-indent-refresh-maybe' on +`after-change-functions'." + (with-silent-modifications + (let ((beg-block (get-text-property beg :omi/block)) + (end-block (get-text-property end :omi/block)) + extend) + (when (and beg-block (or (eq beg-block 'damaged) (omi/-pos-in-leader-p beg))) + (setq extend t + beg (or (previous-single-property-change beg :omi/block) beg))) + (when (and end-block (or (eq end-block 'damaged) (omi/-pos-in-leader-p end))) + (setq extend t + end (or (next-single-property-change end :omi/block) end))) + (when extend + (remove-text-properties beg end '(:omi/block nil :omi/indent nil)) + (org-indent-add-properties beg end))) + ;; If we had a level change, extend down to the next heading + (when omi/-level-change-end (setq end (max end omi/-level-change-end))) + (setq beg (omi/-lbp beg) end (omi/-lbp end 2)) + (remove-text-properties beg end '(omi/display nil)) + (omi/-walk-blocks beg end + (lambda (bl-beg bl-end) + (let ((beg0 bl-beg) (end0 bl-end) + (pf (get-text-property bl-beg 'line-prefix)) + oi-pos oi ci full-block) + (save-excursion + (goto-char bl-beg) + (back-to-indentation) + (setq oi-pos (point) + oi (get-text-property oi-pos :omi/indent) + ci (current-indentation))) + (unless (eq oi ci) + (put-text-property oi-pos (1+ oi-pos) :omi/indent ci)) + (when (and oi (= oi 0) (/= oi ci)) ; was flush, is now indented: + (org-indent-add-properties bl-beg bl-end)) ; repair block's prefixes + (when (< bl-beg beg) ; 1st block straddles BEG + (if (eq oi ci) (setq bl-beg beg) (setq full-block t))) + (when (> bl-end end) ; last block straddles END + (if (eq oi ci) (setq bl-end end) (setq full-block t))) + (when full-block + (with-silent-modifications + (remove-text-properties bl-beg bl-end '(omi/display nil)))) + (omi/-draw-block bl-beg bl-end beg0 end0 (length pf) ci)))))) + +;;;; Mode/setup +(defun omi/init (&optional buf) + "Register buffer BUF and refresh. +To be added to `org-indent-post-buffer-init-functions'." + (interactive) + (let ((buf (or buf (current-buffer)))) + (when (buffer-live-p buf) ; org-capture buffers vanish fast + (with-current-buffer buf + (add-hook 'before-change-functions #'omi/-before-change nil t) + (or (memq #'omi/-after-change after-change-functions) + (cl-loop for func on after-change-functions + if (eq (car func) 'org-indent-refresh-maybe) do + (setcdr func (cons #'omi/-after-change (cdr func))) and return t) + (add-hook 'after-change-functions #'omi/-after-change 98 t)) + (org-with-wide-buffer (omi/-after-change (point-min) (point-max) nil)) + (setq omi/-init t))))) + +;;;###autoload +(define-minor-mode omi/mode + "Org-modern-like block brackets within org-indent." + :global nil + :group 'org-modern-indent + (if omi/mode + (progn + (advice-add 'org-indent-refresh-maybe :around + #'omi/-refresh-maybe-watch) + (cond + ;; already registered before, just toggle + ((or (called-interactively-p 'any) omi/-init) (omi/init)) + ;; Register with buffer init + ((boundp 'org-indent-post-buffer-init-functions) + (add-hook 'org-indent-post-buffer-init-functions #'omi/init nil t)) + ;; No hook available, use the less reliable method + (t (omi/-wait-and-refresh (current-buffer)))) + (cl-pushnew 'omi/display + (alist-get 'display char-property-alias-alist))) + ;; Disabling + (advice-remove 'org-indent-refresh-maybe #'omi/-refresh-maybe-watch) + (remove-hook 'before-change-functions #'omi/-before-change t) + (remove-hook 'after-change-functions #'omi/-after-change t) + (if (boundp 'org-indent-post-buffer-init-functions) + (remove-hook 'org-indent-post-buffer-init-functions #'omi/init t) + (cancel-timer (car omi/-init)) + (setq omi/-init nil)) + (omi/-refresh))) + +(provide 'org-modern-indent) +;;; org-modern-indent.el ends here +;; Local Variables: +;; read-symbol-shorthands: (("omi/" . "org-modern-indent-") (":omi/" . ":org-modern-indent-")) +;; package-lint--sane-prefixes: "^omi/" +;; End: + diff --git a/org-modern.el b/org-modern.el index 22b3cba928..152e96f3ac 100644 --- a/org-modern.el +++ b/org-modern.el @@ -225,6 +225,11 @@ which specifies the offset of the block border from the edge of the window." :type '(choice boolean natnum)) +(defcustom org-modern-indent-block t + "Whether to style indented blocks when using `org-indent'. +See `org-modern-indent-mode'." + :type 'boolean) + (defcustom org-modern-keyword t "Prettify keywords like #+title. If set to t, the prefix #+ will be hidden. If set to a string, @@ -377,6 +382,9 @@ the font.") (defconst org-modern--table-overline '(:overline t)) (defconst org-modern--table-sp '((space :width (org-modern--table-sp-width)) (space :width (org-modern--table-sp-width)))) +(defvar org-indent-mode) +(defvar org-modern-indent-mode) +(declare-function org-modern-indent-mode "org-modern-indent") (defun org-modern--checkbox () "Prettify checkboxes according to `org-modern-checkbox'." @@ -796,7 +804,7 @@ whole buffer; otherwise, for the line at point." (2 '(face org-modern-label display #(" " 0 1 (face (:strike-through t)))) t)))) ;; Do not add source block fringe markers if org-indent-mode is ;; enabled. org-indent-mode uses line prefixes for indentation. - ;; Therefore we cannot have both. + ;; org-modern-indent handles this. (when (and org-modern-block-fringe (not (bound-and-true-p org-indent-mode))) '(("^[ \t]*#\\+\\(?:begin\\|BEGIN\\)_\\S-" (0 (org-modern--block-fringe))))) @@ -862,7 +870,9 @@ whole buffer; otherwise, for the line at point." (when (eq org-modern-star 'fold) (add-hook 'org-cycle-hook #'org-modern--cycle nil 'local)) (org-modern--update-faces) - (org-modern--update-bitmaps)) + (org-modern--update-bitmaps) + (when (and org-indent-mode org-modern-indent-block) + (org-modern-indent-mode 1))) (t (remove-from-invisibility-spec 'org-modern) (font-lock-remove-keywords nil org-modern--font-lock-keywords) @@ -872,7 +882,8 @@ whole buffer; otherwise, for the line at point." (remove-hook 'org-after-promote-entry-hook #'org-modern--unfontify-line 'local) (remove-hook 'org-after-demote-entry-hook #'org-modern--unfontify-line 'local) (when (eq org-modern-star 'fold) - (remove-hook 'org-cycle-hook #'org-modern--cycle 'local)))) + (remove-hook 'org-cycle-hook #'org-modern--cycle 'local)) + (when org-modern-indent-mode (org-modern-indent-mode 0)))) (without-restriction (with-silent-modifications (org-modern--unfontify (point-min) (point-max)))