/treemacs

Primary LanguageEmacs Lisp

https://melpa.org/packages/treemacs-badge.svg https://stable.melpa.org/packages/treemacs-badge.svg https://cdn.rawgit.com/syl20bnr/spacemacs/442d025779da2f62fc86c2082703697714db6514/assets/spacemacs-badge.svg

Treemacs - a tree layout file explorer for Emacs

screenshot.png

Content

Quick Feature Overview

Treemacs is a file and project explorer in the same vein as NeoTree or vim’s NerdTree. It shows the file system outline in a simple tree layout allowing quick navigation and exploration, while also possessing basic file management utilities. Specifically a quick feature overview looks as follows:

  • Easy navigation - quickly change the root directory or use shortcuts to jump to parent or neighbouring nodes.
  • Versatile file access - decide exactly how and where a file will be opened, including using ace-window to choose a window or launching an external application.
  • Optionally always follow along and keep in focus the currently selected file treemacs-follow-mode
  • Optional git integration - treemacs will use different faces for files based on their git status. The git process runs asynchronously and so won’t cause any perceptible delay.
  • Winum integration - treemacs will always be assigned window number 10, never interfering with the numbering layout of your other windows.
  • Projectile integration via the treemacs-projectile package to quickly open treemacs at any known project’s root directory.
  • Simple mouse interface - you can close/expand folders and open files by left-clicking.
  • Dashing good looks - treemacs uses genuine png images in HD 22x22 resolution for its icons (quantity is, of course, another matter). When run in a terminal a very simple fallback is used.
  • Session persistence with desktop-save-mode
  • Treemacs is able to display files’ tags. All file types that emacs can generate a (semantic) imenu index for are supported.
  • Ease of use - treemacs offers many configuration options, but comes with a set of (what hopefully should be) sane defaults. Installation aside there are two obligatory pieces of setup: 1) Choosing convenient keybindings to run treemacs and 2) If you use evil: requiring treemacs-evil to integrate treemacs with evil and enable j/k navigation. More on both below.

Quick Start

If you don’t care about reading the full readme here’s a list of some bare bones basics to get you started:

  • First of all: press ? to summon the helpful hydra: hydra.png
  • If you use evil don’t forget to also install treemacs-evil
  • If you use projectile you can install treemacs-projectile to allow treemacs to interact with projects.
  • Treemacs doesn’ bind any global keys, you need to use whatever fits you best. A full install setup for spacemacs can be found below. Otherwise just bind treemacs and treemacs-toggle.
  • For navigation use n/p (j/k when evil), M-n/M-p to move to same-height neighbour u to go to parent, h to move up a dir, l to move root to selected dir
  • TAB always opens and closes nodes. Files can be opened, too - treemacs will show their imenu index.
  • There’s half a dozen different ways to open nodes, all bound under o as prefix. Pick your favourite.
  • RET runs a default action, configurable to your tastes under treemacs-default-actions

Detailed Feature List

Treemacs-follow-mode

treemacs-follow-mode is a minor mode which allows the treemacs view to always move its focus to the currently selected file. This is achieved by advising select-window, which is a ubiquitous function, often called multiple times in a row when emacs is working. This means two things:

  1. treemacs-follow tries to be very specific about when it is run at all.
  2. There may be times when something slips through (which-key for exmaple would cause such a problem if treemacs

wasn’t made compatible with it by default). If you do see treemacs-follow behaving in a way it shouldn’t open up an issue. The fix shouldn’t be more than a single bit of advice away.

Treemacs-filewatch-mode

treemacs-filewatch-mode is a minor mode which enables treemacs to watch the files it is displaying for changes and automatically refresh itself by means of treemacs-refresh when it detects a change that it decides is relevant.

A file event is relevant for treemacs if a new file has been created or deleted or a file has been changed and treemacs-git-integration is t. Events caused by files that are ignored as per treemacs-ignored-file-predicates are likewise counted as not relevant.

