Re: c*-mode-agnostic basic-offset value
JD Smith <[email protected]> Thu, 4 Jul 2024 13:14:58 -0400
| Newsgroups | gmane.emacs.cc-mode.general |
|---|---|
| Message-ID | <[email protected]> |
--===============6027475216738180127== Content-Type: multipart/alternative; boundary="Apple-Mail=_8D1B272E-2958-49A5-AF96-FD9831F9042C" --Apple-Mail=_8D1B272E-2958-49A5-AF96-FD9831F9042C Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On Jul 4, 2024, at 7:17=E2=80=AFAM, Alan Mackenzie <[email protected]> wrote: >=20 > Hello, JD. >=20 > Thanks for your post! >=20 > On Tue, Jul 02, 2024 at 11:32:45 -0400, JD Smith wrote: >> I am the author of indent-bars[1], a mode providing indentation = bars >> across modes. For its operation, indent-bars requires knowledge of = the >> indentation offset, and uses a heuristic to discover that = information. >=20 >=20 >> For c-modes it currently does a simple (in a large cond): >=20 >> ((and (local-variable-p 'c-basic-offset) (numberp c-basic-offset)) >> c-basic-offset) >=20 >> But that fails to gather the needed information for various >> auto-configuration examples like 'set-from-style. Can anyone >> recommend a simple configuration that will work reliably across all = the >> various c*-modes and their various style options? Indent-bars just >> needs to know the indent multiple (2 chars, 4 chars, 8 chars???). = This >> code runs in a hook like prog-mode-hook (or equivalent = mode-specific >> hooks) so initialization should already be done. >=20 > I'm a little puzzled as to what's going on. In a fully initialised CC > Mode buffer, c-basic-offset should be a number, such as 2, 4, or 8. = Are > you evaluating that large cond before C Mode is fully initialised, > somehow? I think (though I'm not quite sure) that c-basic-offset = should > be set up before the mode hooks (including prog-mode-hook) get run. Thanks for getting back to me. Since writing, the user who opened the = issue has let me know they are using c-ts-mode. I'm not sure of the = relationship among all the various c*-modes, and whether that factors = in. Maybe it's as simple as those modes being distinct and requiring = distinct offset variables? It would of course be nice if all emacs = modes used a unified local variable name (indent-offset?) to indicate = the offset they have configured.=20 > Is there some way I can access indent-bars without having to allow > github's Javascript access to my machine? Sure, I've attached the two relevant files here (main branch, with the = addition of the user's proposed fix of checking = `c-ts-common-indent-offset'). I intend to submit this to ELPA soon so = it should then be accessible there.=20 > It would be useful for me to be able to try to reproduce the bug. Is > there anything else I need to know for this beyond what you've already > said (i.e. call indent-bars from a major mode hook)? If you eval indent-bars.el and M-x indent-bars it should work (assuming = your Emacs supports stipples, sadly not all do, though the situation is = improving). Note that TS support is not on by default; if you want = that you must also configure indent-bars-treesit-scope (though I've not = tested that with C modes). =20 Thanks again, JD =EF=BF=BC=EF=BF=BC= --Apple-Mail=_8D1B272E-2958-49A5-AF96-FD9831F9042C Content-Type: multipart/mixed; boundary="Apple-Mail=_C888637E-22A8-40AE-9AB0-5A5337C16EA2" --Apple-Mail=_C888637E-22A8-40AE-9AB0-5A5337C16EA2 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8 <html><head><meta http-equiv=3D"content-type" content=3D"text/html; = charset=3Dutf-8"></head><body style=3D"overflow-wrap: break-word; = -webkit-nbsp-mode: space; line-break: = after-white-space;"><div><br><blockquote type=3D"cite"><div>On Jul 4, = 2024, at 7:17=E2=80=AFAM, Alan Mackenzie <[email protected]> = wrote:</div><br class=3D"Apple-interchange-newline"><div><meta = charset=3D"UTF-8"><span style=3D"caret-color: rgb(0, 0, 0); font-family: = Helvetica; font-size: 12px; font-style: normal; font-variant-caps: = normal; font-weight: 400; letter-spacing: normal; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; = word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: = none; float: none; display: inline !important;">Hello, JD.</span><br = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none;"><br = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none;"><span = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none; float: none; = display: inline !important;">Thanks for your post!</span><br = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none;"><br = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none;"><span = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none; float: none; = display: inline !important;">On Tue, Jul 02, 2024 at 11:32:45 -0400, JD = Smith wrote:</span><br style=3D"caret-color: rgb(0, 0, 0); font-family: = Helvetica; font-size: 12px; font-style: normal; font-variant-caps: = normal; font-weight: 400; letter-spacing: normal; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; = word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: = none;"><blockquote type=3D"cite" style=3D"font-family: Helvetica; = font-size: 12px; font-style: normal; font-variant-caps: normal; = font-weight: 400; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"> I am the author of indent-bars[1], a = mode providing indentation bars<br> across modes. For = its operation, indent-bars requires knowledge of = the<br> indentation offset, and uses a heuristic to discover = that information.<br></blockquote><br style=3D"caret-color: rgb(0, 0, = 0); font-family: Helvetica; font-size: 12px; font-style: normal; = font-variant-caps: normal; font-weight: 400; letter-spacing: normal; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"><br style=3D"caret-color: rgb(0, 0, 0); = font-family: Helvetica; font-size: 12px; font-style: normal; = font-variant-caps: normal; font-weight: 400; letter-spacing: normal; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"><blockquote type=3D"cite" style=3D"font-family: = Helvetica; font-size: 12px; font-style: normal; font-variant-caps: = normal; font-weight: 400; letter-spacing: normal; orphans: auto; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"> For c-modes it currently does a = simple (in a large cond):<br></blockquote><br style=3D"caret-color: = rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: = normal; font-variant-caps: normal; font-weight: 400; letter-spacing: = normal; text-align: start; text-indent: 0px; text-transform: none; = white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"><blockquote type=3D"cite" style=3D"font-family: = Helvetica; font-size: 12px; font-style: normal; font-variant-caps: = normal; font-weight: 400; letter-spacing: normal; orphans: auto; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"> ((and (local-variable-p = 'c-basic-offset) (numberp = c-basic-offset))<br> c-basic-offset)<br= ></blockquote><br style=3D"caret-color: rgb(0, 0, 0); font-family: = Helvetica; font-size: 12px; font-style: normal; font-variant-caps: = normal; font-weight: 400; letter-spacing: normal; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; = word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: = none;"><blockquote type=3D"cite" style=3D"font-family: Helvetica; = font-size: 12px; font-style: normal; font-variant-caps: normal; = font-weight: 400; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"> But that fails to gather the needed = information for various<br> auto-configuration examples like = 'set-from-style. Can anyone<br> recommend a = simple configuration that will work reliably across all = the<br> various c*-modes and their various style options? = Indent-bars just<br> needs to know the indent multiple = (2 chars, 4 chars, 8 chars???). This<br> code runs in a = hook like prog-mode-hook (or equivalent = mode-specific<br> hooks) so initialization should already be = done.<br></blockquote><br style=3D"caret-color: rgb(0, 0, 0); = font-family: Helvetica; font-size: 12px; font-style: normal; = font-variant-caps: normal; font-weight: 400; letter-spacing: normal; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"><span style=3D"caret-color: rgb(0, 0, 0); = font-family: Helvetica; font-size: 12px; font-style: normal; = font-variant-caps: normal; font-weight: 400; letter-spacing: normal; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none; float: none; display: inline !important;">I'm a = little puzzled as to what's going on. In a fully initialised = CC</span><br style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; = font-size: 12px; font-style: normal; font-variant-caps: normal; = font-weight: 400; letter-spacing: normal; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; = word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: = none;"><span style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; = font-size: 12px; font-style: normal; font-variant-caps: normal; = font-weight: 400; letter-spacing: normal; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; = word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: = none; float: none; display: inline !important;">Mode buffer, = c-basic-offset should be a number, such as 2, 4, or 8. = Are</span><br style=3D"caret-color: rgb(0, 0, 0); font-family: = Helvetica; font-size: 12px; font-style: normal; font-variant-caps: = normal; font-weight: 400; letter-spacing: normal; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; = word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: = none;"><span style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; = font-size: 12px; font-style: normal; font-variant-caps: normal; = font-weight: 400; letter-spacing: normal; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; = word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: = none; float: none; display: inline !important;">you evaluating that = large cond before C Mode is fully initialised,</span><br = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none;"><span = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none; float: none; = display: inline !important;">somehow? I think (though I'm not = quite sure) that c-basic-offset should</span><br style=3D"caret-color: = rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: = normal; font-variant-caps: normal; font-weight: 400; letter-spacing: = normal; text-align: start; text-indent: 0px; text-transform: none; = white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"><span style=3D"caret-color: rgb(0, 0, 0); = font-family: Helvetica; font-size: 12px; font-style: normal; = font-variant-caps: normal; font-weight: 400; letter-spacing: normal; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none; float: none; display: inline !important;">be set = up before the mode hooks (including prog-mode-hook) get run.</span><br = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: = none;"></div></blockquote><div><br></div><div><font = color=3D"#000000">Thanks for getting back to me. Since writing, = the user who opened the issue has let me know they are using c-ts-mode. = I'm not sure of the relationship among all the various c*-modes, = and whether that factors in. Maybe it's as simple as those modes = being distinct and requiring distinct offset variables? It would = of course be nice if all emacs modes used a unified local variable = name (indent-offset?) to indicate the offset they have = configured. </font></div><br><blockquote type=3D"cite"><div><span = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none; float: none; = display: inline !important;">Is there some way I can access indent-bars = without having to allow</span><br style=3D"caret-color: rgb(0, 0, 0); = font-family: Helvetica; font-size: 12px; font-style: normal; = font-variant-caps: normal; font-weight: 400; letter-spacing: normal; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"><span style=3D"caret-color: rgb(0, 0, 0); = font-family: Helvetica; font-size: 12px; font-style: normal; = font-variant-caps: normal; font-weight: 400; letter-spacing: normal; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none; float: none; display: inline = !important;">github's Javascript access to my machine?</span><br = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: = none;"></div></blockquote><div><br></div>Sure, I've attached the two = relevant files here (main branch, with the addition of the user's = proposed fix of checking `c-ts-common-indent-offset'). I intend to = submit this to ELPA soon so it should then be accessible = there. <br><div><br></div><blockquote type=3D"cite"><div><span = style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: = 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; = letter-spacing: normal; text-align: start; text-indent: 0px; = text-transform: none; white-space: normal; word-spacing: 0px; = -webkit-text-stroke-width: 0px; text-decoration: none; float: none; = display: inline !important;">It would be useful for me to be able to try = to reproduce the bug. Is</span><br style=3D"caret-color: rgb(0, 0, = 0); font-family: Helvetica; font-size: 12px; font-style: normal; = font-variant-caps: normal; font-weight: 400; letter-spacing: normal; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"><span style=3D"caret-color: rgb(0, 0, 0); = font-family: Helvetica; font-size: 12px; font-style: normal; = font-variant-caps: normal; font-weight: 400; letter-spacing: normal; = text-align: start; text-indent: 0px; text-transform: none; white-space: = normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none; float: none; display: inline !important;">there = anything else I need to know for this beyond what you've = already</span><br style=3D"caret-color: rgb(0, 0, 0); font-family: = Helvetica; font-size: 12px; font-style: normal; font-variant-caps: = normal; font-weight: 400; letter-spacing: normal; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; = word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: = none;"><span style=3D"caret-color: rgb(0, 0, 0); font-family: Helvetica; = font-size: 12px; font-style: normal; font-variant-caps: normal; = font-weight: 400; letter-spacing: normal; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; = word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: = none; float: none; display: inline !important;">said (i.e. call = indent-bars from a major mode hook)?</span><br style=3D"caret-color: = rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: = normal; font-variant-caps: normal; font-weight: 400; letter-spacing: = normal; text-align: start; text-indent: 0px; text-transform: none; = white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = text-decoration: none;"></div></blockquote><div><br></div><div>If you = eval indent-bars.el and M-x indent-bars it should work (assuming your = Emacs supports stipples, sadly not all do, though the situation is = improving). Note that TS support is not on by default; if you = want that you must also configure indent-bars-treesit-scope (though = I've not tested that with C modes). = </div><div><br></div><div>Thanks = again,</div><div>JD</div><br></div></body></html>= --Apple-Mail=_C888637E-22A8-40AE-9AB0-5A5337C16EA2 Content-Disposition: attachment; filename=indent-bars-ts.el Content-Type: application/octet-stream; x-unix-mode=0644; name="indent-bars-ts.el" Content-Transfer-Encoding: 7bit ;;; indent-bars-ts.el --- treesitter support for indent-bars -*- lexical-binding: t; -*- ;; Copyright (C) 2023-2024 J.D. Smith ;;; Commentary: ;; tree-sitter support for indent-bars: ;; - Optionally uses tree-sitter to fine-tune indentation depth ;; (avoiding "too many bars" in e.g. argument lists) ;; - Uses treesitter to avoid adding bars to blank lines in strings ;; or other configurable node types. ;; - Enable alternate styling for bars inside or outside the ;; treesitter "scope", where scope is defined as the wrapping ;; elements configured in `indent-bars-treesitscope`. ;; For Developers: ;; ;; This file interfaces treesitter scope queries with font-lock-based ;; bar drawing. Some of this happens during normal font-lock, ;; querying treesitter for node information at point (typically at the ;; beginning of the line). The scope highlight capability depends on ;; the position of the point, and so requires some subtle interface ;; between movement, tree-sitter, and font-lock. At any given point ;; there is a scope range (a pair of markers) which determines how the ;; bars get displayed. Small movements can change the scope ;; signficantly. ;; ;; The technique is as follows: ;; ;; - A post-command hook sets up an idle-time callback if none exists. ;; - In idle time, check for the innermost "scope" node at point. ;; - If the node boundaries have changed from the last time they were ;; saved (modulo insertion deletion changes markers can track), ;; invalidate font-lock over the node's boundaries. ;; - Short nodes occupying too-few lines are not considered. A nil ;; scope node indicates the entire file is the scope. ;; - Font-lock automatically re-applies indentation bars, consulting ;; the saved node range to determine whether a given line is ;; in-scope or out-of-scope. ;; ;; ;; Note the shorthand substitutions for style related prefixes (slot ;; accessors and variables); see file-local-variables at the end: ;; ;; ibts/ => indent-bars-ts-scope- (slot accessors) ;; ibtcs => indent-bars-ts-current-scope (scope struct) ;;; Code: ;;;; Requires (require 'cl-lib) (require 'seq) (require 'indent-bars) (require 'treesit nil t) ;;;; Customization (defgroup indent-bars-ts nil "Customization group for indent-bars treesitter options." :group 'indent-bars :prefix "indent-bars-ts-") (defgroup indent-bars-ts-style nil "Customization group for indent-bars treesitter alternate styling." :group 'indent-bars :prefix "indent-bars-ts-") ;;;;; Alternate Style Variables (defcustom indent-bars-ts-styling-scope 'out-of-scope "Which scope the *-ts-* style variables apply to: in or out. By default, the *-ts-* custom variables apply to the out-of-scope style, and in-scope bars make use of the default (non-ts) styling. If instead this is set to `in-scope', the out-of-scope bars share the default style, and in-scope bars are configured with alternate styling using the *-ts-* variables." :type '(choice (const :tag "Out of scope" out-of-scope) (const :tag "In scope" in-scope))) (defun indent-bars-ts--add-customs () "Add all the relevant custom variables for the alternate ts style." (cl-labels ((ts-cust (var &rest r) (eval `(indent-bars--alt-custom "ts" ,var ,(format "Tree-sitter (%s)" indent-bars-ts-styling-scope) ,@r)))) (ts-cust 'color '(unspecified :blend 0.1) 'add-inherit) (dolist (c '( width-frac pad-frac pattern zigzag ;simple types no-stipple-char-font-weight)) (ts-cust c 'unspecified)) (dolist (c '(color-by-depth highlight-current-depth)) (ts-cust c 'unspecified 'add-inherit)))) ;;;;; Treesit Customs (defcustom indent-bars-treesit-wrap nil "An alist of language and treesitter node type symbols to wrap. Inside such wrapping types, indentation bar depth will not be increased more than one beyond that of the containing node's depth. This is typically done for lists, parameters, function arguments, etc., to avoid unwanted \"extra bars\". Types must be valid node types for the grammar of the language indicated. Note that the (non-treesitter) options `indent-bars-no-descend-string' and `indent-bars-no-descend-lists', if set, take precedence over this option." :type '(choice (const :tag "No wrap types" nil) (alist :tag "Alist of node types" :key-type (symbol :tag "Language") :value-type (repeat :tag "Types" (symbol :tag "Type")))) :group 'indent-bars-ts) (defcustom indent-bars-treesit-scope nil "An alist of language and treesitter node types to emphasize. If non-nil, indentation bars on text outside (or inside, if `indent-bars-ts-styling-scope' is changed from its default) of the innermost matching treesitter scope will use the alternative style specified in the indent-bars-ts-os-* custom variables, which mirror and inherit from the normal style variables." :type '(choice (const :tag "No scope types" nil) (alist :tag "Alist of node types" :key-type (symbol :tag "Language") :value-type (repeat :tag "Types" (symbol :tag "Type")))) :group 'indent-bars-ts) (defcustom indent-bars-treesit-scope-min-lines 3 "Minimum number of lines a node must span to be counted as a scope." :type 'integer :group 'indent-bars-ts) (defcustom indent-bars-treesit-ignore-blank-lines-types nil "Do not style blank lines when the type of node at start is in this list. Either nil, or a list of node type strings to avoid adding blank line styling to. Typically \"top-level\" node types like \"module\", \"program\", and \"translation_unit\" would be used here, and they need not be valid types for any particular grammar. Only applicable if `indent-bars-display-on-blank-lines' is set." :type '(choice (const :tag "None" nil) (repeat :tag "Node types" string)) :group 'indent-bars-ts) (defcustom indent-bars-treesit-update-delay 0.125 "Idle time in seconds for treesitter scope updates to occur. This has effect only if `indent-bars-treesit-scope' is non-nil." :type 'float :group 'indent-bars-ts) ;;;; Node Utilities (defvar-local indent-bars-ts--parser nil) (defvar-local indent-bars-ts--wrap-query nil) (defvar-local indent-bars-ts--string-query nil) (defsubst indent-bars-ts--node-spans-p (node start end) "Return NODE if it fully spans START..END. Otherwise return nil." (and (<= (treesit-node-start node) start) (>= (treesit-node-end node) end) node)) (defun indent-bars-ts--node-query (node query &optional start-only spanning min-newlines) "Capture node(s) matching QUERY which overlap with NODE. QUERY is a compiled treesit query. If START-ONLY is non-nil, the query searches for matching nodes which overlap with NODE's starting position. Otherwise nodes which intersect anywhere with NODE will be returned. If SPANNING is non-nil, return a single spanning node which fully spans the start..end range of NODE, if any (or just the start, if START-ONLY is non-nil). If SPANNING is \\='innermost, return the latest (innermost) node on the list which fully spans NODE, which could include NODE itself if it matches the QUERY. For any other non-nil value of SPANNING, check if the first node matched by QUERY spans NODE and return it if so. If MIN-NEWLINES is a number, a spanning node will be returned only if spans at least that many newlines. E.g. MIN-NEWLINES=1 demands a two line node (or larger). If no spanning node is found, nil is returned." (when-let ((start (treesit-node-start node)) (end (if start-only start (treesit-node-end node))) (nodes (treesit-query-capture indent-bars-ts--parser query start end t))) (cond ((eq spanning 'innermost) (cl-loop for n in (nreverse nodes) if (and (or (eq n node) (indent-bars-ts--node-spans-p n start end)) (or (not min-newlines) (>= (count-lines (treesit-node-start n) (treesit-node-end n)) min-newlines))) return n)) (spanning ; check first node, if it doesn't span, none will (when-let ((n (indent-bars-ts--node-spans-p (car nodes) start end)) ((or (not min-newlines) (>= (count-lines (treesit-node-start n) (treesit-node-end n)) min-newlines)))) n)) (t nodes)))) (defsubst indent-bars--indent-at-node (node) "Return the current indentation at the start of TS node NODE." (save-excursion (goto-char (treesit-node-start node)) (current-indentation))) ;;;; Limiting Indentation depth: string and context-dependent (defun indent-bars-ts--update-indentation-depth (d) "Update target depth D using the tree-sitter region. Searches for parent nodes with types specified in `indent-bars-treesit-wrap' for the current buffer's language, and, if found, limits the indentation depth to one more than the topmost matching parent node's first line indentation depth. If `indent-bars-no-descend-string' is non-nil, also looks for enclosing string and marks indent depth no deeper than one more than the indentation depth at string start. This reduces depth inside strings, and for wrapping contexts (e.g. function arguments)." (if-let (((not (bobp))) (node (treesit-node-on (1- (point)) (point) indent-bars-ts--parser)) (dnew (if (and indent-bars-ts--string-query (indent-bars-ts--node-query node indent-bars-ts--string-query t)) ;; A string: do not descend (1+ (indent-bars--depth (indent-bars--indent-at-node node))) ;; Check wrap context (when-let (( indent-bars-ts--wrap-query) (ctx (indent-bars-ts--node-query node indent-bars-ts--wrap-query nil t))) (1+ (indent-bars--depth (indent-bars--indent-at-node ctx))))))) (min dnew d) d)) ;;;; Ignoring Certain Blank Lines ;; see also ts--handle-blank-lines, below (defun indent-bars-ts--ignore-blank (beg) "See if blank lines at BEG should be ignored using tree-sitter. Blank lines to ignore are those within nodes of the types mentioned in `indent-bars-treesit-ignore-blank-lines-types'." (and indent-bars-ts--parser indent-bars-treesit-ignore-blank-lines-types (when-let ((n (treesit-node-on beg beg))) (seq-contains-p indent-bars-treesit-ignore-blank-lines-types (treesit-node-type n))))) ;;;; Scope Highlighting (defvar indent-bars-ts-alt-style nil) (defvar indent-bars-ts-in-out-style nil "A cons of (IN-STYLE . OUT-OF-STYLE).") (cl-declaim (optimize (safety 0))) ; no need for type check (cl-defstruct (indent-bars-ts-scope (:copier nil) (:conc-name ibts/) (:constructor ibts/create)) "A structure for tracking treesitter-based scope information." ( range (cons (point-min-marker) (point-min-marker)) :type cons :documentation "The current scope node's range.") ( clip-win (cons (point-max-marker) (point-max-marker)) :type cons :documentation "The clipping window for the current scope.") ( start-bars 0 :type integer :documentation "The number of bars shown at start of current scope.") ( invalid-ranges nil :type list :documentation "List of current invalid ranges -- (start . end) conses.") ( query nil :type ts-query :documentation "The treesitter scope query object.")) (defvar-local ibtcs nil ; N.B. see shorthands at bottom of file "The current `indent-bars-ts-scope' struct.") (defvar-local indent-bars-ts--scope-timer nil) (defun indent-bars-ts--out-of-scope (pos) "Return t if POS is outside the current treesitter scope. If there is no scope defined, every position is considered in scope. When the timer is running, only consider the most recently clipped node ranges in scope." (when ibtcs (or (< pos (car (ibts/range ibtcs))) (> pos (cdr (ibts/range ibtcs)))))) (defun indent-bars-ts--display () "Display indentation bars, accounting for current treesitter scope." (if (indent-bars-ts--out-of-scope (match-beginning 1)) (indent-bars--display (match-beginning 1) (match-end 1) (cdr indent-bars-ts-in-out-style)) ;; In scope: switch from out to in-scope style (indent-bars--display (match-beginning 1) (match-end 1) (cdr indent-bars-ts-in-out-style) (ibts/start-bars ibtcs) (car indent-bars-ts-in-out-style)))) (defun indent-bars-ts--handle-blank-lines () "Display bars on blank lines, respecting treesitter scope." (let ((beg (match-beginning 0))) (unless (indent-bars-ts--ignore-blank beg) (if (indent-bars-ts--out-of-scope beg) ;fully out of scope (indent-bars--handle-blank-lines (match-beginning 0) (match-end 0) (cdr indent-bars-ts-in-out-style)) ;; Switch from out of scope to in scope after start-bars (indent-bars--handle-blank-lines (match-beginning 0) (match-end 0) (cdr indent-bars-ts-in-out-style) (ibts/start-bars ibtcs) (car indent-bars-ts-in-out-style)))))) (defmacro indent-bars-ts--order-ranges (a b) "Order ranges A and B by start position." `(if (< (car ,b) (car ,a)) (setq ,b (prog1 ,a (setq ,a ,b))))) (defun indent-bars-ts--union (a b) "Return the union between ranges A and B. Ranges A and B are (start . end) conses. Their union is a list of ranges that either cover." (indent-bars-ts--order-ranges a b) (if (< (cdr a) (car b)) (list a b) ; no overlap, use both (list (cons (car a) (max (cdr a) (cdr b)))))) (defun indent-bars-ts--update-scope1 (buf) "Perform the treesitter scope font-lock update in buffer BUF. If the buffer is modified or the point has moved, re-query the scope bounds at point. If the current scope range, clipped to the window's bounds, falls outside the prior scope (beyond simple marker movement), refontify the union of all old invalid ranges and the new window ranges clipped to the window(s) showing BUF. Note that the updated node range clips to an \"extended window\" with 50% padding on either side." (with-current-buffer buf (setq indent-bars-ts--scope-timer nil) (let* ((pmn (point-min)) (pmx (point-max)) (old (ibts/range ibtcs)) (node (treesit-node-on (max pmn (1- (point))) (point) indent-bars-ts--parser)) (scope (and node (indent-bars-ts--node-query node (ibts/query ibtcs) nil 'innermost indent-bars-treesit-scope-min-lines))) (new (if scope ; no scope = full file (cons (treesit-node-start scope) (treesit-node-end scope)) (cons pmn pmx)))) (unless (and (= (car new) (car old)) ; if node is unchanged (spans (= (cdr new) (cdr old))) ; same range) no update needed (setf (ibts/start-bars ibtcs) (save-excursion (goto-char (car new)) (indent-bars--current-indentation-depth))) (dolist (inv (indent-bars-ts--union old new)) (font-lock-flush (car inv) (cdr inv))) (set-marker (car old) (car new)) ;updates ibts/range (set-marker (cdr old) (cdr new)))))) (defun indent-bars-ts--update-scope () "Update treesit scope when possible." (unless indent-bars-ts--scope-timer (setq indent-bars-ts--scope-timer (run-with-idle-timer indent-bars-treesit-update-delay nil #'indent-bars-ts--update-scope1 (current-buffer))))) ;;;; Setup (defun indent-bars-ts--init-scope (&optional force) "Initialize scope style and variables. If FORCE is non-nil, initialize even if this has already been performed." (unless (or force (get 'indent-bars-ts-setup :init-scope)) (indent-bars-ts--add-customs) (put 'indent-bars-ts-setup :init-scope t)) (indent-bars--initialize-style (setq indent-bars-ts-alt-style (indent-bars--new-style "ts"))) (setq indent-bars-ts-in-out-style (if (eq indent-bars-ts-styling-scope 'out-of-scope) (cons indent-bars-style indent-bars-ts-alt-style) (cons indent-bars-ts-alt-style indent-bars-style)))) (defun indent-bars-ts--setup (lang) "Setup indent-bars treesitter support in this buffer for language LANG." (setq indent-bars-ts--parser (cl-find lang (treesit-parser-list) :key #'treesit-parser-language)) ;; Wrap: prevent additional bars inside wrapped entities (when-let ((types (alist-get lang indent-bars-treesit-wrap))) (setq indent-bars-ts--wrap-query (treesit-query-compile lang `([,@(mapcar #'list types)] @ctx)) indent-bars--update-depth-function #'indent-bars-ts--update-indentation-depth)) ;; Strings (avoid descending deeper inside strings using TS) (when (stringp indent-bars-no-descend-string) (let ((query `([(,indent-bars-no-descend-string)] @s)) (pm (point-min))) (setq indent-bars-ts--string-query (treesit-query-compile lang query)) ;; Test it to be sure it works (condition-case err (treesit-query-capture indent-bars-ts--parser indent-bars-ts--string-query pm pm t) (treesit-query-error (setq indent-bars-no-descend-string nil) (message "%s. See `indent-bars-no-descend-string'.\n%s" "indent-bars: malformed treesitter string query; disabling" err)) (:success (setq indent-bars--update-depth-function #'indent-bars-ts--update-indentation-depth))))) ;; Emphasis Scope: use alternate styling outside(/inside) current scope (when-let ((types (alist-get lang indent-bars-treesit-scope))) (indent-bars-ts--init-scope) (setq ibtcs (ibts/create)) (setq-local indent-bars--display-form '(indent-bars-ts--display) indent-bars--handle-blank-lines-form '(indent-bars-ts--handle-blank-lines)) (setf (ibts/query ibtcs) (treesit-query-compile lang `([,@(mapcar #'list types)] @ctx))) (add-hook 'post-command-hook #'indent-bars-ts--update-scope nil t) (add-hook 'indent-bars--teardown-functions 'indent-bars-ts--teardown))) (defun indent-bars-ts--teardown () "Teardown indent-bars-ts." (when indent-bars-ts--scope-timer (cancel-timer indent-bars-ts--scope-timer) (setq indent-bars-ts--scope-timer nil)) (kill-local-variable 'indent-bars--display-form) (kill-local-variable 'indent-bars--handle-blank-lines-form) (remove-hook 'post-command-hook #'indent-bars-ts--update-scope t) (remove-hook 'indent-bars--teardown-functions 'indent-bars-ts--teardown)) ;;;###autoload (define-minor-mode indent-bars-ts-mode "Minor mode for indent-bars using treesitter." :group 'indent-bars-ts (if indent-bars-ts-mode (if-let (((fboundp #'treesit-available-p)) ((treesit-available-p)) (lang (treesit-language-at (point-min)))) (indent-bars-ts--setup lang) (setq indent-bars-ts-mode nil)) (indent-bars-ts--teardown))) (defun indent-bars-ts--custom-update-scope () "Update the TS scope for custom setting." (when indent-bars-ts-mode (indent-bars-ts--update-scope1 (current-buffer)))) (add-hook 'indent-bars-custom-set #'indent-bars-ts--custom-update-scope) (provide 'indent-bars-ts) ;;; indent-bars-ts.el ends here ;; Local Variables: ;; read-symbol-shorthands: (("ibts/" . "indent-bars-ts-scope-") ("ibtcs" . "indent-bars-ts-current-scope")) ;; End: --Apple-Mail=_C888637E-22A8-40AE-9AB0-5A5337C16EA2 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii <html><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><head><meta http-equiv="content-type" content="text/html; charset=us-ascii"></head></body></html> --Apple-Mail=_C888637E-22A8-40AE-9AB0-5A5337C16EA2 Content-Disposition: attachment; filename=indent-bars.el Content-Type: application/octet-stream; x-unix-mode=0644; name="indent-bars.el" Content-Transfer-Encoding: quoted-printable ;;;=20indent-bars.el=20---=20Highlight=20indentation=20with=20bars=20-*-=20= lexical-binding:=20t;=20-*-=0A;;=20Copyright=20(C)=202023-2024=20=20J.D.=20= Smith=0A=0A;;=20Author:=20J.D.=20Smith=0A;;=20Homepage:=20= https://github.com/jdtsmith/indent-bars=0A;;=20Package-Requires:=20= ((emacs=20"27.1")=20(compat=20"29.1.4.5"))=0A;;=20Version:=200.6.1=0A;;=20= Keywords:=20convenience=0A;;=20Prefix:=20indent-bars=0A;;=20Separator:=20= -=0A=0A;;=20indent-bars=20is=20free=20software:=20you=20can=20= redistribute=20it=20and/or=0A;;=20modify=20it=20under=20the=20terms=20of=20= the=20GNU=20General=20Public=20License=20as=0A;;=20published=20by=20the=20= Free=20Software=20Foundation,=20either=20version=203=20of=20the=0A;;=20= License,=20or=20(at=20your=20option)=20any=20later=20version.=0A=0A;;=20= indent-bars=20is=20distributed=20in=20the=20hope=20that=20it=20will=20be=20= useful,=0A;;=20but=20WITHOUT=20ANY=20WARRANTY;=20without=20even=20the=20= implied=20warranty=20of=0A;;=20MERCHANTABILITY=20or=20FITNESS=20FOR=20A=20= PARTICULAR=20PURPOSE.=20=20See=20the=20GNU=0A;;=20General=20Public=20= License=20for=20more=20details.=0A=0A;;=20You=20should=20have=20received=20= a=20copy=20of=20the=20GNU=20General=20Public=20License=0A;;=20along=20= with=20this=20program.=20=20If=20not,=20see=20= <https://www.gnu.org/licenses/>.=0A=0A;;;=20Commentary:=0A=0A;;=20= indent-bars=20highlights=20indentation=20with=20configurable=20font-lock=0A= ;;=20based=20vertical=20bars,=20using=20stipples.=20=20The=20color=20and=20= appearance=0A;;=20(weight,=20pattern,=20position=20within=20the=20= character,=20zigzag,=20etc.)=20are=0A;;=20all=20configurable.=20=20= Includes=20the=20option=20for=20depth-varying=20colors=20and=0A;;=20= highlighting=20the=20indentation=20level=20of=20the=20current=20line.=20=20= Bars=20span=0A;;=20blank=20lines,=20by=20default.=20=20indent-bars=20= works=20in=20any=20mode=20using=20fixed=20tab=0A;;=20or=20space-based=20= indentation.=20=20In=20the=20terminal=20(or=20on=20request)=20it=0A;;=20= uses=20vertical=20bar=20characters=20instead=20of=20stipple=20patterns.=0A= =0A;;=20For=20Developers:=0A;;=0A;;=20To=20efficiently=20accommodate=20= simultaneous=20alternative=20bar=20styling,=20we=0A;;=20do=20two=20= things:=0A;;=0A;;=20=201.=20Collect=20all=20the=20style=20related=20= information=20(color,=20stipple=0A;;=20=20=20=20=20pattern,=20etc.)=20= into=20a=20single=20struct,=20operating=20on=20one=20such=0A;;=20=20=20=20= =20"current"=20style=20struct=20at=20a=20time.=0A;;=0A;;=20=202.=20= Provide=20convenience=20functions=20for=20replicating=20"alternative"=0A= ;;=20=20=20=20=20custom=20variables=20the=20user=20can=20configure;=20= see=0A;;=20=20=20=20=20`indent-bars--style'.=20=20These=20variables=20= can=20"inherit"=20nil=20or=0A;;=20=20=20=20=20omitted=20plist=20= variables=20from=20their=20parent=20var.=0A;;=0A;;=20To=20temporarily=20= alter=20the=20current=20style,=20it's=20enough=20to=20bind=20the=0A;;=20= variable=20`indent-bars-current-style'=20dynamically.=0A;;=0A;;=20Note=20= the=20shorthand=20substitution=20for=20style=20related=20slot;=0A;;=20= see=20file-local-variables=20at=20the=20end:=0A;;=20=0A;;=20=20=20=20= ibs/=20=20=3D>=20indent-bars-style-=0A=0A;;;=20Code:=0A;;;;=20Requires=0A= (require=20'cl-lib)=0A(require=20'map)=0A(require=20'seq)=0A(require=20= 'subr-x)=0A(require=20'color)=0A(require=20'timer)=0A(require=20= 'outline)=0A(require=20'font-lock)=0A(require=20'face-remap)=0A(require=20= 'cus-edit)=0A(require=20'compat)=0A=0A;;;;=20Variables=0A(defvar=20= indent-bars-mode)=0A;;;;=20Customization=0A(defgroup=20indent-bars=20nil=0A= =20=20"Highlight=20indentation=20bars."=0A=20=20:group=20'convenience=0A=20= =20:prefix=20"indent-bars-")=0A=0A(defgroup=20indent-bars-style=20nil=0A=20= =20"Highlight=20indentation=20bars."=0A=20=20:group=20'indent-bars=0A=20=20= :prefix=20"indent-bars-")=0A=0A(defvar=20indent-bars-depth-update-delay)=0A= (defvar=20indent-bars-custom-set=20nil)=0A(defun=20= indent-bars--custom-set=20(sym=20val)=0A=20=20"Set=20SYM=20to=20VAL,=20= and=20reset=20indent-bars=20in=20the=20`other-window'."=0A=20=20= (set-default-toplevel-value=20sym=20val)=0A=20=20(when=20(boundp=20= 'indent-bars-mode)=0A=20=20=20=20(cl-loop=20for=20win=20in=20= (window-list)=0A=09=20=20=20=20=20if=20(buffer-local-value=20= 'indent-bars-mode=20(window-buffer=20win))=20do=0A=09=20=20=20=20=20= (with-selected-window=20win=0A=09=20=20=20=20=20=20=20= (indent-bars-reset)=0A=09=20=20=20=20=20=20=20(let=20= ((indent-bars-depth-update-delay=200))=0A=09=09=20= (indent-bars--highlight-current-depth=20'force))=0A=09=20=20=20=20=20=20=20= (run-hooks=20'indent-bars-custom-set))=0A=09=20=20=20=20=20and=20return=20= win)))=0A=0A;;;;;=20Stipple=20Bar=20Shape=0A(defcustom=20= indent-bars-width-frac=200.375=0A=20=20"The=20width=20of=20the=20indent=20= bar=20as=20a=20fraction=20of=20the=20character=20width.=0AApplies=20to=20= stipple-based=20bars=20only."=0A=20=20:type=20'(float=20:tag=20"Width=20= Fraction"=0A=09=09:match=20(lambda=20(_=20val)=20(and=20val=20(<=3D=20= val=201)=20(>=3D=20val=200)))=0A=09=09:type-error=20"Fraction=20must=20= be=20between=200=20and=201")=0A=20=20:group=20'indent-bars-style=0A=20=20= :set=20#'indent-bars--custom-set)=0A=0A(defcustom=20indent-bars-pad-frac=20= 0.1=0A=20=20"The=20offset=20of=20the=20bar=20from=20the=20left=20edge=20= of=20the=20character.=0AA=20float,=20the=20fraction=20of=20the=20= character=20width.=20=20Applies=20to=0A=20stipple-based=20bars=20only."=0A= =20=20:type=20'(float=20:tag=20"Offset=20Fraction"=0A=09=09:match=20= (lambda=20(_=20val)=20(and=20val=20(<=3D=20val=201)=20(>=3D=20val=200)))=0A= =09=09:type-error=20"Fraction=20must=20be=20between=200=20and=201")=0A=20= =20:group=20'indent-bars-style=0A=20=20:set=20#'indent-bars--custom-set)=0A= =0A(defcustom=20indent-bars-pattern=20"=20..=20=20..=20"=0A=20=20"A=20= pattern=20specifying=20the=20vertical=20structure=20of=20indent=20bars.=0A= Space=20signifies=20blank=20regions,=20and=20any=20other=20character=20= signifies=0Afilled=20regions.=20=20The=20pattern=20length=20is=20scaled=20= to=20match=20the=0Acharacter=20height.=20=20Example:=20\".=20.=20\"=20= would=20specify=20alternating=0Afilled=20and=20blank=20regions=20each=20= approximately=20one-quarter=20of=20the=0Acharacter=20height.=20=20Note=20= that=20the=20non-blank=20characters=20need=20not=20be=0Athe=20same=20= (e.g.,=20see=20`indent-bars-zigzag').=20=20Applies=20to=0Astipple-based=20= bars=20only."=0A=20=20:type=20'(string=20:tag=20"Fill=20Pattern")=0A=20=20= :group=20'indent-bars-style=0A=20=20:set=20#'indent-bars--custom-set)=0A=0A= (defcustom=20indent-bars-zigzag=20nil=0A=20=20"The=20zigzag=20to=20apply=20= to=20the=20bar=20pattern.=0AIf=20non-nil,=20an=20alternating=20zigzag=20= offset=20will=20be=20applied=20to=0Aconsecutive=20groups=20of=20= identical=20non-space=20characters=20in=0A`indent-bars-pattern'.=20=20= Starting=20from=20the=20top=20of=20the=20pattern,=0Apositive=20values=20= will=20zigzag=20(right,=20left,=20right,=20..)=20and=20negative=0Avalues=20= (left,=20right,=20left,=20...).=0A=0AExample:=0A=0A=20=20pattern:=20\"=20= .**.\"=0A=20=20width:=20=20=200.5=0A=20=20pad:=20=20=20=20=200.25=0A=20=20= zigzag:=20-0.25=0A=0Awould=20produce=20a=20zigzag=20pattern=20which=20= differs=20from=20the=20normal=0Abar=20pattern=20as=20follows:=0A=0A=20=20= =20=20|=20=20=20=20|=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=20|=0A= =20=20=20=20|=20..=20|=20=3D=3D=3D=3D=3D=3D=3D=3D=3D>=20|..=20=20|=0A=20=20= =20=20|=20..=20|=20=20=20=20=20=20=20=20=20=20=20=20|=20=20..|=0A=20=20=20= =20|=20..=20|=20apply=20zig-=20|=20=20..|=0A=20=20=20=20|=20..=20|=20zag=20= -0.25=20=20|..=20=20|=0A=0ANote=20that=20the=20pattern=20will=20be=20= truncated=20at=20both=20left=20and=20right=0Aboundaries,=20so=20= (although=20this=20is=20not=20required)=20achieving=20an=20equal=0A= zigzag=20left=20and=20right=20requires=20leaving=20sufficient=20padding=20= on=20each=0Aside=20of=20the=20bar;=20see=20`indent-bars-pad-frac'=20and=0A= `indent-bars-width-frac'.=20=20Applies=20to=20stipple-based=20bars=20= only."=0A=20=20:type=20'(choice=20:tag=20"Zigzag=20Options"=0A=09=09=20= (const=20:tag=20"No=20Zigzag"=20:value=20nil)=0A=09=09=20(float=20:value=20= 0.1=20:tag=20"Zigzag=20Fraction"=0A=09=09=09:match=20(lambda=20(_=20val)=20= (and=20val=20(<=3D=20val=201)=20(>=3D=20val=20-1)))=0A=09=09=09= :type-error=20"Fraction=20must=20be=20between=20-1=20and=201"))=0A=20=20= :group=20'indent-bars-style=0A=20=20:set=20#'indent-bars--custom-set)=0A=0A= ;;;;;=20Bar=20Colors=0A(defcustom=20indent-bars-color=0A=20=20= '(highlight=20:face-bg=20t=20:blend=200.5)=0A=20=20"The=20main=20indent=20= bar=20color.=0AThe=20format=20is=20a=20list=20of=201=20required=20= element,=20followed=20by=20an=0Aoptional=20plist=20(keyword/value=20= pairs):=0A=0A=20=20(main_color=20[:face-bg=20:blend])=0A=0Awhere:=0A=0A=20= =20MAIN_COLOR:=20Specifies=20the=20main=20indentation=20bar=0A=20=20=20=20= color=20(required).=20=20It=20is=20either=20a=20face=20name=20symbol,=20= from=0A=20=20=20=20which=20the=20foreground=20color=20will=20be=20used=20= as=20the=20primary=20bar=0A=20=20=20=20color,=20or=20an=20explicit=20= color=20(a=20string).=20=20If=20nil,=20the=20default=0A=20=20=20=20color=20= foreground=20will=20be=20used.=0A=0A=20=20FACE-BG:=20A=20boolean=20= controlling=20interpretation=20of=20the=0A=20=20=20=20MAIN_COLOR=20face=20= (if=20configured).=20=20If=20non-nil,=20the=20background=0A=20=20=20=20= color=20of=20the=20face=20will=20be=20used=20as=20the=20main=20bar=20= color=20instead=0A=20=20=20=20of=20its=20foreground.=0A=0A=20=20BLEND:=20= an=20optional=20blend=20factor,=20a=20float=20between=200=20and=201.=20=20= If=0A=20=20=20=20non-nil,=20the=20main=20bar=20color=20will=20be=20= computed=20as=20a=20blend=0A=20=20=20=20between=20MAIN_COLOR=20and=20the=20= frame=20background=20color,=0A=20=20=20=20notionally:=0A=0A=20=20=20=20=20= =20BLEND=20*=20MAIN_COLOR=20+=20(1=20-=20BLEND)=20*=20frame-background=0A= =0A=20=20=20=20If=20BLEND=20is=20nil=20or=20unspecified,=20no=20blending=20= is=20done,=20and=0A=20=20=20=20MAIN_COLOR=20is=20used=20as-is."=0A=20=20= :type=0A=20=20'(list=20:tag=20"Color=20Options"=0A=09=20(choice=20:tag=20= "Main=20Bar=20Color"=0A=09=09=20color=0A=09=09=20(face=20:tag=20"from=20= Face")=0A=09=09=20(const=20:tag=20"Use=20default"=20nil))=0A=09=20(plist=20= :tag=20"Other=20Options"=0A=09=09:inline=20t=0A=09=09:options=0A=09=09= ((:face-bg=20(boolean=0A=09=09=09=20=20=20=20:tag=20"Use=20Face's=20= Background=20Color"=0A=09=09=09=20=20=20=20:value=20t))=0A=09=09=20= (:blend=20(float=0A=09=09=09=20=20:tag=20"Blend=20Factor"=0A=09=09=09=20=20= :value=200.5=0A=09=09=09=20=20:match=20(lambda=20(_=20val)=20(and=20val=20= (<=3D=20val=201)=20(>=3D=20val=200)))=0A=09=09=09=20=20:type-error=20= "Factor=20must=20be=20between=200=20and=201")))))=0A=20=20:group=20= 'indent-bars-style=0A=20=20:set=20#'indent-bars--custom-set)=0A=0A= (defcustom=20indent-bars-color-by-depth=0A=20=20'(:regexp=20= "outline-\\([0-9]+\\)"=20:blend=201)=0A=20=20"Configuration=20for=20= depth-varying=20indentation=20bar=20coloring.=0AIf=20non-nil,=20= depth-based=20coloring=20is=20performed.=20=20This=20should=20be=20a=0A= plist=20with=20keys:=0A=0A=20=20=20=20([:regexp=20[:face-bg]=20|=20= :palette]=20[:blend])=0A=0Awith:=0A=0A=20=20REGEXP:=20A=20regular=20= expression=20string=20used=20to=20match=20against=20all=0A=20=20=20=20= face=20names.=20=20For=20the=20matching=20faces,=20the=20first=20match=20= group=20in=0A=20=20=20=20the=20regex=20(if=20any)=20will=20be=20= interpreted=20as=20a=20number,=20and=20used=0A=20=20=20=20to=20sort=20= the=20resulting=20list=20of=20faces.=20=20The=20foreground=20color=20of=0A= =20=20=20=20each=20matching=20face=20will=20then=20constitute=20the=20= depth=20color=0A=20=20=20=20palette=20(see=20also=20PALETTE,=20which=20= this=20option=20overrides).=0A=0A=20=20FACE-BG:=20A=20boolean.=20=20If=20= non-nil,=20use=20the=20background=20color=0A=20=20=20=20from=20the=20= faces=20matching=20REGEXP=20for=20the=20palette=20instead=20of=0A=20=20=20= =20their=20foreground=20colors.=0A=0A=20=20PALETTE:=20An=20explicit=20= cyclical=20palette=20of=20colors/faces=20for=0A=20=20=20=20depth-varying=20= bar=20colors.=20=20Note=20that=20REGEXP=20takes=20precedence=0A=20=20=20=20= over=20this=20setting.=20=20The=20format=20is=20a=20list=20of=20faces=20= (symbols)=0A=20=20=20=20or=20colors=20(strings)=20to=20be=20used=20as=20= a=20color=20cycle=20for=20coloring=0A=20=20=20=20indentations=20at=20= increasing=20levels.=20=20Each=20face=20can=20optionally=0A=20=20=20=20= be=20specified=20as=20a=20cons=20cell=20(face=20.=20\\=3D'bg)=20to=20= specify=20using=0A=20=20=20=20that=20face's=20background=20color=20= instead=20of=20its=20foreground.=0A=0A=20=20=20=20=20=20(face_or_color=20= |=20(face=20.=20\\=3D'bg)=20...)=0A=0A=20=20=20=20While=20this=20list=20= can=20contain=20a=20single=20element,=20it=20makes=20little=0A=20=20=20=20= sense=20to=20do=20so.=20=20The=20depth=20palette=20will=20be=20used=20= cyclically,=0A=20=20=20=20i.e.=20when=20a=20bar's=20indentation=20depth=20= exceeds=20the=20length=20of=20the=0A=20=20=20=20palette,=20colors=20will=20= be=20obtained=20by=20wrapping=20around=20to=20the=0A=20=20=20=20= beginning=20of=20the=20list.=0A=0A=20=20BLEND:=20a=20blend=20factor=20= (0..1)=20which=20controls=20how=20palette=20colors=0A=20=20=20=20are=20= blended=20with=20the=20main=20color,=20prior=20to=20possibly=20blending=0A= =20=20=20=20with=20the=20frame=20background=20color=20(see=20= `indent-bars-color'=20for=0A=20=20=20=20information=20on=20how=20blend=20= factors=20are=20specified).=20=20A=20nil=20value=0A=20=20=20=20causes=20= the=20palette=20colors=20to=20be=20used=20as-is.=20=20A=20unity=20value=0A= =20=20=20=20causes=20the=20palette=20color=20to=20be=20blended=20= directly=20with=20the=0A=20=20=20=20background=20using=20any=20blend=20= factor=20from=20`indent-bars-color'.=0A=0ANote=20that,=20for=20this=20= setting=20to=20have=20any=20effect,=20one=20of=20REGEXP=20or=0APALETTE=20= is=20required=20(the=20former=20overriding=20the=20latter).=20=20If=20= both=0Aare=20omitted=20or=20nil,=20all=20bars=20will=20have=20the=20same=20= color,=20based=20on=0AMAIN_COLOR=20(aside=20possibly=20from=20the=20bar=20= at=20the=20current=0Aindentation=20level,=20if=20configured;=20see=0A= `indent-bars-highlight-current-depth')."=0A=20=20:type=20'(choice=20:tag=20= "Depth=20Palette"=0A=09=09=20(const=20:tag=20"No=20Depth-Coloring"=20= nil)=0A=09=09=20(plist=20:tag=20"Depth-Coloring"=0A=09=09=09:options=0A=09= =09=09((:regexp=20(regexp=20:tag=20"Face=20regexp"))=0A=09=09=09=20= (:face-bg=0A=09=09=09=20=20(boolean=0A=09=09=09=20=20=20:value=20t=0A=09=09= =09=20=20=20:tag=20"Use=20Matching=20Face's=20Background=20Colors"))=0A=09= =09=09=20(:palette=0A=09=09=09=20=20(repeat=20:tag=20"Explicit=20= Color/Face=20List"=0A=09=09=09=09=20=20(choice=20(color=20:tag=20= "Color")=0A=09=09=09=09=09=20=20(face=20:tag=20"Foreground=20from=20= Face")=0A=09=09=09=09=09=20=20(cons=20:tag=20"Background=20from=20Face"=0A= =09=09=09=09=09=09:format=20"Background=20from=20%v"=0A=09=09=09=09=09=09= face=0A=09=09=09=09=09=09(const=20:format=20"\n"=20:value=20bg)))))=0A=09= =09=09=20(:blend=0A=09=09=09=20=20(float=20:tag=20"Blend=20Fraction=20= into=20Main=20Color"=0A=09=09=09=09=20:value=200.5=0A=09=09=09=09=20= :match=20(lambda=20(_=20val)=0A=09=09=09=09=09=20=20(and=20val=20(<=3D=20= val=201)=20(>=3D=20val=200)))=0A=09=09=09=09=20:type-error=0A=09=09=09=09= =20"Factor=20must=20be=20between=200=20and=201")))))=0A=20=20:group=20= 'indent-bars-style=0A=20=20:set=20#'indent-bars--custom-set)=0A=0A;;;;;=20= Depth=20Highlighting=0A(defcustom=20indent-bars-highlight-current-depth=0A= =20=20'(:pattern=20".")=09=09=09;=20solid=20bar,=20no=20color=20change=0A= =20=20"Current=20indentation=20depth=20bar=20highlight=20configuration.=0A= Use=20this=20to=20configure=20optional=20highlighting=20of=20the=20bar=20= at=20the=0Acurrent=20line's=20indentation=20depth=20level.=0A=0AFormat:=0A= =0A=20=20=20=20nil=20|=20(:color=20:face=20:face-bg=20:background=20= :blend=20:palette=0A=20=20=20=20=20=20=20=20=20=20=20:width=20:pad=20= :pattern=20:zigzag)=0A=0AIf=20nil,=20no=20highlighting=20will=20be=20= applied=20to=20bars=20at=20the=20current=0Adepth=20of=20the=20line=20at=20= point.=20=20Otherwise,=20a=20plist=20describes=20what=0Ahighlighting=20= to=20apply,=20which=20can=20include=20changes=20to=20color=20and/or=0A= bar=20pattern.=20=20At=20least=20one=20of=20:blend,=20:color,=20= :palette,=20:face,=0A:width,=20:pad,=20:pattern,=20or=20:zigzag=20must=20= be=20set=20and=20non-nil=20for=0Athis=20setting=20to=20take=20effect.=0A=0A= By=20default,=20the=20highlighted=20bar's=20color=20will=20be=20the=20= same=20as=20the=0Aunderlying=20bar=20color.=20=20With=20PALETTE,=20COLOR=20= or=20FACE=20set,=20all=20bars=0Aat=20the=20current=20depth=20will=20be=20= highlighted=20in=20the=20appropriate=0Acolor,=20either=20from=20an=20= explicit=20COLOR,=20a=20PALETTE=20list=20(see=0A= `indent-bars-color-by-depth'),=20or,=20if=20FACE=20is=20set,=20FACE's=0A= foreground=20or=20background=20color=20(the=20latter=20if=20FACE-BG=20is=0A= non-nil).=20=20If=20PALETTE=20is=20provided,=20it=20overrides=20any=20= other=0Aforeground=20color=20setting=20for=20the=20current=20depth=20= highlight=20bar.=20=20If=0ABACKGROUND=20is=20set=20to=20a=20color,=20= this=20will=20be=20used=20for=20the=0Abackground=20color=20of=20the=20= current=20depth=20bar.=0A=0AIf=20BLEND=20is=20provided,=20it=20is=20a=20= blend=20fraction=20between=200=20and=201=20for=0Ablending=20the=20= specified=20highlight=20color=20with=20the=0Aexisting=20(depth-based=20= or=20main)=20bar=20color;=20see=20`indent-bars-color'=0Afor=20its=20= meaning.=20=20BLEND=3D1=20indicates=20using=20the=20full,=20unblended=0A= highlight=20color=20(and=20is=20the=20same=20as=20omitting=20BLEND).=0A=0A= As=20a=20special=20case,=20if=20BLEND=20is=20provided,=20but=20neither=20= COLOR=20nor=0AFACE=20is,=20BLEND=20is=20used=20as=20a=20(presumably=20= distinct)=20blend=20factor=0Abetween=20the=20usual=20color=20for=20that=20= bar=20and=20the=20frame=20background.=0AThe=20original=20colors=20are=20= specified=20in=20`indent-bars-color-by-depth'=0Aor=20= `indent-bars-color'.=20=20In=20this=20manner=20the=20current-depth=0A= highlight=20can=20be=20made=20a=20more=20(or=20less)=20prominent=20= version=20of=20the=0Adefault=20coloring,=20just=20by=20setting=20BLEND.=0A= =0AIf=20any=20of=20WIDTH,=20PAD,=20PATTERN,=20or=20ZIGZAG=20are=20set,=20= the=20stipple=20bar=0Apattern=20at=20the=20current=20level=20will=20be=20= altered=20as=20well.=20=20Note=20that=0A`indent-bars-width-frac',=20= `indent-bars-pad-frac',=0A`indent-bars-pattern',=20and=20= `indent-bars-zigzag'=20will=20be=20used=20as=0Adefaults=20for=20any=20= missing=20values;=20see=20these=20variables.=0A=0ANote:=20on=20terminal,=20= or=20if=20`indent-bars-prefer-character'=20is=0Anon-nil,=20any=20stipple=20= appearance=20parameters=20will=20be=20ignored."=0A=20=20:type=20'(choice=0A= =09=20=20:tag=20"Highlighting=20Options"=0A=09=20=20(const=20:tag=20"No=20= Current=20Highlighting"=20:value=20nil)=0A=09=20=20(plist=20:tag=20= "Highlight=20Current=20Depth"=0A=09=09=20:options=0A=09=09=20((:color=20= (color=20:tag=20"Highlight=20Color"))=0A=09=09=20=20(:face=20(face=20= :tag=20"Color=20from=20Face"))=0A=09=09=20=20(:face-bg=20(boolean=20:tag=20= "Use=20Face's=20Background=20Color"))=0A=09=09=20=20(:background=20= (color=20:tag=20"Background=20Color=20of=20Current=20Bar"))=0A=09=09=20=20= (:blend=20(float=20:tag=20"Blend=20Fraction=20into=20Existing=20Color")=0A= =09=09=09=20=20:value=200.5=0A=09=09=09=20=20:match=20(lambda=20(_=20= val)=20(and=20(<=3D=20val=201)=20(>=3D=20val=200)))=0A=09=09=09=20=20= :type-error=20"Factor=20must=20be=20between=200=20and=201")=0A=09=09=20=20= (:palette=0A=09=09=20=20=20(repeat=20:tag=20"Explicit=20Color/Face=20= List"=0A=09=09=09=20=20=20(choice=20(color=20:tag=20"Color")=0A=09=09=09=09= =20=20=20(face=20:tag=20"Foreground=20from=20Face")=0A=09=09=09=09=20=20=20= (cons=20:tag=20"Background=20from=20Face"=0A=09=09=09=09=09=20:format=20= "Background=20from=20%v"=0A=09=09=09=09=09=20face=0A=09=09=09=09=09=20= (const=20:format=20"\n"=20:value=20bg)))))=0A=09=09=20=20(:width=20= (float=20:tag=20"Bar=20Width"))=0A=09=09=20=20(:pad=20(float=20:tag=20= "Bar=20Padding=20(from=20left)"))=0A=09=09=20=20(:pattern=20(string=20= :tag=20"Fill=20Pattern"))=0A=09=09=20=20(:zigzag=20(float=20:tag=20= "Zig-Zag")))))=0A=20=20:group=20'indent-bars-style=0A=20=20:set=20= #'indent-bars--custom-set)=0A=0A(defcustom=20= indent-bars-highlight-selection-method=20'context=0A=20=20"Method=20for=20= selecting=20bar=20depth=20for=20current=20indentation=20highlight.=0AIf=20= nil,=20the=20last=20showing=20bar=20on=20the=20current=20line=20is=20= selected=20for=0Ahighlight.=20=20If=20the=20symbol=20`on-bar',=20and=20= the=20start=20of=20the=20text=20on=0Athe=20line=20would=20have=20fallen=20= directly=20on=20a=20bar,=20highlight=20that=20bar=0Adepth=20instead.=20=20= If=20`context',=20use=20`on-bar'=20logic,=20but=20only=20if=20a=0A= directly=20adjacent=20(non-blank)=20context=20line=20is=20indented=20= deeper,=20by=0Amore=20than=20one=20indent=20spacing.=20=20Otherwise=20= select=20the=20last=20bar=0Ashowing=20for=20highlight=20(i.e.=20the=20= same=20as=20CONTEXT=20nil)."=0A=20=20:type=20'(choice=20(const=20:tag=20= "Containing"=20nil)=0A=09=09=20(const=20:tag=20"On=20Bar"=20on-bar)=0A=09= =09=20(const=20:tag=20"Context"=20context))=0A=20=20:group=20= 'indent-bars)=0A=0A(defcustom=20indent-bars-depth-update-delay=200.075=0A= =20=20"Minimum=20delay=20time=20in=20seconds=20between=20depth=20= highlight=20updates.=0AHas=20effect=20only=20if=20= `indent-bars-highlight-current-depth'=20is=0Anon-nil.=20=20Set=20to=200=20= for=20instant=20depth=20updates."=0A=20=20:type=20'float=0A=20=20:group=20= 'indent-bars)=0A=0A;;;;;=20Other=0A(defcustom=20= indent-bars-display-on-blank-lines=20t=0A=20=20"Whether=20to=20display=20= bars=20on=20blank=20lines."=0A=20=20:type=20'boolean=0A=20=20:set=20= #'indent-bars--custom-set=0A=20=20:group=20'indent-bars)=0A=0A(defcustom=20= indent-bars-no-descend-string=20t=0A=20=20"Configure=20bar=20behavior=20= inside=20strings.=0AIf=20non-nil,=20displayed=20bars=20inside=20the=20= string=20will=20go=20no=20deeper=0Athan=20the=20indent=20level=20of=20= the=20string's=20starting=20line."=0A=20=20:local=20t=0A=20=20:type=20= 'boolean=0A=20=20:set=20#'indent-bars--custom-set=0A=20=20:group=20= 'indent-bars)=0A=0A(defcustom=20indent-bars-no-descend-lists=20t=0A=20=20= "Configure=20bar=20behavior=20inside=20lists.=0AIf=20non-nil,=20= displayed=20bars=20will=20go=20no=20deeper=20than=20the=20indent=0Alevel=20= at=20the=20starting=20line=20of=20the=20innermost=20containing=20list."=0A= =20=20:local=20t=0A=20=20:type=20'boolean=0A=20=20:set=20= #'indent-bars--custom-set=0A=20=20:group=20'indent-bars)=0A=0A(defcustom=20= indent-bars-prefer-character=20nil=0A=20=20"Use=20characters=20instead=20= of=20stipple=20to=20draw=20bars.=0ANormally=20characters=20are=20used=20= on=20terminal=20only.=20=20A=20non-nil=20value=0Aspecifies=20using=20= character=20bars=20exclusively.=20=20See=0A= `indent-bars-no-stipple-char'."=0A=20=20:type=20'boolean=0A=20=20:set=20= #'indent-bars--custom-set=0A=20=20:group=20'indent-bars)=0A=0A(defcustom=20= indent-bars-no-stipple-char=20?\=E2=94=82=0A=20=20"Character=20to=20= display=20when=20stipple=20is=20unavailable=20(as=20in=20the=20= terminal)."=0A=20=20:type=20'char=0A=20=20:set=20= #'indent-bars--custom-set=0A=20=20:group=20'indent-bars)=0A=0A(defcustom=20= indent-bars-no-stipple-char-font-weight=20nil=0A=20=20"Font=20weight=20= to=20use=20to=20draw=20the=20character=20bars.=0AIf=20non-nil,=20set=20= the=20no-stipple=20character=20font=20weight=20accordingly."=0A=20=20= :type=20`(choice=0A=20=20=20=20=20=20=20=20=20=20(const=20:tag=20"Use=20= Default=20Weight"=20nil)=0A=20=20=20=20=20=20=20=20=20=20,@(mapcar=20= (lambda=20(item)=20(list=20'const=20(aref=20item=201)))=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20font-weight-table))=0A=20=20= :set=20#'indent-bars--custom-set=0A=20=20:group=20'indent-bars)=0A=0A= (defcustom=20indent-bars-unspecified-bg-color=20"black"=0A=20=20"Color=20= to=20use=20as=20the=20frame=20background=20color=20if=20unspecified.=0A= Unless=20actively=20set,=20most=20terminal=20frames=20do=20not=20have=20= a=0Abackground=20color=20specified.=20=20This=20setting=20controls=20the=20= background=0Acolor=20to=20use=20for=20color=20blending=20in=20that=20= case."=0A=20=20:type=20'color=0A=20=20:set=20#'indent-bars--custom-set=0A= =20=20:group=20'indent-bars)=0A=0A(defcustom=20= indent-bars-unspecified-fg-color=20"white"=0A=20=20"Color=20to=20use=20= as=20the=20default=20foreground=20color=20if=20unspecified."=0A=20=20= :type=20'color=0A=20=20:set=20#'indent-bars--custom-set=0A=20=20:group=20= 'indent-bars)=0A=0A(defcustom=20indent-bars-starting-column=20nil=0A=20=20= "The=20starting=20column=20on=20which=20to=20display=20the=20first=20= bar.=0ASet=20to=20nil,=20for=20the=20default=20behavior=20(first=20bar=20= at=20the=20first=0Aindent=20level)=20or=20an=20integer=20value=20for=20= some=20other=20column."=0A=20=20:type=20'(choice=20(const=20:tag=20= "Default:=201st=20indent=20position"=20nil)=0A=09=09=20(integer=20:tag=20= "Specified=20column"))=0A=20=20:set=20#'indent-bars--custom-set=0A=20=20= :group=20'indent-bars)=0A=0A(defcustom=20indent-bars-spacing-override=20= nil=0A=20=20"Override=20for=20default,=20major-mode=20based=20= indentation=20spacing.=0ASet=20only=20if=20the=20default=20guessed=20= spacing=20is=20incorrect.=20=20Becomes=0Abuffer-local=20automatically."=0A= =20=20:local=20t=0A=20=20:type=20'(choice=20integer=20(const=20:tag=20= "Discover=20automatically"=20:value=20nil))=0A=20=20:set=20= #'indent-bars--custom-set=0A=20=20:group=20'indent-bars)=0A=0A(defcustom=20= indent-bars-treesit-support=20nil=0A=20=20"Whether=20to=20enable=20= tree-sitter=20support=20(if=20available)."=0A=20=20:type=20'boolean=0A=20= =20:set=20#'indent-bars--custom-set=0A=20=20:group=20'indent-bars)=0A=0A= ;;;;;=20Color=20Utilities=0A(defun=20= indent-bars--frame-background-color()=0A=20=20"Return=20the=20frame=20= background=20color."=0A=20=20(let=20((fb=20(frame-parameter=20nil=20= 'background-color)))=0A=20=20=20=20(cond=20((not=20fb)=20"white")=0A=09=20= =20((string=3D=20fb=20"unspecified-bg")=20= indent-bars-unspecified-bg-color)=0A=09=20=20(t=20fb))))=0A=0A(defun=20= indent-bars--blend-colors=20(c1=20c2=20fac)=0A=20=20"Return=20a=20= fractional=20color=20between=20two=20colors=20C1=20and=20C2.=0AEach=20is=20= a=20string=20color.=20=20The=20fractional=20blend=20point=20is=20the=0A= float=20FAC,=20with=201.0=20matching=20C1=20and=200.0=20C2."=0A=20=20= (apply=20#'color-rgb-to-hex=0A=09=20(cl-mapcar=20(lambda=20(a=20b)=0A=09=09= =20=20=20=20=20=20(+=20(*=20a=20fac)=20(*=20b=20(-=201.0=20fac))))=0A=09=09= =20=20=20=20(color-name-to-rgb=20c1)=20(color-name-to-rgb=20c2))))=0A=0A= (defun=20indent-bars--colors-from-regexp=20(regexp=20&optional=20= face-bg)=0A=20=20"Return=20a=20list=20of=20colors=20(strings)=20for=20= faces=20matching=20REGEXP.=0AThe=20first=20capture=20group=20in=20REGEXP=20= will=20be=20interpreted=20as=20a=20number=0Aand=20used=20to=20sort=20the=20= list=20numerically.=20=20A=20list=20of=20the=20foreground=0Acolor=20of=20= the=20matching,=20sorted=20faces=20will=20be=20returned,=20unless=0A= FACE-BG=20is=20non-nil,=20in=20which=20case=20the=20background=20color=20= is=0Areturned."=0A=20=20(mapcar=20(lambda=20(x)=20(funcall=20(if=20= face-bg=20#'face-background=20#'face-foreground)=0A=09=09=09=20=20=20=20=20= =20=20(cdr=20x)=20nil=20t))=0A=20=20=20=20=20=20=20=20=20=20(seq-sort-by=20= #'car=0A=09=09=20=20=20=20=20=20=20(lambda=20(a=20b)=20(cond=0A=09=09=09=09= =20=20=20=20=20=20((not=20(numberp=20b))=20t)=0A=09=09=09=09=20=20=20=20=20= =20((not=20(numberp=20a))=20nil)=0A=09=09=09=09=20=20=20=20=20=20(t=20(<=20= a=20b))))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20(delq=20nil=0A=09=09=09=20=20=20=20=20(seq-map=0A=09=09=09=20=20=20= =20=20=20(lambda=20(x)=0A=09=09=09=09(let=20((n=20(symbol-name=20x)))=0A=09= =09=09=09=20=20(if=20(string-match=20regexp=20n)=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20(cons=20(string-to-number=20(match-string=201=20n))=0A=09=09= =09=09=09=20=20=20=20x))))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(face-list))))))=0A=0A= (defun=20indent-bars--unpack-palette=20(palette)=0A=20=20"Process=20a=20= face=20or=20color-based=20PALETTE."=0A=20=20(delq=20nil=0A=09(cl-loop=20= for=20el=20in=20palette=0A=09=09=20collect=20(cond=0A=09=09=09=20=20= ((and=20(consp=20el)=20(facep=20(car=20el)))=0A=09=09=09=20=20=20= (face-background=20(car=20el)))=0A=09=09=09=20=20((facep=20el)=0A=09=09=09= =20=20=20(face-foreground=20el))=0A=09=09=09=20=20((color-defined-p=20= el)=20el)=0A=09=09=09=20=20(t=20nil)))))=0A;;;;=20Style=0A(defvar=20= indent-bars-style=20nil=0A=20=20"The=20`indent-bars-style'=20struct=20= for=20the=20main=20style.")=0A=0A(defvar=20indent-bars--styles=20nil=0A=20= =20"List=20of=20known=20indent-bars=20style=20structs.")=0A=0A= (cl-declaim=20(optimize=20(safety=200)))=20;=20no=20need=20for=20type=20= check=0A(cl-defstruct=0A=20=20=20=20(indent-bars-style=0A=20=20=20=20=20= (:copier=20nil)=0A=20=20=20=20=20(:conc-name=20ibs/)=09;=20Note:=20ibs/=20= =3D>=20indent-bars-style-=20in=20this=20file=0A=20=20=20=20=20= (:constructor=20nil)=0A=20=20=20=20=20(:constructor=20ibs/create=0A=09=09= =20=20=20(=20&optional=20tag=20&aux=0A=09=09=20=20=20=20=20(stipple-face=0A= =09=09=20=20=20=20=20=20(intern=20(format=20"indent-bars%s-face"=0A=09=09= =09=09=20=20=20=20=20=20(if=20tag=20(concat=20"-"=20tag)=20"")))))))=0A=20= =20"A=20style=20configuration=20structure=20for=20indent-bars."=0A=20=20= (=20tag=20nil=20:type=20string=0A=20=20=20=20:documentation=20"An=20= optional=20tag=20to=20include=20in=20face=20name")=0A=20=20;;=20Colors=20= and=20Faces=0A=20=20(=20main-color=20nil=20:type=20string=0A=20=20=20=20= :documentation=20"The=20main=20bar=20color")=0A=20=20(=20depth-palette=20= nil=0A=20=20=20=20:documentation=20"Palette=20of=20depth=20colors.=0AMay=20= be=20nil,=20a=20color=20string=20or=20a=20vector=20of=20colors=20= strings.")=0A=20=20(=20faces=20nil=20:type=20vector=0A=20=20=20=20= :documentation=20"Depth-based=20faces.")=0A=20=20;;=20Stipple=0A=20=20(=20= stipple-face=20nil=20:type=20face=0A=20=20=20=20:documentation=20"A=20= stipple=20face=20to=20inherit=20from.")=0A=20=20(=20no-stipple-chars=20= nil=0A=20=20=20=20:documentation=20"A=20vector=20of=20styled=20= non-stipple=20chars.")=0A=20=20;;=20Current=20depth=20highlighting=0A=20=20= (=20current-stipple-face=20nil=20:type=20face=0A=20=20=20=20= :documentation=20"A=20current=20depth=20stipple=20face=20to=20inherit=20= from.")=0A=20=20(=20current-bg-color=20nil=20:type=20color=0A=20=20=20=20= :documentation=20"The=20background=20color=20of=20the=20current=20depth=20= highlight.")=0A=20=20(=20current-depth-palette=20nil=0A=20=20=20=20= :documentation=20"Depth=20palette=20of=20highlighted=20colors."))=0A=0A= (defsubst=20indent-bars--tag=20(format-str=20s=20&rest=20r)=0A=20=20"Tag=20= FORMAT-STR=20with=20style=20S=20and=20return=20the=20associate=20= interned=20symbol.=0AAdditional=20`format'=20arguments=20can=20be=20= passed=20as=20R."=0A=20=20(intern=20(apply=20#'format=20format-str=0A=09=09= =20(if=20(ibs/tag=20s)=20(concat=20"-"=20(ibs/tag=20s))=20"")=20r)))=0A=0A= (defun=20indent-bars--new-style=20(&optional=20tag)=0A=20=20"Create=20= and=20record=20a=20new=20style=20struct=20with=20TAG.=0AA=20new=20style=20= is=20only=20created=20if=20an=20existing=20style=20with=20that=20TAG=20= is=0Ano=20yet=20recorded."=0A=20=20(or=20(seq-find=20(lambda=20(s)=20= (equal=20(ibs/tag=20s)=20tag))=20indent-bars--styles)=0A=20=20=20=20=20=20= (let=20((style=20(ibs/create=20tag)))=0A=09(cl-pushnew=20style=20= indent-bars--styles=20:test=20#'equal)=0A=09style)))=0A=0A;;;;;=20Colors=0A= (defun=20indent-bars--main-color=20(style=20&optional=20tint=20= tint-blend=20blend-override)=0A=20=20"Calculate=20the=20main=20bar=20= color=20for=20STYLE.=0AUses=20`indent-bars-color'=20for=20color=20and=20= background=20blend=20config.=0AIf=20TINT=20and=20TINT-BLEND=20are=20= passed,=20first=20blend=20the=20TINT=20color=0Ainto=20the=20main=20color=20= with=20the=20requested=20blend,=20prior=20to=20blending=0Ainto=20the=20= background=20color.=20=20If=20BLEND-OVERRIDE=20is=20set,=20use=20it=0A= instead=20of=20the=20:blend=20factor=20in=20`indent-bars-color'."=0A=20=20= (cl-destructuring-bind=20(main=20&key=20face-bg=20blend)=20= (indent-bars--style=20style=20"color")=0A=20=20=20=20(let=20((col=20= (cond=20((facep=20main)=0A=09=09=20=20=20=20=20=20(funcall=20(if=20= face-bg=20#'face-background=20#'face-foreground)=0A=09=09=09=20=20=20=20=20= =20=20main))=0A=09=09=20=20=20=20=20((color-defined-p=20main)=20main)))=0A= =09=20=20(blend=20(or=20blend-override=20blend)))=0A=20=20=20=20=20=20= (if=20(and=20tint=20tint-blend=20(color-defined-p=20tint))=20;tint=20= main=20color=0A=09=20=20(setq=20col=20(indent-bars--blend-colors=20tint=20= col=20tint-blend)))=0A=20=20=20=20=20=20(if=20blend=09=09=09=09;now=20= blend=20into=20BG=0A=09=20=20(setq=20col=20(indent-bars--blend-colors=0A=09= =09=20=20=20=20=20col=20(indent-bars--frame-background-color)=20blend)))=0A= =20=20=20=20=20=20col)))=0A=0A(defun=20indent-bars--depth-palette=20= (style=20&optional=20blend-override)=0A=20=20"Calculate=20the=20palette=20= of=20depth-based=20colors=20(a=20vector)=20for=20STYLE.=0AIf=20= BLEND-OVERRIDE=20is=20set,=20the=20main=20color's=20:blend=20will=20be=20= ignored=0Aand=20this=20value=20will=20be=20used=20instead,=20for=20= blending=20into=20the=20frame=0Abackground=20color.=20=20See=20= `indent-bars-color-by-depth'."=0A=20=20(when-let=20((cbd=20= (indent-bars--style=20style=20"color-by-depth")))=0A=20=20=20=20= (cl-destructuring-bind=20(&key=20regexp=20face-bg=20palette=20blend)=20= cbd=0A=20=20=20=20=20=20(let=20((colors=0A=09=20=20=20=20=20(cond=0A=09=20= =20=20=20=20=20(regexp=0A=09=20=20=20=20=20=20=20= (indent-bars--colors-from-regexp=20regexp=20face-bg))=0A=09=20=20=20=20=20= =20(palette=0A=09=20=20=20=20=20=20=20(indent-bars--unpack-palette=20= palette)))))=0A=09(vconcat=0A=09=20(if=20(or=20blend=20blend-override)=0A= =09=20=20=20=20=20(mapcar=20(lambda=20(c)=0A=09=09=20=20=20=20=20=20=20= (indent-bars--main-color=20style=20c=20blend=20blend-override))=0A=09=09=20= =20=20=20=20colors)=0A=09=20=20=20colors))))))=0A=0A(defun=20= indent-bars--current-depth-palette=20(style)=0A=20=20"Colors=20for=20= highlighting=20the=20current=20depth=20bar=20for=20STYLE.=0AA=20color=20= or=20palette=20(vector)=20of=20colors=20is=20returned,=20which=20may=20= be=0Anil,=20in=20which=20case=20no=20special=20current=20depth-coloring=20= is=20used.=0ASee=20`indent-bars-highlight-current-depth'=20for=20= configuration."=0A=20=20(when-let=20((hcd=20(indent-bars--style=20style=20= "highlight-current-depth")))=0A=20=20=20=20(cl-destructuring-bind=20= (&key=20color=20face=20face-bg=0A=09=09=09=09=20blend=20palette=20= &allow-other-keys)=0A=09hcd=0A=20=20=20=20=20=20(let=20((color=0A=09=20=20= =20=20=20(cond=0A=09=20=20=20=20=20=20((facep=20face)=0A=09=20=20=20=20=20= =20=20(funcall=20(if=20face-bg=20#'face-background=20#'face-foreground)=0A= =09=09=09face))=0A=09=20=20=20=20=20=20((and=20color=20(color-defined-p=20= color))=20color))))=0A=09(cond=0A=09=20;;=20An=20explicit=20palette=0A=09= =20(palette=0A=09=20=20(vconcat=20(indent-bars--unpack-palette=20= palette)))=0A=0A=09=20;;=20A=20specified=20color=20(possibly=20to=20= blend=20in)=0A=09=20(color=0A=09=20=20(if=20(string=3D=20color=20= "unspecified-fg")=0A=09=20=20=20=20=20=20(setq=20color=20= indent-bars-unspecified-fg-color))=0A=09=20=20(if=20blend=0A=09=20=20=20=20= =20=20(if-let=20((palette=20(indent-bars--depth-palette=20style)))=20;=20= blend=20into=20normal=20depth=20palette=0A=09=09=20=20(vconcat=0A=09=09=20= =20=20(mapcar=20(lambda=20(c)=0A=09=09=09=20=20=20=20=20= (indent-bars--blend-colors=20color=20c=20blend))=0A=09=09=09=20=20=20= palette))=0A=09=09;;=20Just=20blend=20into=20main=20color=0A=09=09= (indent-bars--blend-colors=20color=20(ibs/main-color=20style)=20blend))=0A= =09=20=20=20=20color))=0A=09=20=0A=09=20;;=20blend-only=20without=20a=20= specified=20color:=20re-blend=20originals=20with=20BG=0A=09=20(blend=0A=09= =20=20(or=20(indent-bars--depth-palette=20style=20blend)=0A=09=20=20=20=20= =20=20(indent-bars--main-color=20style=20nil=20nil=20blend))))))))=0A=0A= (defun=20indent-bars--get-color=20(style=20depth=20=20&optional=20= current-highlight)=0A=20=20"Return=20the=20color=20appropriate=20for=20= indentation=20DEPTH=20in=20STYLE.=0AIf=20CURRENT-HIGHLIGHT=20is=20= non-nil,=20return=20the=20appropriate=20highlight=0Acolor,=20if=20setup=20= (see=20`indent-bars-highlight-current-depth')."=0A=20=20(let*=20= ((palette=20(or=20(and=20current-highlight=0A=09=09=09=20=20=20= (ibs/current-depth-palette=20style))=0A=09=09=20=20=20=20=20=20= (ibs/depth-palette=20style))))=0A=20=20=20=20(cond=0A=20=20=20=20=20= ((vectorp=20palette)=0A=20=20=20=20=20=20(aref=20palette=20(mod=20(1-=20= depth)=20(length=20palette))))=0A=20=20=20=20=20(palette)=20=20;=20= single=20color=0A=20=20=20=20=20(t=20(ibs/main-color=20style)))))=0A=0A= ;;;;;=20Faces=0A(defun=20indent-bars--stipple-face-spec=20(w=20h=20rot=20= &optional=20style=20stipple)=0A=20=20"Create=20a=20face=20specification=20= for=20the=20stipple=20face=20for=20STYLE.=0ACreate=20for=20character=20= size=20W=20x=20H=20with=20offset=20ROT.=20=20If=20STIPPLE=20is=0A= non-nil,=20use=20it=20instead=20of=20calculating.=20=20Includes=0A= :weight=20(affecting=20only=20non-stipple=20character=20display)=20if=0A= `indent-bars-no-stipple-char-font-weight'=20(or=20equivalent=20for=20the=0A= STYLE)=20is=20non-nil."=0A=20=20(let=20((stipple=20(or=20stipple=20= (indent-bars--stipple=20w=20h=20rot=20style)))=0A=09(wt=20= (indent-bars--style=20style=20"no-stipple-char-font-weight")))=0A=20=20=20= =20`((t=20(=20:inherit=20nil=0A=09=20=20=20,@(and=20stipple=20`(:stipple=20= ,stipple))=0A=09=20=20=20,@(and=20wt=20`(:weight=20,wt)))))))=0A=0A= (defun=20indent-bars--calculate-face-spec=20(style=20depth)=0A=20=20= "Calculate=20the=20face=20spec=20for=20bar=20at=20DEPTH=20in=20STYLE.=0A= DEPTH=20starts=20at=201."=0A=20=20`((t=20.=20(=20:inherit=20= ,(ibs/stipple-face=20style)=0A=09=20=20=20:foreground=20= ,(indent-bars--get-color=20style=20depth)))))=0A=0A(defun=20= indent-bars--create-faces=20(style=20num=20&optional=20redefine)=0A=20=20= "Create=20bar=20faces=20up=20to=20depth=20NUM=20for=20STYLE.=0ARedefine=20= them=20if=20REDEFINE=20is=20non-nil."=0A=20=20(vconcat=0A=20=20=20= (cl-loop=0A=20=20=20=20for=20i=20from=201=20to=20num=0A=20=20=20=20for=20= face=20=3D=20(indent-bars--tag=20"indent-bars%s-%d"=20style=20i)=20do=0A=20= =20=20=20(if=20(and=20redefine=20(facep=20face))=20(face-spec-reset-face=20= face))=0A=20=20=20=20(face-spec-set=20face=20= (indent-bars--calculate-face-spec=20style=20i))=0A=20=20=20=20collect=20= face)))=0A=0A(defsubst=20indent-bars--face=20(style=20depth)=0A=20=20= "Return=20the=20bar=20face=20for=20bar=20DEPTH=20in=20STYLE.=0AThe=20= face=20is=20created=20if=20necessary."=0A=20=20(when=20(>=20depth=20= (length=20(ibs/faces=20style)))=0A=20=20=20=20(setf=20(ibs/faces=20= style)=0A=09=20=20(indent-bars--create-faces=20style=20depth)))=0A=20=20= (aref=20(ibs/faces=20style)=20(1-=20depth)))=0A=0A;;;;;=20No=20stipple=20= characters=20(e.g.=20terminal)=0A(defun=20indent-bars--no-stipple-char=20= (style=20depth)=0A=20=20"Return=20the=20no-stipple=20bar=20character=20= for=20DEPTH=20in=20STYLE."=0A=20=20(when=20(>=20depth=20(length=20= (ibs/no-stipple-chars=20style)))=0A=20=20=20=20(setf=20= (ibs/no-stipple-chars=20style)=0A=09=20=20= (indent-bars--create-no-stipple-chars=20style=20depth)))=0A=20=20(aref=20= (ibs/no-stipple-chars=20style)=20(1-=20depth)))=0A=0A(defun=20= indent-bars--create-no-stipple-chars=20(style=20num)=0A=20=20"Setup=20= bar=20characters=20for=20bar=20faces=20up=20to=20depth=20NUM=20in=20= STYLE.=0AUsed=20when=20not=20using=20stipple=20display=20(on=20terminal,=20= or=20by=20request;=0Asee=20`indent-bars-prefer-character')."=0A=20=20= (vconcat=0A=20=20=20(nreverse=0A=20=20=20=20(cl-loop=0A=20=20=20=20=20= with=20chars=20=3D=20(ibs/no-stipple-chars=20style)=0A=20=20=20=20=20= with=20l=20=3D=20(length=20chars)=0A=20=20=20=20=20for=20d=20from=20num=20= downto=201=0A=20=20=20=20=20collect=0A=20=20=20=20=20(or=20(and=20(<=20d=20= l)=20(aref=20chars=20(1-=20d)))=0A=09=20(propertize=20(string=20= indent-bars-no-stipple-char)=0A=09=09=20=20=20=20=20'face=20= (indent-bars--face=20style=20d)))))))=0A=0A;;;;;=20Alternate=20Style=20= Support=0A(defmacro=20indent-bars--alt-custom=0A=20=20=20=20(alt=20opt=20= alt-description=20std-val=20&optional=20add-inherit=20no-inherit=20&rest=20= r)=0A=20=20"Define=20a=20custom=20ALT=20variable=20for=20option=20OPT.=0A= The=20new=20custom=20options=20default=20value=20is=20set=20to=20= STD-VAL.=20=20This=0Acreates=20a=20new=20variable=20indent-bars-alt-opt,=20= based=20on=0Aindent-bars-opt=20(referred=20to=20as=20the=20parent=20= variable).=0AALT-DESCRIPTION=20will=20be=20used=20to=20identify=20the=20= alternate=20variable=0Ain=20the=20customize=20interface.=0A=0AIf=20= ADD-INHERIT=20is=20non-nil,=20expand=20the=20type=20to=20a=20cons:=0A=0A=20= =20(inherit=20.=20type)=0A=0Awhere=20INHERIT=20is=20either=20`inherit'=20= or=20`no-inherit',=20depending=0Aon=20the=20value=20of=20NO-INHERIT.=0A=0A= Additional=20`defcustom`=20keyword=20arguments=20can=20be=20given=20as=20= R."=0A=20=20(require=20'cus-edit)=0A=20=20(let*=20((optname=20= (symbol-name=20opt))=0A=09=20(group=20(intern=20(concat=20"indent-bars-"=20= alt=20"-style")))=0A=09=20(symname=20(concat=20"indent-bars-"=20= optname))=0A=09=20(sym=20(intern=20(concat=20"indent-bars-"=20optname)))=0A= =09=20(tsym=20(intern=20(concat=20"indent-bars-"=20alt=20"-"=20= optname)))=0A=09=20(type=20(custom-variable-type=20sym))=0A=09=20(choice=20= (cond=20((eq=20(car=20type)=20'choice)=20type)=0A=09=09=20=20=20=20=20=20= =20((eq=20(car=20type)=20'list)=0A=09=09=09(seq-find=0A=09=09=09=20= (lambda=20(el)=20(and=20(consp=20el)=20(eq=20(car=20el)=20'choice)))=0A=09= =09=09=20type))=0A=09=09=20=20=20=20=20=20=20(t=20(setq=20type=20= `(choice=20,type))))))=0A=20=20=20=20;;=20Add=20an=20unspecified=20= choice=0A=20=20=20=20(when-let=20((tag-pos=20(member=20:tag=20choice)))=0A= =20=20=20=20=20=20(setq=20choice=20(cdr=20tag-pos)))=09;after=20tag=0A=20= =20=20=20(setcdr=20choice=0A=09=20=20=20=20(push=0A=09=20=20=20=20=20= `(const=20:tag=20,(concat=20"No-value=20(use=20parent=20"=20optname=20= ")")=20unspecified)=0A=09=20=20=20=20=20(cdr=20choice)))=0A=0A=20=20=20=20= ;;=20Add=20leading=20inherit=20flag,=20if=20needed=0A=20=20=20=20(when=20= (or=20no-inherit=20add-inherit)=0A=20=20=20=20=20=20(setq=20type=0A=09=20= =20=20=20`(cons=20:tag=20,(concat=20alt-description=20"=20Style")=0A=09=09= =20=20=20(choice=20:tag=0A=09=09=09=20=20=20,(concat=20"Inherit=20= missing=20data=20from=20`indent-bars-"=0A=09=09=09=09=20=20=20=20optname=20= "'")=0A=09=09=09=20=20=20(const=20:tag=20"Do=20not=20inherit"=20= no-inherit)=0A=09=09=09=20=20=20(const=20:tag=20"Inherit"=20inherit))=0A=09= =09=20=20=20,type)=0A=09=20=20=20=20std-val=20`(=20,(if=20no-inherit=20= 'no-inherit=20'inherit)=20.=20,std-val=20)))=0A=20=20=20=20`(defcustom=20= ,tsym=20',std-val=0A=20=20=20=20=20=20=20,(concat=20"Alternate=20"=20= alt-description=20"=20version=20of=20`"=20symname=20"'.")=0A=20=20=20=20=20= =20=20:type=20',type=0A=20=20=20=20=20=20=20:link=20'(variable-link=20= ,sym)=0A=20=20=20=20=20=20=20:set=20#'indent-bars--custom-set=0A=20=20=20= =20=20=20=20:group=20',group=0A=20=20=20=20=20=20=20,@r)))=0A=0A= (defsubst=20indent-bars--alt=20(name=20alt)=0A=20=20"Find=20the=20symbol=20= value=20of=20NAME,=20with=20alternate=20style=20ALT.=0ANAME=20is=20a=20= string,=20and=20ALT=20and=20be=20a=20string=20or=20nil."=0A=20=20(intern=20= (format=20"indent-bars%s-%s"=0A=09=09=20=20(if=20alt=20(concat=20"-"=20= alt)=20"")=20name)))=0A=0A(defun=20indent-bars--style1=20(style=20name)=0A= =20=20"Return=20the=20value=20of=20style=20variable=20NAME=20for=20= STYLE.=0AConsiders=20([no-]inherit=20.=20rest)=20inheritance."=0A=20=20= (let*=20((tag=20(ibs/tag=20style))=0A=09=20(sym=20(indent-bars--alt=20= name=20tag))=0A=09=20(val=20(symbol-value=20sym))=0A=09=20(inhrt=20t))=20= =20;=20inherit=20by=20default=0A=20=20=20=20(when=20tag=0A=20=20=20=20=20= =20;;=20Check=20for=20the=20([no-]inherit=20.=20actual-val)=20form=0A=20=20= =20=20=20=20(when=20(and=20(consp=20val)=20(memq=20(car=20val)=20= '(inherit=20no-inherit)))=0A=09(setq=20inhrt=20(and=20(car=20val)=20(not=20= (eq=20(car=20val)=20'no-inherit)))=0A=09=20=20=20=20=20=20val=20(cdr=20= val)))=0A=20=20=20=20=20=20(when=20inhrt=0A=09(setq=20val=20= (indent-bars--custom-inherit=0A=09=09=20=20=20(symbol-value=20= (indent-bars--alt=20name=20nil))=20val))))=0A=20=20=20=20val))=0A=0A= (defun=20indent-bars--style=20(style=20name)=0A=20=20"Return=20the=20= value=20of=20style=20variable=20NAME=20for=20STYLE.=0ADetermines=20= variables=20to=20use=20based=20on=20the=20style=20tag.=20=20For=20style=0A= variable=20values=20of=20the=20form=20(`inherit'|`no-inherit'=20.=20= plist),=0Ainheritance=20of=20the=20plist=20is=20handled.=20=20If=20style=20= is=20the=20symbol=0A`any',=20return=20the=20first=20non-nil=20value=20= for=20all=20styles=20in=0A`indent-bars--styles'."=0A=20=20(if=20(eq=20= style=20'any)=0A=20=20=20=20=20=20(cl-some=20(lambda=20(s)=20= (indent-bars--style1=20s=20name))=0A=09=20=20=20=20=20=20=20= indent-bars--styles)=0A=20=20=20=20(indent-bars--style1=20style=20= name)))=0A=0A(defun=20indent-bars--custom-inherit=20(old=20new)=0A=20=20= "Inherit=20the=20values=20of=20NEW=20and=20OLD,=20which=20can=20be=20= values=20or=20lists.=0ANEW=20and=20OLD=20must=20have=20the=20same=20= form,=20composed=20of=20atoms=0Aand=20(optionally)=20a=20final=20plist.=20= =20The=20symbol=20`unspecified'=20in=0ANEW=20indicates=20that=20that=20= value=20should=20be=20replaced=20by=20the=0Acorresponding=20value=20in=20= OLD.=20=20Any=20trailing=20PLIST=20in=20NEW=20and=20OLD=0Awill=20be=20= merged=20(with=20NEW=20taking=20precedence).=20=20The=20merged=20value=20= is=0Areturned."=0A=20=20(cond=0A=20=20=20((and=20old=20(eq=20new=20= 'unspecified))=0A=20=20=20=20old)=20=09;=20fully=20inherited=0A=20=20=20=0A= =20=20=20((and=20(atom=20old)=20(atom=20new))=0A=20=20=20=20(if=20(eq=20= new=20'unspecified)=20old=20new))=0A=20=20=20=0A=20=20=20((and=20(consp=20= old)=20(consp=20new))=0A=20=20=20=20(let*=20((old=20(copy-sequence=20= old))=20=09;=20avoid=20editing=20old=0A=09=20=20=20(n=20new)=20(o=20old)=20= last-o)=0A=20=20=20=20=20=20(while=20(and=20n=20o)=0A=09(if=20(and=20= (plistp=20n)=20(plistp=20o)=20(keywordp=20(car=20o)))=0A=09=20=20=20=20= (let=20((m=20(map-merge=20'plist=20o=20n)))=0A=09=20=20=20=20=20=20(if=20= last-o=20(setcdr=20last-o=20m)=20(setq=20old=20m))=0A=09=20=20=20=20=20=20= (setq=20o=20nil))=09=09;=20signify=20list=20complete=0A=09=20=20(unless=20= (eq=20(car=20n)=20'unspecified)=0A=09=20=20=20=20(setcar=20o=20(car=20= n))))=0A=09(setq=20last-o=20o=20n=20(cdr=20n)=20o=20(cdr=20o)))=0A=20=20=20= =20=20=20old))=0A=0A=20=20=20(t=20new)))=0A=0A(defun=20= indent-bars-reset-styles=20(&rest=20_r)=0A=20=20"Reset=20all=20styles'=20= colors=20and=20faces.=0AUseful=20for=20calling=20after=20theme=20= changes."=0A=20=20(interactive)=0A=20=20(dolist=20(s=20= indent-bars--styles)=0A=20=20=20=20(indent-bars--initialize-style=20s)))=0A= =0A(defun=20indent-bars--initialize-style=20(style)=0A=20=20"Initialize=20= STYLE."=0A=20=20;;=20Colors=0A=20=20(setf=20(ibs/main-color=20style)=0A=09= (indent-bars--main-color=20style)=0A=09(ibs/depth-palette=20style)=0A=09= (indent-bars--depth-palette=20style)=0A=09(ibs/current-depth-palette=20= style)=0A=09(indent-bars--current-depth-palette=20style)=0A=09(ibs/faces=20= style)=20(indent-bars--create-faces=20style=207=20'reset)=0A=09= (ibs/no-stipple-chars=20style)=20(indent-bars--create-no-stipple-chars=20= style=207))=0A=20=20=0A=20=20;;=20Base=20stipple=20face=0A=20=20= (face-spec-set=0A=20=20=20(ibs/stipple-face=20style)=0A=20=20=20= (indent-bars--stipple-face-spec=0A=20=20=20=20(frame-char-width)=20= (frame-char-height)=0A=20=20=20=20(indent-bars--stipple-rot=20= (selected-window)=20(frame-char-width))=0A=20=20=20=20style))=0A=20=20=0A= =20=20;;=20Current=20depth=20highlight=20faces/stipple=0A=20=20(setf=20= (ibs/current-bg-color=20style)=0A=09(indent-bars--current-bg-color=20= style))=0A=20=20(when-let=20((stipple=20= (indent-bars--current-depth-stipple=20nil=20nil=20nil=20style)))=0A=20=20= =20=20(setf=20(ibs/current-stipple-face=20style)=0A=09=20=20= (indent-bars--tag=20"indent-bars%s-current-face"=20style))=0A=20=20=20=20= (face-spec-set=20(ibs/current-stipple-face=20style)=20nil)))=0A=0A;;;;=20= Indentation=20and=20Drawing=0A(defvar-local=20indent-bars-spacing=20nil)=0A= (defvar-local=20indent-bars--offset=20nil)=0A(defvar-local=20= indent-bars--no-stipple=20nil)=0A=0A(defsubst=20indent-bars--depth=20= (len)=0A=20=20"Number=20of=20possible=20bars=20for=20initial=20blank=20= string=20of=20length=20LEN.=0ANote=20that=20the=20first=20bar=20is=20= expected=20at=20`indent-bars-starting-column'."=0A=20=20(if=20(>=20len=20= indent-bars--offset)=0A=20=20=20=20=20=20(1+=20(/=20(-=20len=20= indent-bars--offset=201)=20indent-bars-spacing))=0A=20=20=20=200))=0A=0A= (defun=20indent-bars--context-depth=20()=0A=20=20"Return=20the=20maximum=20= `current-indentation'=20around=20current=20line.=0ASkips=20any=20fully=20= blank=20lines."=0A=20=20(let=20(b=20(p=20(point)))=0A=20=20=20=20= (beginning-of-line)=0A=20=20=20=20(skip-chars-backward=20"[:space:]\n")=0A= =20=20=20=20(setq=20b=20(current-indentation))=0A=20=20=20=20(goto-char=20= p)=0A=20=20=20=20(forward-line=201)=0A=20=20=20=20(skip-chars-forward=20= "[:space:]\n")=0A=20=20=20=20(prog1=0A=09(max=20(current-indentation)=20= b)=0A=20=20=20=20=20=20(goto-char=20p))))=0A=0A(defvar=20= indent-bars--update-depth-function=20nil)=0A(defvar=20indent-bars--ppss=20= nil)=0A(defun=20indent-bars--current-indentation-depth=20(&optional=20= on-bar)=0A=20=20"Calculate=20current=20indentation=20depth.=0AIf=20= ON-BAR=20is=20nil,=20return=20the=20depth=20of=20the=20last=20visible=20= bar=20on=20the=0Aline.=20=20If=20ON-BAR=20is=20non-nil=20and=20content=20= begins=20at=20a=20column=20where=0Aa=20bar=20would=20otherwise=20have=20= fallen,=20report=20the=20depth=20of=0Athat=20(undrawn)=20bar.=20=20If=20= ON-BAR=20is=20the=20symbol=20`context',=20and=20the=0Afirst=20non-blank=20= line=20immediately=20above=20or=20below=20the=20current=20line=0Ais=20= not=20at=20a=20deeper=20indentation=20level=20(by=20at=20least=20one=20= bar=0Aspacing),=20disable=20on-bar=20and=20use=20the=20last-visible-bar=20= depth=20for=0Athat=20line=20instead.=0A=0AIf=20= `indent-bars-no-descend-string'=20is=20non-nil=20and=20point=20at=20line=0A= beginning=20is=20inside=20a=20string,=20do=20not=20add=20bars=20deeper=20= than=20one=0Amore=20than=20the=20string's=20start.=20=20If=20= `indent-bars-no-descend-lists'=0Ais=20non-nil,=20perform=20the=20same=20= check=20for=20lists.=0A=0AIf=20`indent-bars--update-depth-function'=20is=20= non-nil,=20it=20will=20be=0Acalled=20with=20the=20indentation=20depth=20= (prior=20to=20the=20ON-BAR=20check),=0Aand=20can=20return=20an=20updated=20= depth."=0A=20=20(let*=20((c=20(current-indentation))=0A=09=20(d=20= (indent-bars--depth=20c))=20=09;last=20visible=20bar=0A=09=20ppss-ind)=0A= =20=20=20=20(when=20indent-bars--ppss=0A=20=20=20=20=20=20(let*=20((p=20= (prog1=20(point)=20(forward-line=200)))=0A=09=20=20=20=20=20(ppss=20= (syntax-ppss))=20=09;=20moves=20point!=0A=09=20=20=20=20=20(ss=20(and=20= indent-bars-no-descend-string=20(nth=208=20ppss)))=0A=09=20=20=20=20=20= (sl=20(and=20indent-bars-no-descend-lists=20(nth=201=20ppss))))=0A=09= (when=20(setq=20ppss-ind=20(if=20(and=20ss=20sl)=20(max=20ss=20sl)=20(or=20= ss=20sl)))=0A=09=20=20(goto-char=20ppss-ind)=0A=09=20=20(let*=20((cnew=20= (current-indentation))=0A=09=09=20(dnew=20(1+=20(indent-bars--depth=20= cnew))))=0A=09=20=20=20=20(when=20(<=20dnew=20d)=20(setq=20d=20dnew=20c=20= cnew))))=0A=09(goto-char=20p)))=0A=20=20=20=20(when=20(and=20= indent-bars--update-depth-function=20(not=20ppss-ind))=0A=20=20=20=20=20=20= (setq=20d=20(funcall=20indent-bars--update-depth-function=20d)))=0A=20=20= =20=20(when=20(and=20(eq=20on-bar=20'context)=0A=09=20=20=20=20=20=20=20= (<=20(indent-bars--context-depth)=20(+=20c=20indent-bars-spacing)))=0A=20= =20=20=20=20=20(setq=20on-bar=20nil))=0A=20=20=20=20(if=20(and=20on-bar=20= (=3D=20c=20(+=20indent-bars--offset=20(*=20d=20indent-bars-spacing))))=0A= =09(1+=20d)=20d)))=0A=0A(defun=20indent-bars--blank-string=20(style=20= off=20nbars=20bar-from=0A=09=09=09=09=09&optional=20width=0A=09=09=09=09=09= switch-after=20style2)=0A=20=20"Return=20a=20blank=20string=20with=20= bars=20displayed,=20using=20style=20STYLE.=0AOFF=20is=20the=20character=20= offset=20within=20the=20string=20to=20draw=20the=20first=0Abar,=20NBARS=20= is=20the=20desired=20number=20of=20bars=20to=20add,=20and=20BAR-FROM=20= is=0Athe=20starting=20index=20of=20the=20first=20bar=20(>=3D1).=20=20= WIDTH=20is=20the=20total=0Astring=20width=20to=20return,=20right=20= padding=20with=20space=20if=20needed.=0A=0AIf=20SWITCH-AFTER=20is=20= supplied=20and=20is=20an=20integer,=20switch=20from=20STYLE=0Ato=20= STYLE2=20after=20drawing=20that=20many=20bars.=20=20If=20it=20is=20t,=20= use=0ASTYLE2=20for=20all=20bars.=0A=0ABars=20are=20displayed=20using=20= stipple=20properties=20or=20characters;=20see=0A= `indent-bars-prefer-character'."=0A=20=20(concat=20(make-string=20off=20= ?\s)=0A=09=20=20(string-join=0A=09=20=20=20(cl-loop=0A=09=20=20=20=20for=20= i=20from=200=20to=20(1-=20nbars)=0A=09=20=20=20=20for=20depth=20=3D=20(+=20= bar-from=20i)=0A=09=20=20=20=20for=20sty=20=3D=20(if=20switch-after=0A=09= =09=09=20=20(if=20(or=20(eq=20switch-after=20t)=0A=09=09=09=09=20=20(>=3D=20= i=20switch-after))=0A=09=09=09=20=20=20=20=20=20style2=0A=09=09=09=20=20=20= =20style)=0A=09=09=09style)=0A=09=20=20=20=20collect=20(if=20= indent-bars--no-stipple=0A=09=09=09(indent-bars--no-stipple-char=20sty=20= depth)=0A=09=09=20=20=20=20=20=20(propertize=20"=20"=20'face=20= (indent-bars--face=20sty=20depth))))=0A=09=20=20=20(make-string=20(1-=20= indent-bars-spacing)=20?\s))=0A=09=20=20(if=20width=0A=09=20=20=20=20=20=20= (make-string=20(-=20width=0A=09=09=09=20=20=20=20=20=20(+=20off=20nbars=20= (*=20(1-=20nbars)=20(1-=20indent-bars-spacing))))=0A=09=09=09=20=20=20= ?\s))))=0A=0A(defun=20indent-bars--tab-display=20(style=20p=20off=20= bar-from=20max=20&rest=20r)=0A=20=20"Display=20up=20to=20MAX=20bars=20on=20= the=20tab=20at=20P,=20offseting=20them=20by=20OFF.=0ABars=20are=20spaced=20= by=20`indent-bars-spacing'=20and=20displayed=20with=20style=0ASTYLE.=20=20= BAR-FROM=20is=20the=20bar=20number=20for=20the=20first=20bar.=20=20Other=0A= arguments=20R=20are=20passed=20to=20`indent-bars--blank-string'.=20=20= Returns=0Athe=20number=20of=20bars=20actually=20displayed."=0A=20=20= (let*=20((nb=20(min=20max=20(/=20(-=20tab-width=20off=20-1)=20= indent-bars-spacing)))=0A=09=20(str=20(apply=20= #'indent-bars--blank-string=20style=20off=20nb=0A=09=09=20=20=20=20=20= bar-from=20tab-width=20r)))=0A=20=20=20=20(put-text-property=20p=20(+=20= p=201)=20'display=20str)=0A=20=20=20=20nb))=0A=0A(defun=20= indent-bars--draw-line=20(style=20nbars=20start=20end=20&optional=0A=09=09= =09=09=20=20=20=20=20invent=20switch-after=20style2)=0A=20=20"Draw=20= NBARS=20bars=20on=20the=20line=20between=20positions=20START=20and=20= END.=0ABars=20are=20drawn=20in=20style=20STYLE,=20`indent-bars-style'=20= by=20default=0ASTART=20is=20assumed=20to=20be=20on=20a=20line=20= beginning=20position.=20=20Drawing=0Astarts=20at=20a=20column=20= determined=20by=20`indent-bars-starting-column'.=0ATabs=20at=20the=20= line=20beginning=20have=20appropriate=20display=20properties=0Aapplied=20= if=20`indent-tabs-mode'=20is=20enabled.=0A=0AIf=20SWITCH-AFTER=20is=20an=20= integer,=20switch=20from=20STYLE=20to=20STYLE2=0Aafter=20drawing=20that=20= many=20bars.=20=20If=20it=20is=20t,=20use=20STYLE2=0Aexclusively.=0A=0A= If=20INVENT=20is=20non-nil=20and=20the=20line's=20length=20is=20= insufficient=20to=0Adisplay=20all=20NBARS=20bars=20(whether=20by=20= replacing=20tabs=20or=20adding=0Aproperties=20to=20existing=20non-tab=20= whitespace),=20bars=20will=20be=0A\"invented\".=20=20That=20is,=20the=20= line's=20final=20newline,=20which=20is=20(only=0Ain=20this=20case)=20= expected=20to=20be=20located=20at=20END,=20will=20have=20its=0Adisplay=20= properties=20set=20to=20fill=20out=20the=20remaining=20bars,=20if=20any=20= are=0Aneeded."=0A=20=20(let*=20((tabs=20(when=20(and=20indent-tabs-mode=0A= =09=09=09=20=20(save-excursion=0A=09=09=09=20=20=20=20(goto-char=20= start)=20(looking-at=20"^\t+")))=0A=09=09=20(-=20(match-end=200)=20= (match-beginning=200))))=0A=09=20(vp=20indent-bars--offset)=0A=09=20= (style=20(or=20style=20indent-bars-style))=0A=09=20(bar=201)=20prop=20= fun=20tnum=20bars-drawn)=0A=20=20=20=20(when=20tabs=09=09=09=09;=20deal=20= with=20initial=20tabs=0A=20=20=20=20=20=20(while=20(and=20(<=3D=20bar=20= nbars)=20(<=20(setq=20tnum=20(/=20vp=20tab-width))=20tabs))=0A=09(setq=20= bars-drawn=0A=09=20=20=20=20=20=20(indent-bars--tab-display=20style=20(+=20= start=20tnum)=20(mod=20vp=20tab-width)=0A=09=09=09=09=09bar=20(-=20nbars=20= bar=20-1)=0A=09=09=09=09=09switch-after=20style2))=0A=09(when=20= (integerp=20switch-after)=0A=09=20=20(cl-decf=20switch-after=20= bars-drawn)=0A=09=20=20(if=20(<=3D=20switch-after=200)=20(setq=20= switch-after=20t)))=20;=20switch=20the=20rest=0A=09(cl-incf=20bar=20= bars-drawn)=0A=09(cl-incf=20vp=20(*=20bars-drawn=20= indent-bars-spacing)))=0A=20=20=20=20=20=20(cl-incf=20start=20(+=20(mod=20= vp=20tab-width)=20(/=20vp=20tab-width))))=0A=20=20=20=20(when=20(<=3D=20= bar=20nbars)=09=09;=20still=20bars=20to=20show=0A=20=20=20=20=20=20(if=20= indent-bars--no-stipple=0A=09=20=20(setq=20prop=20'display=20fun=20= #'indent-bars--no-stipple-char)=0A=09(setq=20prop=20'face=20fun=20= #'indent-bars--face))=0A=20=20=20=20=20=20(let=20((pos=20(if=20tabs=20= start=20(+=20start=20indent-bars--offset))))=0A=09(while=20(and=20(<=3D=20= bar=20nbars)=20(<=20pos=20end))=0A=09=20=20(put-text-property=20pos=20= (1+=20pos)=0A=09=09=09=20=20=20=20=20prop=20(funcall=20fun=0A=09=09=09=09= =09=20=20=20(cond=20((integerp=20switch-after)=0A=09=09=09=09=09=09=20=20= (prog1=0A=09=09=09=09=09=09=20=20=20=20=20=20(if=20(>=20switch-after=20= 0)=20style=20style2)=0A=09=09=09=09=09=09=20=20=20=20(cl-decf=20= switch-after)=0A=09=09=09=09=09=09=20=20=20=20(if=20(<=3D=20switch-after=20= 0)=0A=09=09=09=09=09=09=09(setq=20switch-after=20t))))=0A=09=09=09=09=09=09= =20((eq=20switch-after=20t)=20style2)=0A=09=09=09=09=09=09=20(t=20= style))=0A=09=09=09=09=09=20=20=20bar))=0A=09=20=20(cl-incf=20bar)=0A=09=20= =20(cl-incf=20pos=20indent-bars-spacing))=0A=09;;=20STILL=20bars=20to=20= show:=20invent=20them=20(if=20requested)=0A=09(if=20(and=20invent=20(<=3D=20= bar=20nbars))=0A=09=20=20=20=20(put-text-property=0A=09=20=20=20=20=20= end=20(1+=20end)=20'display=0A=09=20=20=20=20=20(concat=20= (indent-bars--blank-string=0A=09=09=20=20=20=20=20=20style=20(-=20pos=20= end)=20(-=20nbars=20bar=20-1)=20bar=20nil=0A=09=09=20=20=20=20=20=20= switch-after=20style2)=0A=09=09=20=20=20=20=20"\n")))))))=0A=0A;;;;=20= Font=20Lock=0A(defvar-local=20indent-bars--font-lock-keywords=20nil)=0A= (defvar=20indent-bars--font-lock-blank-line-keywords=20nil)=0A=0A(defvar=20= indent-bars-orig-unfontify-region=20nil)=0A(defun=20= indent-bars--unfontify=20(beg=20end)=0A=20=20"Unfontify=20region=20= between=20BEG=20and=20END.=0ARemoves=20the=20display=20properties=20in=20= addition=20to=20the=20normal=20managed=0Afont-lock=20properties."=0A=20=20= (let=20((font-lock-extra-managed-props=0A=20=20=20=20=20=20=20=20=20= (append=20'(display)=20font-lock-extra-managed-props)))=0A=20=20=20=20= (funcall=20indent-bars-orig-unfontify-region=20beg=20end)))=0A=0A(defun=20= indent-bars--display=20(beg=20end=20&optional=20style=20switch-after=20= style2)=0A=20=20"Draw=20indentation=20bars=20from=20BEG..END,=20based=20= on=20line=20contents.=0ABEG=20and=20END=20should=20be=20on=20the=20same=20= line.=20=20STYLE,=20SWITCH-AFTER=20and=0ASTYLE2=20are=20as=20in=20= `indent-bars--draw-line'.=20=20If=20STYLE=20is=20not=0Apassed,=20uses=20= `indent-bars-style'=20for=20drawing."=0A=20=20(let=20((n=20= (save-excursion=0A=09=20=20=20=20=20(goto-char=20beg)=0A=09=20=20=20=20=20= (indent-bars--current-indentation-depth))))=0A=20=20=20=20(when=20(>=20n=20= 0)=20(indent-bars--draw-line=20style=20n=20beg=20end=20nil=0A=09=09=09=09= =09=20=20switch-after=20style2))))=0A=0A(defsubst=20= indent-bars--context-bars=20(end)=0A=20=20"Maximum=20number=20of=20bars=20= at=20point=20and=20END.=0AMoves=20point."=0A=20=20(max=20= (indent-bars--current-indentation-depth)=0A=20=20=20=20=20=20=20(progn=0A= =09=20(goto-char=20(1+=20end))=09=09;=20end=20is=20always=20eol=0A=09=20= (indent-bars--current-indentation-depth))))=0A=0A(defun=20= indent-bars--handle-blank-lines=20(beg=20end=20&optional=20style=20= switch-after=20style2)=0A=20=20"Display=20the=20appropriate=20bars=20= over=20the=20blank-only=20lines=20from=20BEG..END.=0AOnly=20called=20if=20= `indent-bars-display-on-blank-lines'=20is=20non-nil.=0ATo=20be=20called=20= on=20complete=20multi-line=20blank=20line=20regions.=0A=0AIt=20is=20= ambigious=20how=20many=20bars=20to=20draw=20on=20each=20line=20in=20a=20= stretch=0Aof=20blank=20lines,=20so=20this=20uses=20the=20maximum=20depth=20= of=20the=20surrounding=0Aline=20indentation,=20above=20and=20below.=20=20= Drawing=20using=0A`indent-bars--draw-line'.=20=20STYLE,=20SWITCH-AFTER=20= and=20STYLE2=20are=20as=0Ain=20`indent-bars--draw-line'.=0A=0ANote:=20= blank=20lines=20at=20the=20very=20beginning=20or=20end=20of=20the=20= buffer=20are=0Anot=20indicated,=20even=20if=20they=20otherwise=20would=20= be.=20=20This=20function=20is=0Aconfigured=20by=20default=20in=20= `indent-bars--handle-blank-lines-form'."=0A=20=20(let=20((pm=20= (point-max))=20ctxbars)=0A=20=20=20=20(save-excursion=0A=20=20=20=20=20=20= (goto-char=20(1-=20beg))=0A=20=20=20=20=20=20(beginning-of-line=201)=0A=20= =20=20=20=20=20(when=20(>=20(setq=20ctxbars=20(indent-bars--context-bars=20= end))=200)=0A=09(goto-char=20beg)=0A=09(while=20(<=20(point)=20end)=20= ;note:=20end=20extends=201=20char=20beyond=20blank=20line=20range=0A=09=20= =20(let*=20((bp=20(line-beginning-position))=0A=09=09=20(ep=20= (line-end-position)))=0A=09=20=20=20=20(unless=20(=3D=20ep=20pm)=0A=09=20= =20=20=20=20=20(indent-bars--draw-line=20style=20ctxbars=20bp=20ep=20= 'invent=0A=09=09=09=09=20=20=20=20=20=20switch-after=20style2))=0A=09=20=20= =20=20(beginning-of-line=202)))))=0A=20=20=20=20nil))=0A=0A(defvar=20= font-lock-beg)=20(defvar=20font-lock-end)=20;=20Dynamic=20font-lock=20= variables!=0A(defun=20indent-bars--extend-blank-line-regions=20()=0A=20=20= "Extend=20the=20region=20about=20to=20be=20font-locked=20to=20include=20= stretches=20of=20blank=20lines."=0A=20=20;;=20(message=20"request=20to=20= extend:=20%d->%d"=20font-lock-beg=20font-lock-end)=0A=20=20(let=20= ((changed=20nil)=20(chars=20"=20\t\n"))=0A=20=20=20=20(goto-char=20= font-lock-beg)=0A=20=20=20=20(when=20(<=20(skip-chars-backward=20chars)=20= 0)=0A=20=20=20=20=20=20(unless=20(bolp)=20(beginning-of-line=202))=20;=20= spaces=20at=20end=20don't=20count=0A=20=20=20=20=20=20(when=20(<=20= (point)=20font-lock-beg)=0A=09(setq=20changed=20t=20font-lock-beg=20= (point))))=0A=20=20=20=20(goto-char=20font-lock-end)=0A=20=20=20=20(when=20= (>=20(skip-chars-forward=20chars)=200)=0A=20=20=20=20=20=20(unless=20= (bolp)=20(beginning-of-line=201))=0A=20=20=20=20=20=20(when=20(>=20= (point)=20font-lock-end)=0A=09(setq=20changed=20t=20font-lock-end=20= (point))))=0A=20=20=20=20;;=20(if=20changed=20(message=20"expanded=20to=20= %d->%d"=20font-lock-beg=20font-lock-end))=0A=20=20=20=20changed))=0A=0A= ;;;;=20Current=20indentation=20depth=20highlighting=0A(defvar-local=20= indent-bars--current-depth=200)=0A(defvar-local=20indent-bars--remaps=20= nil=0A=20=20"An=20alist=20of=20active=20face-remap=20cookies=20for=20= faces.=0AKeyed=20by=20style=20tag=20(nil=20for=20the=20main=20style).=20=20= These=20remaps=20are=0Aused=20to=20change=20the=20current=20depth=20= highlight=20(aside=20from=20stipple=20changes).")=0A=0A(defun=20= indent-bars--current-bg-color=20(style)=0A=20=20"Return=20the=20current=20= bar=20background=20color=20appropriate=20for=20STYLE."=0A=20=20(when-let=20= ((hcd=0A=09=20=20=20=20=20=20(indent-bars--style=20style=20= "highlight-current-depth")))=0A=20=20=20=20(plist-get=20hcd=20= :background)))=0A=0A(defun=20indent-bars--current-depth-stipple=20= (&optional=20w=20h=20rot=20style)=0A=20=20"Return=20the=20current=20= depth=20stipple=20highlight=20(if=20any)=20for=20STYLE.=0AOne=20of=20the=20= keywords=20:width,=20:pad,=20:pattern,=20or=20:zigzag=20must=20be=0Aset=20= in=20`indent-bars-highlight-current-depth'=20config.=20=20W,=20H,=20and=0A= ROT=20are=20as=20in=20`indent-bars--stipple',=20and=20have=20similar=20= default=20values."=0A=20=20(cl-destructuring-bind=20(&key=20width=20pad=20= pattern=20zigzag=20&allow-other-keys)=0A=20=20=20=20=20=20= (indent-bars--style=20style=20"highlight-current-depth")=0A=20=20=20=20= (when=20(or=20width=20pad=20pattern=20zigzag)=0A=20=20=20=20=20=20(let*=20= ((w=20(or=20w=20(window-font-width)))=0A=09=20=20=20=20=20(h=20(or=20h=20= (window-font-height)))=0A=09=20=20=20=20=20(rot=20(or=20rot=20= (indent-bars--stipple-rot=20nil=20w))))=0A=09(indent-bars--stipple=20w=20= h=20rot=20style=20width=20pad=20pattern=20zigzag)))))=0A=0A(defvar-local=20= indent-bars--highlight-timer=20nil)=0A(defun=20= indent-bars--update-current-depth-highlight=20(depth)=0A=20=20"Update=20= highlight=20for=20the=20current=20DEPTH.=0AWorks=20by=20remapping=20the=20= appropriate=20indent-bars[-tag]-N=20face=20for=0Aall=20styles=20in=20the=20= `indent-bars--styles'=20list.=20=20DEPTH=20should=20be=0Agreater=20than=20= zero."=0A=20=20(setq=20indent-bars--highlight-timer=20nil)=0A=20=20= (dolist=20(s=20indent-bars--styles)=0A=20=20=20=20(let*=20((face=20= (indent-bars--face=20s=20depth))=0A=09=20=20=20(hl-col=20(and=20= (ibs/current-depth-palette=20s)=0A=09=09=09(indent-bars--get-color=20s=20= depth=20'highlight)))=0A=09=20=20=20(hl-bg=20(ibs/current-bg-color=20= s)))=0A=20=20=20=20=20=20(when=20(or=20hl-col=20hl-bg=20= (ibs/current-stipple-face=20s))=0A=09(when-let=20((c=20(alist-get=20= (ibs/tag=20s)=20indent-bars--remaps)))=20;=20out=20with=20the=20old=0A=09= =20=20(face-remap-remove-relative=20c))=0A=09(setf=20(alist-get=20= (ibs/tag=20s)=20indent-bars--remaps)=0A=09=20=20=20=20=20=20= (face-remap-add-relative=0A=09=20=20=20=20=20=20=20face=0A=09=20=20=20=20= =20=20=20`(,@(when=20hl-col=20`(:foreground=20,hl-col))=0A=09=09=20= ,@(when=20hl-bg=20`(:background=20,hl-bg)))=0A=09=20=20=20=20=20=20=20= (ibs/current-stipple-face=20s)))))))=0A=0A(defun=20= indent-bars--update-current-depth-highlight-in-buffer=20(buf=20depth)=0A=20= =20"Highlight=20bar=20at=20DEPTH=20in=20buffer=20BUF."=0A=20=20(if=20= (buffer-live-p=20buf)=0A=20=20=20=20=20=20(with-current-buffer=20buf=0A=09= (indent-bars--update-current-depth-highlight=20depth))))=0A=0A(defun=20= indent-bars--highlight-current-depth=20(&optional=20force)=0A=20=20= "Refresh=20current=20indentation=20depth=20highlight.=0ARate=20limit=20= set=20by=20`indent-bars-depth-update-delay'.=20=20If=20FORCE=20is=0A= non-nil,=20update=20depth=20even=20if=20it=20has=20not=20changed."=0A=20=20= (unless=20(or=20indent-bars--highlight-timer=20(not=20indent-bars-mode))=0A= =20=20=20=20(let*=20((depth=20(indent-bars--current-indentation-depth=0A=09= =09=20=20=20indent-bars-highlight-selection-method)))=0A=20=20=20=20=20=20= (when=20(and=20depth=20(or=20force=20(not=20(=3D=20depth=20= indent-bars--current-depth)))=0A=09=09=20(>=20depth=200))=0A=09(setq=20= indent-bars--current-depth=20depth)=0A=09(if=20(zerop=20= indent-bars-depth-update-delay)=0A=09=20=20=20=20= (indent-bars--update-current-depth-highlight=20depth)=0A=09=20=20(setq=20= indent-bars--highlight-timer=0A=09=09(run-with-idle-timer=0A=09=09=20= indent-bars-depth-update-delay=20nil=0A=09=09=20= #'indent-bars--update-current-depth-highlight-in-buffer=0A=09=09=20= (current-buffer)=20depth)))))))=0A=0A;;;;=20Stipple=20Display=0A= (defsubst=20indent-bars--block=20(n)=0A=20=20"Create=20a=20block=20of=20= N=20low-order=201=20bits."=0A=20=20(-=20(ash=201=20n)=201))=0A=0A(defun=20= indent-bars--stipple-rot=20(win=20w)=0A=20=20"Return=20the=20stipple=20= rotation=20for=20window=20WIN=20and=20pattern=20width=20W.=0AWIN=20= defaults=20to=20the=20selected=20window=20if=20nil."=0A=20=20(mod=20(car=20= (window-edges=20win=20t=20nil=20t))=20w))=0A=0A(defun=20indent-bars--rot=20= (num=20w=20n)=0A=20=20"Shift=20number=20NUM=20of=20W=20bits=20up=20by=20= N=20bits,=20carrying=20around=20to=20the=20low=20bits.=0AN=20should=20be=20= strictly=20less=20than=20W=20and=20the=20returned=20value=20will=20fit=0A= within=20W=20bits."=0A=20=20(logand=20(indent-bars--block=20w)=20(logior=20= (ash=20num=20n)=20(ash=20num=20(-=20n=20w)))))=0A=0A(defun=20= indent-bars--row-data=20(w=20pad=20rot=20width-frac)=0A=20=20"Calculate=20= stipple=20row=20data=20to=20fit=20in=20character=20of=20width=20W.=0AThe=20= width=20of=20the=20pattern=20of=20filled=20pixels=20is=20determined=20by=0A= WIDTH-FRAC.=20=20The=20pattern=20itself=20is=20shifted=20up=20by=20PAD=20= bits=20(which=0Ashifts=20the=20pattern=20to=20the=20right,=20for=20= positive=20values=20of=20PAD).=0ASubsequently,=20the=20value=20is=20= shifted=20up=20(with=20W-bit=20wrap-around)=20by=0AROT=20bits,=20and=20= returned.=20=20ROT=20is=20the=20starting=20bit=20offset=20of=20a=0A= character=20within=20the=20closest=20stipple=20repeat=20to=20the=20left;=20= i.e.=20if=0Apixel=201=20of=20the=20stipple=20aligns=20with=20pixel=201=20= of=20the=20chacter,=20ROT=3D0.=0AROT=20should=20be=20less=20than=20W."=0A= =20=20(let*=20((bar-width=20(max=201=20(round=20(*=20w=20width-frac))))=0A= =09=20(num=20(indent-bars--rot=0A=09=20=20=20=20=20=20=20(ash=20= (indent-bars--block=20bar-width)=20pad)=20w=20rot)))=0A=20=20=20=20= (apply=20#'unibyte-string=0A=09=20=20=20(cl-loop=20for=20boff=20=3D=200=20= then=20(+=20boff=208)=20while=20(<=20boff=20w)=0A=09=09=20=20=20=20for=20= nbits=20=3D=20(min=208=20(-=20w=20boff))=0A=09=09=20=20=20=20collect=20= (ash=20(logand=20num=0A=09=09=09=09=09=20(ash=20(indent-bars--block=20= nbits)=20boff))=0A=09=09=09=09=20(-=20boff))))))=0A=0A;;=20**=20Notes=20= on=20the=20stipples:=0A;;=0A;;=20indent-bars=20by=20default=20uses=20a=20= selectively-revealed=20stipple=20pattern=0A;;=20with=20a=20width=20= equivalent=20to=20the=20(presumed=20fixed)=20width=20of=20individual=0A= ;;=20characters=20to=20efficiently=20draw=20bars.=20=20A=20stipple=20= pattern=20is=20drawn=20as=0A;;=20a=20fixed=20repeating=20bit=20pattern,=20= with=20its=20lowest=20bits=20and=20earlier=0A;;=20bytes=20leftmost.=20=20= It=20is=20drawn=20with=20respect=20to=20the=20*entire=20frame*,=0A;;=20= with=20its=20first=20bit=20aligned=20with=20the=20first=20(leftmost)=20= frame=20pixel.=0A;;=20=0A;;=20Turning=20on=20:stipple=20for=20a=20= character=20merely=20"opens=20a=20window"=20on=20that=0A;;=20= frame-filling,=20repeating=20stipple=20pattern.=20=20Since=20the=20= pattern=20starts=0A;;=20outside=20the=20body=20(in=20literally=20the=20= first=20frame=20pixel,=20typically=0A;;=20within=20the=20fringe),=20you=20= must=20consider=20the=20shift=20between=20the=20first=0A;;=20pixel=20of=20= a=20window=20character=20and=20the=20first=20pixel=20of=20the=20= repeating=0A;;=20stipple=20block=20at=20that=20pixel=20position=20or=20= above:=0A;;=20=0A;;=20=20=20=20=20|<-frame=20edge=20|<---buffer/window=20= edge=0A;;=20=20=20=20=20|<--w-->|<--w-->|<--w-->|=20=20=20=20=20w=20=3D=20= pattern=20width=0A;;=20=20=20=20=20|=20marg+fringe=20|<-chr->|=20=20=20=20= =20chr=20=3D=20character=20width=20=3D=20w=0A;;=20=20=20=20=20=20=20=20=20= =20=20=20=20|<-g->|=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20g=20=3D=20= gutter=20offset=20of=20chr=20start,=20g<w=0A;;=0A;;=20Or,=20when=20the=20= character=20width=20exceeds=20the=20margin/fringe=20offset:=0A;;=20=0A;;=20= =20=20=20=20|<-frame=20edge=20|<---buffer/window=20edge=0A;;=20=20=20=20=20= |<--------w-------->|<---------w-------->|=0A;;=20=20=20=20=20|=20= marg+fringe=20|<-------chr------->|=0A;;=20=20=20=20=20|<-----g----->|=0A= ;;=0A;;=20So=20g=20=3D=20(mod=20marg+fringe=20w).=0A;;=20=0A;;=20When=20= the=20block/zigzag/whatever=20stipple=20pattern=20is=20made,=20to=20= align=0A;;=20with=20characters,=20it=20must=20get=20shifted=20up=20(=3D=20= right)=20by=20g=20bits,=20with=0A;;=20carry=20over=20(wrap)=20around=20= w=3D(window-font-width)=20bits=20(i.e=20the=20width=0A;;=20of=20the=20= bitmap).=20=20The=20byte/bit=20pattern=20is=20first-lowest-leftmost.=0A= ;;=0A;;=20Note=20that=20different=20windows=20may=20have=20different=20g=20= values=0A;;=20(e.g.=20left/right),=20which=20means=20the=20same=20bitmap=20= cannot=20work=20for=20the=0A;;=20buffer=20in=20both=20windows.=20=20In=20= practice=20that=20means=20that=20all=20stipple=0A;;=20face=20attributes=20= must=20be=20set=20via=20filtered=20face=20remaps,=20with=20the=0A;;=20= filter=20set=20to=20match=20the=20pattern=20size=20(width=20and=20= height)=20as=20well=20as=0A;;=20gutter=20offset=20"rot"=20value=20in=20= that=20window,=20which=20we=20combine=20into=20a=0A;;=20single=20= integer.=0A;;=0A;;=20Note:=20a=20bug=20in=20Emacs=20<29=20means=20= `face-remapping-alist'=20is=0A;;=20unintentionally=20shared=20between=20= indirect=20and=20master=20buffers.=20=20Fixed=0A;;=20in=20Emacs=2029.=0A=0A= (defun=20indent-bars--stipple=20(w=20h=20rot=20&optional=20style=0A=09=09= =09=20=20=20=20=20=20=20width-frac=20pad-frac=20pattern=20zigzag)=0A=20=20= "Calculate=20stipple=20bitmap=20pattern=20for=20char=20width=20W=20and=20= height=20H.=0AROT=20is=20the=20number=20of=20bits=20to=20rotate=20the=20= pattern=20around=20to=20the=0Aright=20(with=20wrap).=0A=0AUses=20= configuration=20variables=20`indent-bars-width-frac',=0A= `indent-bars-pad-frac',=20`indent-bars-pattern',=20and=0A= `indent-bars-zigzag',=20unless=20PAD-FRAC,=20WIDTH-FRAC,=20PATTERN,=0A= and/or=20ZIGZAG=20are=20set=20(the=20latter=20overriding=20the=20config=0A= variables,=20which=20see).=20=20If=20STYLE=20is=20set,=20use=20config=20= variables=0Aappropriate=20for=20that=20style."=0A=20=20(unless=20(or=20= (not=20(display-graphic-p))=20indent-bars-prefer-character)=0A=20=20=20=20= (let*=20((rowbytes=20(/=20(+=20w=207)=208))=0A=09=20=20=20(pattern=20(or=20= pattern=20(indent-bars--style=20style=20"pattern")))=0A=09=20=20=20(pat=20= (if=20(<=20h=20(length=20pattern))=20(substring=20pattern=200=20h)=20= pattern))=0A=09=20=20=20(plen=20(length=20pat))=0A=09=20=20=20(chunk=20= (/=20(float=20h)=20plen))=0A=09=20=20=20(small=20(floor=20chunk))=0A=09=20= =20=20(large=20(ceiling=20chunk))=0A=09=20=20=20(pad-frac=20(or=20= pad-frac=20(indent-bars--style=20style=20"pad-frac")))=0A=09=20=20=20= (pad=20(round=20(*=20w=20pad-frac)))=0A=09=20=20=20(zigzag=20(or=20= zigzag=20(indent-bars--style=20style=20"zigzag")))=0A=09=20=20=20(zz=20= (if=20zigzag=20(round=20(*=20w=20zigzag))=200))=0A=09=20=20=20(zeroes=20= (make-string=20rowbytes=20?\0))=0A=09=20=20=20(width-frac=20(or=20= width-frac=20(indent-bars--style=20style=20"width-frac")))=0A=09=20=20=20= (dlist=20(if=20(and=20(=3D=20plen=201)=20(not=20(string=3D=20pat=20"=20= ")))=20;=20solid=20bar=0A=09=09=20=20=20=20=20=20(list=20= (indent-bars--row-data=20w=20pad=20rot=20width-frac))=20;=20one=20row=0A=09= =09=20=20=20=20(cl-loop=20for=20last-fill-char=20=3D=20nil=20then=20x=0A=09= =09=09=20=20=20=20=20for=20x=20across=20pat=0A=09=09=09=20=20=20=20=20= for=20n=20=3D=20small=20then=20(if=20(and=20(/=3D=20x=20?\s)=20(=3D=20n=20= small))=0A=09=09=09=09=09=09=20=20=20=20large=0A=09=09=09=09=09=09=20=20= small)=0A=09=09=09=20=20=20=20=20for=20zoff=20=3D=20zz=20then=20(if=20= (and=20last-fill-char=0A=09=09=09=09=09=09=09=20(/=3D=20x=20?\s)=0A=09=09= =09=09=09=09=09=20(/=3D=20x=20last-fill-char))=0A=09=09=09=09=09=09=20=20= =20=20(-=20zoff)=20zoff)=0A=09=09=09=20=20=20=20=20for=20row=20=3D=20(if=20= (=3D=20x=20?\s)=20zeroes=0A=09=09=09=09=09=20(indent-bars--row-data=20w=20= (+=20pad=20zoff)=0A=09=09=09=09=09=09=09=09rot=20width-frac))=0A=09=09=09= =20=20=20=20=20append=20(cl-loop=20repeat=20n=20collect=20row)))))=0A=20=20= =20=20=20=20(list=20w=20(length=20dlist)=20(string-join=20dlist)))))=0A=0A= (defsubst=20indent-bars--whr=20(w=20h=20r)=0A=20=20"Encoded=20value=20= for=20W,=20H=20and=20R."=0A=20=20(+=20(ash=20w=2016)=20(ash=20h=208)=20= r))=0A=0A(defvar-local=20indent-bars--stipple-remaps=20nil=0A=20=20"A=20= hash=20table=20of=20active=20stipple=20face-remap=20cookies.=0AThe=20= hash=20table=20is=20keyed=20by=20the=20`whr',=20an=20integer=20composing=20= font=0Awidth,=20height,=20and=20window=20starting=20offset=20(see=0A= `indent-bars--whr').=20=20Elements=20of=20the=20hash=20table=20are=20= plists=20with=0Athe=20following=20keys:=0A=0A=20=20(:main[-styletag]=20= ...=20:current[-styletag]=20...)=0A=0AThese=20are=20used=20to=20update=20= relevant=20stipples=20for=20main=20and=20current=0Astipple=20faces=20for=20= the=20various=20styles=20as=20character=20size=20and/or=0Awindow=20pixel=20= start=20(pattern=20rotation=20\"rot\")=20change,=20due=20to=0Awindow=20= layout=20or=20font=20size=20changes.=20=20Note=20that=20all=20stipple=0A= attributes=20are=20set=20via=20filtered=20face=20remaps.")=0A=0A= (defsubst=20indent-bars--remove-plist-remaps=20(pl)=0A=20=20"Remove=20= remaps=20key=20values=20from=20plist=20PL."=0A=20=20(cl-loop=20for=20(_k=20= r)=20on=20pl=20by=20#'cddr=20do=0A=09=20=20=20= (face-remap-remove-relative=20r)))=0A=0A(defun=20= indent-bars--create-stipple-remaps=20(w=20h=20rot)=0A=20=20"Create=20and=20= store=20stipple=20remaps=20for=20the=20given=20font=20size=20and=20pixel=20= start.=0AW=20is=20the=20`window-font-width',=20H=20is=20the=20= corresponding=20height,=20and=0AROT=20is=20the=20number=20of=20bits=20to=20= rotate=20the=20pattern=20start.=20=20An=20entry=0Ais=20created=20for=20= each=20active=20style,=20for=20both=20:main[-styletag]=20and=0A= :current[-styletag]=20highlight=20contexts."=0A=20=20(let*=20((whr=20= (indent-bars--whr=20w=20h=20rot))=0A=09=20(filter=20`(:window=20= indent-bars-whr=20,whr))=0A=09=20remap)=0A=20=20=20=20(dolist=20(s=20= indent-bars--styles)=0A=20=20=20=20=20=20;;=20Main=20stipple=20face=0A=20= =20=20=20=20=20(when=20(ibs/stipple-face=20s)=0A=09(setq=20remap=0A=09=20= =20=20=20=20=20(plist-put=0A=09=20=20=20=20=20=20=20remap=20= (indent-bars--tag=20":main%s"=20s)=0A=09=20=20=20=20=20=20=20= (face-remap-add-relative=0A=09=09(ibs/stipple-face=20s)=0A=09=09`(=20= :filtered=20,filter=0A=09=09=20=20=20(:stipple=20,(indent-bars--stipple=20= w=20h=20rot=20s)))))))=0A=20=20=20=20=20=20;;=20Currently=20highlighted=20= stipple=20face=0A=20=20=20=20=20=20(when=20(ibs/current-stipple-face=20= s)=0A=09(setq=20remap=0A=09=20=20=20=20=20=20(plist-put=0A=09=20=20=20=20= =20=20=20remap=20(indent-bars--tag=20":current%s"=20s)=0A=09=20=20=20=20=20= =20=20(face-remap-add-relative=0A=09=09(ibs/current-stipple-face=20s)=0A=09= =09`(=20:filtered=20,filter=0A=09=09=20=20=20(:stipple=20= ,(indent-bars--current-depth-stipple=20w=20h=20rot=20s))))))=0A=09= (indent-bars--highlight-current-depth=20'force)))=0A=20=20=20=20(puthash=20= whr=20remap=20indent-bars--stipple-remaps)))=0A=0A;;;;=20Window=20change=20= and=20cleanup=0A(defvar-local=20indent-bars--needs-cleanup=20nil)=0A= (defun=20indent-bars--schedule-remap-cleanup=20()=0A=20=20"Schedule=20= cleanup=20of=20stipple=20remaps,=20unless=20already=20scheduled."=0A=20=20= (unless=20indent-bars--needs-cleanup=0A=20=20=20=20(setq=20= indent-bars--needs-cleanup=20t)=0A=20=20=20=20(run-with-idle-timer=0A=20=20= =20=20=201=20nil=0A=20=20=20=20=20(apply-partially=20= #'indent-bars--cleanup-stipple-remaps=20(current-buffer)))))=0A=0A(defun=20= indent-bars--update-all-stipples=20()=0A=20=20"Update=20all=20stipples=20= for=20current=20buffer."=0A=20=20(dolist=20(w=20(get-buffer-window-list=20= nil=20nil=20t))=0A=20=20=20=20(indent-bars--window-change=20w)))=0A=0A= (defun=20indent-bars--window-change=20(&optional=20win)=0A=20=20"Update=20= the=20stipples=20for=20buffer=20in=20window=20WIN.=0AWIN=20defaults=20to=20= the=20selected=20window.=20=20To=20be=20set=20as=20a=20local=0A= `window-state-change-functions'=20hook."=0A=20=20(unless=20win=20(setq=20= win=20(selected-window)))=0A=20=20(let*=20((w=20(window-font-width=20= win))=0A=09=20(h=20(window-font-height=20win))=0A=09=20(rot=20= (indent-bars--stipple-rot=20win=20w))=0A=09=20(whr=20(indent-bars--whr=20= w=20h=20rot))=0A=09=20(cur-whr=20(window-parameter=20win=20= 'indent-bars-whr)))=0A=20=20=20=20(unless=20(eq=20cur-whr=20whr)=0A=20=20= =20=20=20=20(set-window-parameter=20win=20'indent-bars-whr=20whr))=0A=20=20= =20=20(when-let=20((buf=20(window-buffer=20win))=0A=09=20=20=20=20=20=20=20= (ht=20(buffer-local-value=20'indent-bars--stipple-remaps=20buf))=0A=09=20= =20=20=20=20=20=20((null=20(gethash=20whr=20ht))))=0A=20=20=20=20=20=20= (with-current-buffer=20buf=20;=20we=20may=20be=20called=20from=20an=20= arbitrary=20buffer=0A=09(indent-bars--create-stipple-remaps=20w=20h=20= rot)=0A=09(indent-bars--schedule-remap-cleanup)))))=0A=0A(defun=20= indent-bars--cleanup-stipple-remaps=20(buf)=0A=20=20"Clean=20up=20unused=20= stipple=20face=20remaps=20for=20buffer=20BUF."=0A=20=20(when-let=20= (((buffer-live-p=20buf))=0A=09=20=20=20=20=20(wins=20= (get-buffer-window-list=20buf=20nil=20t))=0A=09=20=20=20=20=20(whrs=20= (cl-loop=20for=20win=20in=20wins=0A=09=09=09=20=20=20=20collect=20= (window-parameter=20win=20'indent-bars-whr)))=0A=09=20=20=20=20=20= (rmp-hsh=20(buffer-local-value=20'indent-bars--stipple-remaps=20buf))=0A=09= =20=20=20=20=20(rkeys=20(hash-table-keys=20rmp-hsh))=0A=09=20=20=20=20=20= (unneeded=20(seq-difference=20rkeys=20whrs)))=0A=20=20=20=20= (with-current-buffer=20buf=20;N.B.=20face-remapping-alist=20is=20= buffer-local=0A=20=20=20=20=20=20(dolist=20(rk=20unneeded)=0A=09= (indent-bars--remove-plist-remaps=20(gethash=20rk=20rmp-hsh))=0A=09= (remhash=20rk=20rmp-hsh)))=0A=20=20=20=20(setf=20(buffer-local-value=20= 'indent-bars--needs-cleanup=20buf)=20nil)))=0A=0A;;;;=20Setup=20and=20= mode=0A(defun=20indent-bars--guess-spacing=20()=0A=20=20"Get=20= indentation=20spacing=20of=20current=20buffer.=0AAdapted=20from=20= `highlight-indentation-mode'."=0A=20=20(cond=0A=20=20=20= (indent-bars-spacing-override)=0A=20=20=20((and=20(derived-mode-p=20= 'python-mode)=20(boundp=20'py-indent-offset))=0A=20=20=20=20= py-indent-offset)=0A=20=20=20((and=20(derived-mode-p=20'python-mode)=20= (boundp=20'python-indent-offset))=0A=20=20=20=20python-indent-offset)=0A=20= =20=20((and=20(derived-mode-p=20'ruby-mode)=20(boundp=20= 'ruby-indent-level))=0A=20=20=20=20ruby-indent-level)=0A=20=20=20((and=20= (derived-mode-p=20'scala-mode)=20(boundp=20'scala-indent:step))=0A=20=20=20= =20scala-indent:step)=0A=20=20=20((and=20(derived-mode-p=20'scala-mode)=20= (boundp=20'scala-mode-indent:step))=0A=20=20=20=20= scala-mode-indent:step)=0A=20=20=20((and=20(or=20(derived-mode-p=20= 'scss-mode)=20(derived-mode-p=20'css-mode))=0A=09=20(boundp=20= 'css-indent-offset))=0A=20=20=20=20css-indent-offset)=0A=20=20=20((and=20= (derived-mode-p=20'nxml-mode)=20(boundp=20'nxml-child-indent))=0A=20=20=20= =20nxml-child-indent)=0A=20=20=20((and=20(derived-mode-p=20'coffee-mode)=20= (boundp=20'coffee-tab-width))=0A=20=20=20=20coffee-tab-width)=0A=20=20=20= ((and=20(derived-mode-p=20'js-mode)=20(boundp=20'js-indent-level))=0A=20=20= =20=20js-indent-level)=0A=20=20=20((and=20(derived-mode-p=20'js2-mode)=20= (boundp=20'js2-basic-offset))=0A=20=20=20=20js2-basic-offset)=0A=20=20=20= ((and=20(derived-mode-p=20'sws-mode)=20(boundp=20'sws-tab-width))=0A=20=20= =20=20sws-tab-width)=0A=20=20=20((and=20(derived-mode-p=20'web-mode)=20= (boundp=20'web-mode-markup-indent-offset))=0A=20=20=20=20= web-mode-markup-indent-offset)=0A=20=20=20((and=20(derived-mode-p=20= 'web-mode)=20(boundp=20'web-mode-html-offset))=20;=20old=20var=0A=20=20=20= =20web-mode-html-offset)=0A=20=20=20((and=20(local-variable-p=20= 'c-basic-offset)=20(numberp=20c-basic-offset))=0A=20=20=20=20= c-basic-offset)=0A=20=20=20((and=20(local-variable-p=20= 'c-ts-common-indent-offset)=0A=09=20(symbolp=20= c-ts-common-indent-offset))=0A=20=20=20=20(numberp=20(symbol-value=20= c-ts-common-indent-offset)))=0A=20=20=20((and=20(derived-mode-p=20= 'yaml-mode)=20(boundp=20'yaml-indent-offset))=0A=20=20=20=20= yaml-indent-offset)=0A=20=20=20((and=20(derived-mode-p=20'elixir-mode)=20= (boundp=20'elixir-smie-indent-basic))=0A=20=20=20=20= elixir-smie-indent-basic)=0A=20=20=20((and=20(derived-mode-p=20= 'lisp-data-mode)=20(boundp=20'lisp-body-indent))=0A=20=20=20=20= lisp-body-indent)=0A=20=20=20((and=20(derived-mode-p=20'cobol-mode)=20= (boundp=20'cobol-tab-width))=0A=20=20=20=20cobol-tab-width)=0A=20=20=20= ((or=20(derived-mode-p=20'go-ts-mode)=20(derived-mode-p=20'go-mode))=0A=20= =20=20=20tab-width)=0A=20=20=20((derived-mode-p=20'nix-mode)=0A=20=20=20=20= tab-width)=0A=20=20=20((and=20(derived-mode-p=20'nix-ts-mode)=20(boundp=20= 'nix-ts-mode-indent-offset))=0A=20=20=20=20nix-ts-mode-indent-offset)=0A=20= =20=20((and=20(derived-mode-p=20'json-ts-mode)=20(boundp=20= 'json-ts-mode-indent-offset))=0A=20=20=20=20json-ts-mode-indent-offset)=0A= =20=20=20((and=20(derived-mode-p=20'json-mode)=20(boundp=20= 'js-indent-level))=0A=20=20=20=20js-indent-level)=0A=20=20=20((and=20= (boundp=20'standard-indent)=20standard-indent))=0A=20=20=20(t=204)))=20=09= =09=09=09;=20backup=0A=0A(defvar=20indent-bars--display-form=0A=20=20= '(indent-bars--display=20(match-beginning=201)=20(match-end=201)))=0A= (defvar=20indent-bars--handle-blank-lines-form=0A=20=20= '(indent-bars--handle-blank-lines=20(match-beginning=200)=20(match-end=20= 0)))=0A(defun=20indent-bars--setup-font-lock=20()=0A=20=20"Setup=20font=20= lock=20keywords=20and=20functions=20for=20indent-bars."=0A=20=20(unless=20= (eq=20font-lock-unfontify-region-function=20#'indent-bars--unfontify)=0A=20= =20=20=20(setq=20indent-bars-orig-unfontify-region=20= font-lock-unfontify-region-function))=0A=20=20(setq-local=20= font-lock-unfontify-region-function=20#'indent-bars--unfontify)=0A=20=20= (setq=20indent-bars--font-lock-keywords=20;=20basic=20blank=20prefix=20= detection=0A=09`((,(rx-to-string=20`(seq=20bol=0A=09=09=09=09(group=0A=09= =09=09=09=20,(if=20(not=20indent-tabs-mode)=0A=09=09=09=09=20=20=20=20=20= =20`(>=3D=20,(1+=20indent-bars--offset)=20?\s)=0A=09=09=09=09=20=20=20=20= '(+=20(any=20?\t=20?\s))))=0A=09=09=09=09(not=20(any=20?\t=20?\s=20= ?\n))))=0A=09=20=20=20(1=20,indent-bars--display-form))))=0A=20=20= (font-lock-add-keywords=20nil=20indent-bars--font-lock-keywords=20t)=0A=20= =20(if=20indent-bars-display-on-blank-lines=0A=20=20=20=20=20=20(let=20= ((re=20(rx=20bol=20(*=20(or=20?\s=20?\t=20?\n))=20?\n)))=20;=20= multi-line=20blank=20regions=0A=09(setq=20= indent-bars--font-lock-blank-line-keywords=0A=09=20=20=20=20=20=20`((,re=20= (0=20,indent-bars--handle-blank-lines-form))))=0A=09= (font-lock-add-keywords=20nil=20= indent-bars--font-lock-blank-line-keywords=20t)=0A=09(add-hook=20= 'font-lock-extend-region-functions=0A=09=09=20=20= #'indent-bars--extend-blank-line-regions=2095=20t))))=0A=0A= (declare-function=20indent-bars-ts-mode=20"indent-bars-ts")=0A=0A(defun=20= indent-bars-setup=20()=0A=20=20"Setup=20all=20face,=20color,=20bar=20= size,=20and=20indentation=20info=20for=20the=20current=20buffer."=0A=20=20= ;;=20Spacing=0A=20=20(setq=20indent-bars-spacing=20= (indent-bars--guess-spacing)=0A=09indent-bars--offset=20(or=20= indent-bars-starting-column=20indent-bars-spacing))=0A=0A=20=20;;=20No=20= Stipple=20(e.g.=20terminal)=0A=20=20(setq=20indent-bars--no-stipple=0A=09= (or=20(not=20(display-graphic-p))=20indent-bars-prefer-character))=0A=0A=20= =20;;=20Style=20(color=20+=20stipple)=0A=20=20(unless=20(and=20= indent-bars-style=20indent-bars--styles)=0A=20=20=20=20= (indent-bars--initialize-style=0A=20=20=20=20=20(setq=20= indent-bars-style=20(indent-bars--new-style))))=0A=0A=20=20;;=20Window=20= state:=20selection/size=0A=20=20(unless=20indent-bars--no-stipple=0A=20=20= =20=20(add-hook=20'window-state-change-functions=0A=09=20=20=20=20=20=20= #'indent-bars--window-change=20nil=20t))=0A=0A=20=20;;=20PPSS=0A=20=20= (setq=20indent-bars--ppss=0A=09(or=20indent-bars-no-descend-string=20= indent-bars-no-descend-lists))=0A=20=20=0A=20=20;;=20Treesitter=0A=20=20= (if=20indent-bars-treesit-support=20(indent-bars-ts-mode=201))=20;=20= autoloads=0A=0A=20=20;;=20Remap/Resize=0A=20=20(unless=20= indent-bars--no-stipple=0A=20=20=20=20(setq=20= indent-bars--stipple-remaps=20(make-hash-table))=0A=20=20=20=20(add-hook=20= 'text-scale-mode-hook=20#'indent-bars--update-all-stipples=20nil=20t)=0A=20= =20=20=20(indent-bars--update-all-stipples))=20;=20sets=20all=20remaps=20= for=20current=20buffer=0A=0A=20=20;;=20Current=20depth=20Highlighting=0A=20= =20(when=20(indent-bars--style=20'any=20"highlight-current-depth")=0A=20=20= =20=20(add-hook=20'post-command-hook=0A=09=20=20=20=20=20=20= #'indent-bars--highlight-current-depth=20nil=20t)=0A=20=20=20=20(setq=20= indent-bars--current-depth=200)=0A=20=20=20=20= (indent-bars--highlight-current-depth))=0A=20=20=0A=20=20;;=20Font-lock=0A= =20=20(indent-bars--setup-font-lock)=0A=20=20(font-lock-flush))=0A=0A= (defvar=20indent-bars--teardown-functions=20nil)=0A(defun=20= indent-bars-teardown=20()=0A=20=20"Tears=20down=20indent-bars."=0A=20=20= ;;=20Remove=20current=20highlight=20remaps=0A=20=20(dolist=20(s=20= indent-bars--styles)=0A=20=20=20=20(face-remap-remove-relative=0A=20=20=20= =20=20(alist-get=20(ibs/tag=20s)=20indent-bars--remaps)))=0A=0A=20=20;;=20= Remove=20stipple=20remaps=20and=20window=20parameters=0A=20=20(unless=20= indent-bars--no-stipple=0A=20=20=20=20(when=20= indent-bars--stipple-remaps=0A=20=20=20=20=20=20(maphash=20(lambda=20(_k=20= pl)=0A=09=09=20(indent-bars--remove-plist-remaps=20pl))=0A=09=20=20=20=20= =20=20=20indent-bars--stipple-remaps)=0A=20=20=20=20=20=20(setq=20= indent-bars--stipple-remaps=20nil)))=0A=20=20=0A=20=20= (font-lock-remove-keywords=20nil=20indent-bars--font-lock-keywords)=0A=20= =20(font-lock-remove-keywords=20nil=20= indent-bars--font-lock-blank-line-keywords)=0A=20=20(font-lock-flush)=0A=20= =20(font-lock-ensure)=0A=20=20=0A=20=20(when=20= indent-bars-orig-unfontify-region=0A=20=20=20=20(setq=20= font-lock-unfontify-region-function=0A=09=20=20= indent-bars-orig-unfontify-region))=0A=20=20(setq=20= indent-bars--current-depth=200)=0A=20=20(remove-hook=20= 'text-scale-mode-hook=20#'indent-bars--update-all-stipples=20t)=0A=20=20= (remove-hook=20'post-command-hook=20= #'indent-bars--highlight-current-depth=20t)=0A=20=20(remove-hook=20= 'font-lock-extend-region-functions=0A=09=20=20=20=20=20=20=20= #'indent-bars--extend-blank-line-regions=20t)=0A=20=20(remove-hook=20= 'window-state-change-functions=0A=09=20=20=20=20=20=20=20= #'indent-bars--window-change=20t)=0A=20=20(run-hooks=20= 'indent-bars--teardown-functions))=0A=0A(defun=20indent-bars-reset=20= (&rest=20_r)=0A=20=20"Reset=20indent-bars=20config."=0A=20=20= (interactive)=0A=20=20(indent-bars-teardown)=0A=20=20(setq=20= indent-bars-style=20nil=20indent-bars--styles=20nil)=0A=20=20= (indent-bars-setup))=0A=0A(defun=20indent-bars-setup-and-remove=20= (frame)=0A=20=20"Setup=20indent=20bars=20for=20FRAME=20and=20remove=20= from=20`after-make-frame-functions'."=0A=20=20(when=20(display-graphic-p=20= frame)=0A=20=20=20=20(with-selected-frame=20frame=0A=20=20=20=20=20=20= (remove-hook=20'after-make-frame-functions=20= #'indent-bars-setup-and-remove=20t)=0A=20=20=20=20=20=20= (indent-bars-setup))))=0A=0A;;;###autoload=0A(define-minor-mode=20= indent-bars-mode=0A=20=20"Indicate=20indentation=20with=20configurable=20= bars."=0A=20=20:global=20nil=0A=20=20=0A=20=20(if=20indent-bars-mode=0A=20= =20=20=20=20=20(if=20(and=20(daemonp)=20(not=20(frame-parameter=20nil=20= 'client)))=0A=09=20=20(add-hook=20'after-make-frame-functions=20= #'indent-bars-setup-and-remove=0A=09=09=20=20=20=20nil=20t)=0A=09= (indent-bars-setup))=0A=20=20=20=20(indent-bars-teardown)))=0A=0A;;=20= Theme=20support=0A(if=20(boundp=20'enable-theme-functions)=0A=20=20=20=20= (add-hook=20'enable-theme-functions=20#'indent-bars-reset-styles))=0A=0A= (provide=20'indent-bars)=0A=0A;;;=20indent-bars.el=20ends=20here=0A;;=20= Local=20Variables:=0A;;=20read-symbol-shorthands:=20(("ibs/"=20.=20= "indent-bars-style-"))=0A;;=20End:=0A= --Apple-Mail=_C888637E-22A8-40AE-9AB0-5A5337C16EA2 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii <html><head><meta http-equiv="content-type" content="text/html; charset=us-ascii"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"></body></html> --Apple-Mail=_C888637E-22A8-40AE-9AB0-5A5337C16EA2-- --Apple-Mail=_8D1B272E-2958-49A5-AF96-FD9831F9042C-- --===============6027475216738180127== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline --===============6027475216738180127==--