A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/jdtsmith/indent-bars below:

jdtsmith/indent-bars: Fast, configurable indentation guide-bars for Emacs

indent-bars: fast, configurable indentation guide-bars for Emacs

FAQINSTALLCUSTOMIZEMORE DETAILS

This package provides indentation guide bars in Emacs, with optional tree-sitter enhancement:

See the release NEWS.

indent-bars is on ELPA; simply install with Emacs' package facilities, and configure by calling indent-bars-mode in your desired mode hooks.

Simple default config using use-package:

(use-package indent-bars
  :hook ((python-mode yaml-mode) . indent-bars-mode)) ; or whichever modes you prefer

Important

treesitter users: indent-bars needs your help! If you have come up with good settings for treesitter "wrap" and "scope" for your favorite languages, please add them to the Wiki! If we get a large enough collection they may be included as defaults.

Configures tree-sitter and ignore-blank-line support for an example language.

(use-package indent-bars
  :custom
  (indent-bars-no-descend-lists t) ; no extra bars in continued func arg lists
  (indent-bars-treesit-support t)
  (indent-bars-treesit-ignore-blank-lines-types '("module"))
  ;; Add other languages as needed
  (indent-bars-treesit-scope '((python function_definition class_definition for_statement
	  if_statement with_statement while_statement)))
  ;; Note: wrap may not be needed if no-descend-list is enough
  ;;(indent-bars-treesit-wrap '((python argument_list parameters ; for python, as an example
  ;;				      list list_comprehension
  ;;				      dictionary dictionary_comprehension
  ;;				      parenthesized_expression subscript)))
  :hook ((python-base-mode yaml-mode) . indent-bars-mode))

See tree-sitter, and also the Wiki page.

Important

For indent-bars to display fancy guide bars, your port and version of emacs must correctly display the :stipple face attribute. Most do, but some do not.

Known :stipple support, by Emacs build:

Please open an issue with any updates/corrections to this list. See also Testing Stipples.

indent-bars can also be used without stipples, drawing a simple vertical character (like ) instead. It automatically does this in non-graphical displays (terminals), but this can be made the default; see Character Display.

Note

indent-bars is highly flexible and can be adapted to most situations. It can't anticipate all nuances of different languages, modes, and user preferences, however — "some assembly may be required". If you arrive at customizations you are happy with for a given mode, please consider adding to the Wiki page.

M-x customize-group indent-bars is the easiest way to customize everything about the appearance and function of indent-bars (check sub-groups too). There are many customization variables and bar styling in particular is highly configurable, so use Customize!

Tip

The easiest way to achieve a particular style is to customize the groups indent-bars, sub-group indent-bars-style and (if you use TS) indent-bars-ts + indent-bars-ts-style. While in the Customize interface, pull up one of your buffers with bars in another window on the same frame. When you make changes to variables (C-c C-c is convenient in custom buffers), the bar style/etc. will automatically update. When you are happy, you can either "Set for Future Sessions", or "Show Saved Lisp Expression" for the variables you changed and copy them into your init file.

See some examples with relevant settings.

The main customization variables are categorized below. See the documentation of each variable for more details on the valid values.

Custom variables for configuring bar color, including depth-based palettes:

Variables affecting the visual appearance of bars (color aside):

Current Depth highlighting

Configuration for highlighting the current indentation bar depth:

Configuration variables for bar position and line locations (including on blank lines):

Character-based bars and terminal

Custom variables affecting character-based bar display, e.g. in the terminal:

For more information, check the details.

Main treesitter configuration variables Tree-sitter alternate in-scope/out-of-scope styling variables

By default, if tree-sitter and scope focus are active (indent-bars-treesit-scope), the style and highlight settings above apply only to the in-scope bars (or visa versa if indent-bars-ts-styling-scope is set to in-scope). You can separately configure an alternate style for the appearance of the out-of-scope bars — i.e. the bars outside the current tree-sitter scope. Usually you'd want to de-emphasize out-of-scope bars somehow, but that's not required (go crazy).

To customize the alternate bar appearance, you use the parallel set of custom variables with an indent-bars-ts- prefix. Each of these variables can be set similarly to their default counterparts to fully configure alternate bar appearance, including color, depth highlighting, bar pattern, etc.