The refresh is not called immediately after an event was received, treemacs instead waits treemacs-file-event-delay ms to see if any more files have changed to avoid having to refresh multiple times over a short period of time. If the treemacs buffer exists, but is not visible, a refresh will be run the next time it is shown.

The change only applies to directories opened after this mode has been activated. This means that to enable file watching in an already existing treemacs buffer it needs to be torn down and rebuilt by calling treemacs or treemacs-projectile.

Turning off this mode is, on the other hand, instantaneous - it will immediately turn off all existing file watch processes and outstanding refresh actions.

Known limitations: Staging and comitting changes does not produce any file change events of its own, if you use treemacs-git-integration you still need to do a manual refresh to see your files’ face go from ‘changed’ and ‘untracked’ to ‘unchanged’ after a commit.

Session Persistence

To persist treemacs state beyond emacs’ shutdown treemacs offers integration with the builtin desktop-save-mode and the persp-mode's layout saving. This integration shoud work out of the box and require zero setup and configuration (aside from the option to turn it off with treemacs-never-persist).

The persisted state is saved under user-emacs-directory/.cache/treemacs-persist. The exact file location is saved in the variable treemacs--persist-file.

Persistence by means of frameworks other than desktop-save-mode is likewise possible, but does require some additional work. To save treemacs’ current state treemacs-persist must be called. By default this would happen in desktop-save-hook, in its absence it must be invoked elsewhere. If all else fails emacs-kill-hook is a good candidate to run persistence.

State restoration should again work automatically. When the treemacs major mode is toggled in a completely empty buffer (this should normally never happen, as even an empty directory still contains a header) treemacs-restore will be called and the previously saved state (if available) will be restored. If this does not work it is of course still possible to invoke treemacs-restore manually when the right conditions are met.

Terminal Compatibility

When run in a terminal treemacs will fall back to a much simpler rendering system, foregoing its usual png icons and using simple + and - characters instead. Changes to the current rendering system are detected automatically - within some limits. The check for the change happens with treemacs’ functions which build or show/hide the treemacs buffer, namely treemacs(-projectile). treemacs(-projectile)-toggle and treemacs-refresh.

Tag View

Treemacs is able to display not only the file system, but also tags found in individual files. The tags list is sourced using emacs’ builtin imenu functionality, so all file types that emacs can generate an imenu index for are supported. Imenu cachses its result, so to avoid stale tag lists setting imenu-auto-rescan to t is recommended. Tags generated with the help of semantic-mode are likewise supported.

Tag view support is in an early beta release stage, and so (other than the increased likelyhood of bugs), it’s currently missing certain features:

  • It won’t look right in the terminal, there arent’t any terminal icons for tags yet.

Additional Packages

Next to treemacs itself you can optionally install:

treemacs-evil

Must be installed and loaded if you use evil. The keybindings and the cursor will not be setup propertĺy otherwise. It’ll also enable navigation navigation with j/k instead of n/p.

treemacs-projectile

Introduces projectile-centric counterparts for treemacs-launching commands, namely treemacs-projectile and treemacs-projectile-toggle. Also adds treemacs-create-header-projectile to be used as a value for treemacs-header-function.

Installation

Treemacs is available from MELPA. If you just want to quickly start using it you grab use the following use-package example, and customize it as needed (remove treemacs-evil if you don’t use it, customize the keybinds as needed, the example code uses keys derived from spacemacs).

Either way keep in mind that treemacs has no default keybinds for its globally callable initialization functions. Each user is supposed to select keybinds for functions like treemacs, treemacs-toggle and their projectile counterparts based on whatever they find convenient.

You can find an exhaustive overview of all functions, their keybinds and functions you need to bind yourself below.

(use-package treemacs
  :ensure t
  :defer t
  :config
  (progn
    (use-package treemacs-evil
      :ensure t
      :demand t)
    (setq treemacs-follow-after-init          t
          treemacs-width                      35
          treemacs-indentation                2
          treemacs-git-integration            t
          treemacs-collapse-dirs              3
          treemacs-silent-refresh             nil
          treemacs-change-root-without-asking nil
          treemacs-sorting                    'alphabetic-desc
          treemacs-show-hidden-files          t
          treemacs-never-persist              nil
          treemacs-is-never-other-window      nil
          treemacs-goto-tag-strategy          'refetch-index)

    (treemacs-follow-mode t)
    (treemacs-filewatch-mode t))
  :bind
  (:map global-map
        ([f8]        . treemacs-toggle)
        ("M-0"       . treemacs-select-window)
        ("C-c 1"     . treemacs-delete-other-windows)
        ("M-m ft"    . treemacs-toggle)
        ("M-m fT"    . treemacs)
        ("M-m f C-t" . treemacs-find-file)))
(use-package treemacs-projectile
  :defer t
  :ensure t
  :config
  (setq treemacs-header-function #'treemacs-projectile-create-header)
  :bind (:map global-map
              ("M-m fP" . treemacs-projectile)
              ("M-m fp" . treemacs-projectile-toggle)))

Configuration

Variables

Treemacs offers the following configuration options:

VariableDefaultDescription
treemacs-indentation2The number of spaces each level is indented in the tree.
treemacs-width35Width of the treemacs window.
treemacs-show-hidden-filestDotfiles will be shown if this is set to t and be hidden otherwise.
treemacs-header-functiontreemacs–create-headerThe function which is used to create the header string for treemacs buffers. Default options are treemacs--create-header and treemacs--create-header-projectile. Any function that takes the current root path and returns the header string may be used.
treemacs-git-integrationnilWhen t use different faces for files’ different git states.
treemacs-follow-after-initnilWhen t follow the currently selected file after initializing the treemacs buffer, regardless of treemacs-follow-mode setting.
treemacs-change-root-without-askingnilWhen t don’t ask to change the root when calling treemacs-find-file.
treemacs-never-persistnilWhen t treemacs will never persist its state.
treemacs-sortingalphabetic-ascIndicates how treemeacs will sort its files and directories. Files will still always be shown after directories. Valid values are alphabetic-asc, alphabetic-desc, size-asc, size-desc, mod-time-asc, mod-time-desc.
treemacs-ignored-file-predicates(treemacs–std-ignore-file-predicate)List of predicates to test for files ignored by Emacs. Ignored files will never be shown in the treemacs buffer (unlike dotfiles) whose presence is controlled by treemacs-show-hidden-files). Each predicate is a function that takes the filename as its only argument and returns t if the file should be ignored and nil otherwise. A file whose name returns t for any function in this list counts as ignored. By default this list contains treemacs--std-ignore-file-predicate which filters out ‘.’, ‘..’, Emacs’ lock files as well as flycheck’s temp files, and therefore should not be directly overwritten, but added to and removed from instead.
treemacs-file-event-delay5000How long (in milliseconds) to collect file events before refreshing. When treemacs receives a file change notification it doesn’t immediately refresh and instead waits treemacs--file-event-delay milliseconds to collect further file change events. This is done so as to avoid refreshing multiple times in a short time. See also treemacs-filewatch-mode.
treemacs-goto-tag-strategyrefetch-indexInidicates how to move to a tag when its buffer is dead. The tags in the treemacs view store their position as markers pointing to a buffer. If that buffer is killed, or has never really been open, as treemacs kills buffer after fetching their tags if they did no exist before, the stored positions become stale, and treemacs needs to use a different method to move to that tag. This variale sets that method. Its possible values are: refetch-index: Call up the file’s imenu index again and use its information to jump. call-xref: Call xref-find-definitions to find the tag. issue-warning: Just issue a warning that the tag’s position pointer is invalid.
treemacs-default-actionsOpen/close dirs & tag sections, treemacs-visit-node-no-split for files & tagsDefines the behaviour of treemacs-visit-node-default-action. Each alist element maps from a button state to the function that should be used for that state. The list of all possible button states is defined in treemacs-valid-button-states. Possible values are all treemacs-visit-node-* functions as well as treemacs-push-button for simple open/close actions. To keep the alist clean changes should not be made directly, but with treemacs-define-default-action.
treemacs-collapse-dirs0When > 0 treemacs will collapse directories into one when possible. A directory is collapsible when its content consists of nothing but another directory. The value determines how many directories can be collapsed at once, both as a performance cap and to prevent a too long directory names in the treemacs view. To minimize this option’s impact on display performace the search for directories to collapse is done asynchronously in a python script and will thus only work when python installed. The script should work both on python2 and 3.
treemacs-silent-refreshnilWhen non-nil a completed refresh will not be announced with a message. This applies both to manuall refreshing as well as automatic (due to e.g. treemacs-filewatch-mode).
treemacs-is-never-other-windownilWhen non-nil treemacs will never be used as other-window. This can prevent other packages from opening other buffers in the treemacs window. It also means treemacs is never selected by calls to other-window.
treemacs-positionleftPosition of treemacs buffer. Valid values are left, right.

Faces

Treemacs defines and uses the following faces:

FaceInherits fromDescription
treemacs-directory-facefont-lock-function-name-faceFace used for directories.
treemacs-file-facedefaultFace used for files.
treemacs-header-facefont-lock-constant-face (underlined & size 1.4)Face used for the treemacs header.
treemacs-term-node-facefont-lock-string-faceFace for directory node symbols used by treemacs when it runs in a terminal.
treemacs-git-*-facevarious font lock facesFaces used by treemacs for various git states.

Evil compatibility

To make treemacs get along with evil-mode you need to install and load treemacs-evil. It does not define any functions or offer any configuration options, making sure it is loaded is sufficient.

Custom Icons

If you have an icon you’d like to make use of in treemacs my preferred solution is very much for you to open a pull request (adding a new icon is a one-liner in treemacs-visuals.el) or an issue to let me know about a good icon I can add.

If that’s not possible or if you’d like to use something like all-the-icons.el (which isn’t used by default treemacs due to iconic fonts not being monospaced) treemacs offers the option to quickly define custom icons using the treemacs-define-custom-icon function.

It takes as its arguments an icon (a string) and a list of file extension to use the icon for. Already present icons for these extensions will be overwritten. The extensions are not case-sensitive and will be dowcased.

Note that treemacs has a very loose definition of what constitutes a file extension - it’s either everything past the last period, or just the file’s full name if there is no period. This makes it possible to match file names like ‘.gitignore’ and ‘Makefile’.

Example usage would look like this:

(with-eval-after-load "treemacs"
  (defvar treemacs-custom-html-icon (all-the-icons-icon-for-file "file.html"))
  (treemacs-define-custom-icon treemacs-custom-html-icon "html" "htm"))

Custom header function

The function which creates the header in treemacs is easily replaced (see the entry for treemacs-header-function in the section about configuration variables for details). To use your own custom header you just need to define a function that formats the header as you wish and then tell treemacs to use it:

(defun treemacs-header-with-brackets (current-root)
  (format "<%s>" (file-name-nondirectory current-root)))
(setq treemacs-header-function #'treemacs-header-with-brackets)

Keymap

Unbound functions

These functions are not bound to any keys by default. It’s left up to users to find the most convenient key binds. Additionally treemacs-refresh, treemacs-select-window and treemacs-find-file may also be called from outside the treemacs window and might therefore need their own global binding.

ActionDescription
treemacsOpen treemacs with current buffer’s directory as root. If the current buffer is not visiting any files use $HOME as fallback. If a prefix argument is given manually select the root directory.
treemacs-projectileOpen treemacs for the current projectile project. If not in a project do nothing. If a prefix argument is given select the project from among projectile-known-projects.
treemacs-toggleIf a treemacs buffer exists and is visible hide it. If a treemacs buffer exists, but is not visible bring it to the foreground and select it. If no treemacs buffer exists call treemacs.
treemacs-toggle-projectileIf a treemacs buffer exists and is visible hide it. If a treemacs buffer exists, but is not visible bring it to the foreground and select it. If no treemacs buffer exists call treemacs-projectile.
treemacs-find-fileFind and move point to PATH (or the current file) in the treemacs buffer. Expand folders if needed.
treemacs-select-windowSelect the treemacs window if it is visible. Call treemacs-toggle if it is not.
treemacs-delete-other-windowsSame as delete-other-windows, but will not delete the treemacs window.
treemacs-push-button-select-sortSame as treemacs-push-button, but the sorting function is chosen manually. The sort setting is active for only a single push, its effect will be undone on the next refresh.

Default keymap

By default Treemacs’s keymap looks as follows:

KeyActionDescription
?treemacs-helpful-hydraSummon the helpful hydra to show you the treemacs keymap.
j/ntreemacs-next-lineGoto next line.
k/ptreemacs-previous-lineGoto previous line.
htreemacs-uprootSwitch treemacs’ root directory to current root’s parent, if possible.
ltreemacs-change-rootUse currently selected directory as new root. Do nothing for files.
M-j/M-ntreemacs-next-neighbourSelect next node at the same depth as currently selected node, if possible.
M-k/M-ptreemacs-previous-neighbourSelect previous node at the same depth as currently selected node, if possible.
thtreemacs-toggle-show-dotfilesToggle the hiding and displaying of dotfiles.
twtreemacs-toggle-fixed-widthToggle whether the treemacs window should have a fixed width. See also treemacs-width.
tftreemacs-follow-modeToggle treemacs-follow-mode (see above).
tatreemacs-filewatch-modeToggle treemacs-filewatch-mode (see above).
wtreemacs-reset-widthReset the width of the treemacs window to treemacs-width. If a prefix argument is provided read a new value for treemacs-width first.
TABtreemacs-push-buttonPush the button in the current line. For directories, files and tag sections expand/close the button. For tags go to the tag definition via treemacs-visit-node-no-split.
mouse1treemacs-click-mouse1Do the same as treemacs-push-button when mouse1-clicking on an line.
g/r/grtreemacs-refreshRefresh and rebuild the treemacs buffer.
dtreemacs-deleteDelete node at point. A delete action must always be confirmed. Directories are deleted recursively.
cftreemacs-create-fileCreate a file.
cdtreemacs-create-dirCreate a directory.
Rtreemacs-renameRename the currently selected node. Reload buffers visiting renamed files or files in renamed direcotries.
utreemacs-goto-parent-nodeSelect parent of selected node, if possible.
qtreemacs-toggleHide/show an existing treemacs window.
Qtreemacs-kill-bufferKill the treemacs buffer.
RETtreemacs-visit-node-default-actionRun the action defined in treemacs-default-actions for the current button.
ovtreemacs-visit-node-vertical-splitOpen current file or tag by vertically splitting next-window. Stay in current window with a prefix argument.
ohtreemacs-visit-node-horizontal-splitOpen current file or tag by horizontally splitting next-window. Stay in current window with a prefix argument.
oo/RETtreemacs-visit-node-no-splitOpen current file or tag, performing no split and using next-window directly. Stay in current window with a prefix argument.
oaatreemacs-visit-node-aceOpen current file or tag, using ace-window to decide which window to open the file in. Stay in current window with a prefix argument.
oahtreemacs-visit-node-ace-horizontal-splitOpen current file or tag by horizontally splitting a window selected by ace-window. Stay in current window with a prefix argument.
oavtreemacs-visit-node-ace-vertical-splitOpen current file or tag by vertically splitting a window selected by ace-window. Stay in current window with a prefix argument.
oxtreemacs-visit-node-in-external-applicationOpen current file according to its mime type in an external application. Linux, Windows and Mac are supported.
yytreemacs-yank-path-at-pointCopy the absolute path of the node at point.
yrtreemacs-yank-rootCopy the absolute path of the current treemacs root.

Working With The Code Base

If you’ve need to delve into treemacs’ code base check out the wiki for some general pointers.

Dependencies

  • emacs >= 25.1
  • f.el
  • s.el
  • dash
  • cl-lib
  • ace-window
  • pfuture
  • hydra
  • (optionally) evil
  • (optionally) projectile
  • (optionally) winum