You can interchange the role of in-scope and out-of-scope using indent-bars-ts-styling-scope. This is useful if you prefer to have the default style (e.g. the bar style in non-tree-sitter-enabled buffers) match the out-of-scope style within tree-sitter buffers (i.e. if you want to emphasize bars within scope, not de-emphasize out-of-scope bars).

Note

Scope focus highlighting is completely independent of current depth highlighting, and you can style them separately, and can enable one or the other, both, or neither.

The ts custom variables for configuring the alternate styling are:

Each of these parallel variables has the same form as their equivalent non-ts version (the "parent" variable), with two additions:

  1. Some (marked with [I] above) can optionally use inheritance from their parent. Inheritance means any missing :key-based elements are inherited from the parent style. To configure whether inheritance happens, you can optionally set these [I] variables to a cons cell of the form ([no-]inherit . value), where value has the normal format for the parent variable. inherit (the default, if the cons cell is omitted and value is simply used as-is) means that any unspecified :key values are inherited from the parent variable. The symbol no-inherit means to omit (rather than inherit) any missing key values for the alternate styling. See below for an example of using/overriding inheritance.
  2. For any non-:key type values, the specific symbol value 'unspecified can be set to indicate using the parent's value for that slot.

For example, a setting of:

(setopt indent-bars-ts-color '(inherit unspecified :blend 0.15))

means to configure the color of the alternate style bars as follows:

  1. use the color from the parent variable indent-bars-color (since it is unspecified here)
  2. set :blend to 0.15
  3. inherit any other missing keyword values from indent-bars-color

The easiest way to configure inheritance and unspecified values in the ts variables is via the customize interface; see the customize group indent-bars-ts-style.

Per major-mode customization

Sometimes different indent-bars settings are appropriate for different major modes. In that case, you can use setq-local to set the appropriate cutomize variables locally, directly in the mode's hook, prior to enabling indent-bars:

(add-hook 'emacs-lisp-mode-hook
	  (lambda ()
	    (setq-local indent-tabs-mode t ; make sure tabs-based indenting is on, even if we disable it globally
			indent-bars-no-descend-lists nil) ; elisp is mostly continued lists!  allow bars to descend inside
	    (indent-bars-mode 1)))

Note that tree-sitter scope and wrap config are keyed to the parser language, which may be sufficient for tailoring these (i.e. no buffer-local values needed).

indent-bars works with either space- or tab-based indentation (see indent-tabs-mode). If possible, prefer space indentation, as it is faster.

Note that some modes explicitly enable or disable indent-tabs-mode. If the value of that variable does not match the actual indentation used in a file (e.g. file is indented with tabs, but you have set indent-tabs-mode=nil), bars may go missing. You should ideally pick one indentation-style (tabs or spaces) per mode and stick to it for all files in that mode, but see dtrt-indent for a package that can adapt this variable by examining the file's contents.

indent-bars can highlight the bar at the current depth, and supports a few different ways to determine which bar gets selected for highlight based on point. To configure this behavior, you can set indent-bars-highlight-selection-method to:

  1. nil: The simplest version selects the depth of the last-visible bar on the current line for highlight.
  2. on-bar: The old default, which selects the "unseen" bar that the very first non-blank character on the current line "covers up", or if no such bar exists, the last visible bar.
  3. context: The new default, a blend of these two methods. It selects the last-visible bar (à la nil), unless an adjacent non-blank line (above or below) is indented deeper by at least one level, in which case the on-bar approach is used.

Experiment with these to see which you prefer.

indent-bars can optionally use tree-sitter in supported files to enable several features:

  1. Scope Focus: The current tree-sitter scope can be focused, with out-of-scope bars de-emphasized or in-scope bars emphasized (or actually, styled however you want). This can be configured by specifying matching "scope" node types (e.g. functions, blocks, etc.) for each language of interest. The innermost node (covering sufficient lines) will then be rendered distinctly from out-of-scope bars.
  2. Selective Blank Line Display: By default, indent-bars displays bars on blank lines (though this can be configured), so that they remain continuous. It can be nice to omit the display of blank lines bars at the top structural level (e.g. in a module), to make divisions between top-level constructs more visible. Tree-sitter can help indent-bars identify those lines.
  3. Wrap Detection: It can be useful to prevent excess bars inside wrapped entities which alter indent to "line things up." These include things like argument lists, literal dictionaries, or other heirarchical multi-line structures. Tree-sitter can help detect these and inhibit unwanted bars (but see also indent-bars-no-descend-string/list, which do not require tree-sitter).

Note

indent-bars' tree-sitter capabilities require Emacs 29 or later built with tree-sitter support, and the appropriate tree-sitter grammars installed for your languages of interest. Additional node type configuration by language is required; see below.

Simply configure indent-bars-treesit-scope with the languages and node types for which "local scope" highlighting nodes are of interest. This must be done for each tree-sitter language you use. This scope could be as granular as classes and functions, or include detailed block statements. You can disable scoping for "short blocks" using indent-bars-treesit-scope-min-lines, so that, e.g., a quick if statement does not capture scope. I recommend starting with the minimal possible set of scope node types, adding as needed.

Tip

If you don't know the name treesitter uses for your language, try M-: (treesit-language-at (point-min)) in a ts-enabled buffer.

indent-bars-treesit-wrap can be configured in a similar manner (mapping language to wrapping node types). Note that indent-bars-no-descend-list, which does not require tree-sitter and is on by default, may be sufficient for your uses.

Ignore certain blank lines

You can assign a single (usually top-level) node type to ignore when drawing bars on blanks linkes; see indent-bars-treesit-ignore-blank-lines-types (which, please note, is configured as a list of strings, unlike indent-bars-treesit-wrap/scope).

Identifying treesit node types of interest

The easiest way to discover node types of interest (in a buffer with working treesit support) is to M-x treesit-explore-mode. Then simply highlight the beginning of a line of interest, and look in the treesitter explorer buffer which pops up for the names of obvious nodes in the tree. Add these types to indent-bars-treesit-scope/wrap for the language of interest, then M-x indent-bars-reset and see how you did (this will happen automatically if you make the change in the Customize interface).

Please document good tree-sitter settings for other languages in the Wiki.

Compatibility with other Packages

indent-bars in general has good compatibility with other packages. But sometimes conflicts do occur.

In general, org-mode src blocks are difficult for many modes to support. Org actually offsets the indentation of the src contents, copies that text to a special hidden buffer, and then maps all face properties (only)) back to the original buffer. This doesn't work well for indent-bars for a few reasons:

So it is best to disable indent-bars in org src blocks. You can achieve this by inhibiting all the mode-hooks from running in org's special hidden fontification buffers (one per mode). E.g., for python:

  (defun my/org-simple-python-mode ()
    (if (string-prefix-p " *org-src-fontification:" (buffer-name))
	(delay-mode-hooks (python-mode))
      (python-mode)))
  (setf (alist-get "python" org-src-lang-modes) 'my/org-simple-python)

This will inhibit hooks (and hence indent-bars, eglot, flymake, whatever else you have setup) from running in the special *org-src-fontification:.. buffers (where they are either harmful or not needed), but these features will still be loaded and work when editing src block contents with C-c '.

Unwanted :stipple inheritance on popups/overlays/etc.

indent-bars by default uses :stipple face attributes, which have only rarely been used in Emacs in recent decades. Consequently, some packages which inherit the face of underlying text while adding styled overlays, popups, etc. to the buffer neglect to guard against the presence of :stipple (e.g. this, or this). This becomes more likely if you set indent-bars-starting-column=0 (since often overlays are placed at the line beginning).

If you encounter unwanted bar patterns on text added to your buffer by other packages as seen in these issues, contact the package's maintainer to let them know they should also clear the :stipple face attribute. You can also try restoring ``indent-bars-starting-column` to the default, if you've changed it.

Sometimes unwanted stipples can be worked around yourself by explicitly setting :stipple to nil in appropriate faces, like:

(set-face-attribute face nil :stipple nil)

for some relevant face (e.g. one from which the package's faces used for overlay/popup inherit). This should be done both when loading indent-bars-mode and in the after-enable-theme-hook.

indent-bars overrides and wraps the font-lock-fontify-region-function (and, when using treesitter, font-lock-fontify-buffer-function). Other packages which advise or wrap the functions pointed to by these variables may lead to odd behavior on disabling/re-enabling indent-bars and/or their associated modes. There is no generic solution to this issue, but the strong recommendation is to enable indent-bars last, after any other package which overrides font-lock in this way have been loaded.

If indent-bars-display-on-blank-lines is set, the newline at the end of blank lines may have a 'display property set to show the bars. Emacs does not deal correctly with display properties containing newlines when moving by columns. This is not normally a problem, but in one instance it is a nuisance: evil-mode tries to "preserve" column during line moves, so can trigger this emacs misfeature. The symptom is that point jumps a line and moves over as you move down with evil. A workaround is here.

Stipples are repeating bitmap patterns anchored to the full emacs frame. indent-bars basically "opens windows" on this fixed pattern to "reveal" the bars.

The fast stipple method used for drawing bars enables lots of interesting patterns.

If you are experiencing issues with stipple bar display (missing, garbled, etc.), and would like to determine if stipples are working correctly in your build of emacs, you can test it as follows.

  1. In the *scratch* buffer, use first M-x font-lock-mode to disable fontification
  2. Hit C-x C-e just after the last ) in the following code:
    (let* ((w (window-font-width))
           (stipple `(,w 1 ,(apply #'unibyte-string
    			       (append (make-list (1- (/ (+ w 7) 8)) ?\0)
    				       '(1))))))
      (insert "\n" (propertize (concat  (make-string 15 ?\s)
    				    "THIS IS A TEST"
    				    (make-string 15 ?\s))
                               'face `(:background "red" :foreground "blue" :stipple ,stipple))))

This should then look something like (note the blue vertical bars):

If you determine that stipples do not work in your version of Emacs, consider upgrading to a version which supports them, reporting the bug, or setting indent-bars-prefer-character=t.

Per-buffer stipple offsets

To get the stipple bars to appear in the correct location within their column, indent-bars must consider the starting horizontal pixel position of the current window, and "rotate" the stipple pattern accordingly. It does this automatically, per buffer, so you shouldn't ever notice problems, even when re-sizing or re-arranging windows, changing font size, etc. Until v0.5, showing the same buffer side by side in Emacs versions which support pixel-level window width/offsets could lead to unexpected bar artifacts, since the offset applies per-buffer, not per-window. In v0.5, an alternate method for applying per-window stipple patterns was used to solve this.

For terminals, (and everywhere, if indent-bars-prefer-character is set), indent-bars will not attempt stipple display, but instead use simple characters (e.g. ; see an example).

Note that in mixed gui/terminal sessions of the same Emacs process, you may need to M-x indent-bars-reset when switching a given buffer between graphical and terminal frames.

Advantages of character bar display

indent-bars was in part motivated by the inefficiency of older indentation highlight modes, and is designed for speed. It uses stipples (fixed bitmap patterns) and font-lock for fast and efficient bar drawing — simply faces on spaces. Highlighting the current indentation level is essentially free, since it works by filtered remapping of the relevant face.

The heaviest operations are tree-sitter support (especially scope highlighting), and blank-line highlighting. If you experience any speed issues, these are the first settings to experiment with. Using with tab-based indentation may also be slightly (but likely imperceptibly) slower than with space-based.

Both indentation-depth highlighting and current-tree-sitter-scope highlighting are protected by timers to avoid unnecessary loads (e.g. when pixel-scrolling). Note that indentation-depth highlighting is very fast and can safely be set to 0 seconds (though bars will then flash rapidly as you scroll). Tree-sitter scope requires querying the tree-sitter core, which can be somewhat slower, so be careful setting its timer too low.

None of the existing packages:

  1. were fast enough with large files (including current depth highlighting)
  2. had enough guide appearance configurability
  3. were able to support depth-based coloring
  4. offered robust support for guides on blank lines
  5. had tree-sitter capabilities

I'm grateful for in-depth advice and input on the design of indent-bars from Eli Zaretski, Stefan Monnier, Dmitry Gutov and many other who opened issues and PRs.

highlight-indentation-mode was a source of good ideas, and indent-bars adapts the indentation guessing function from this mode. The original idea of using stipples for "better" indent-bars came from this comment by @vlcek.

  1. Most easily installed with brew.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4