- Treemacs - a tree layout file explorer for Emacs
- Quick Feature Overview
- Quick Start
- Detailed Feature List
- Installation
- Configuration
- Keymap
- Working With The Code Base
- Dependencies
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.
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: - 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
andtreemacs-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
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:
treemacs-follow
tries to be very specific about when it is run at all.- 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
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.
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.
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
.
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.
Next to treemacs itself you can optionally install:
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.
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
.
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)))
Treemacs offers the following configuration options:
Variable | Default | Description |
---|---|---|
treemacs-indentation | 2 | The number of spaces each level is indented in the tree. |
treemacs-width | 35 | Width of the treemacs window. |
treemacs-show-hidden-files | t | Dotfiles will be shown if this is set to t and be hidden otherwise. |
treemacs-header-function | treemacs–create-header | The 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-integration | nil | When t use different faces for files’ different git states. |
treemacs-follow-after-init | nil | When t follow the currently selected file after initializing the treemacs buffer, regardless of treemacs-follow-mode setting. |
treemacs-change-root-without-asking | nil | When t don’t ask to change the root when calling treemacs-find-file . |
treemacs-never-persist | nil | When t treemacs will never persist its state. |
treemacs-sorting | alphabetic-asc | Indicates 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-delay | 5000 | How 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-strategy | refetch-index | Inidicates 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-actions | Open/close dirs & tag sections, treemacs-visit-node-no-split for files & tags | Defines 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-dirs | 0 | When > 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-refresh | nil | When 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-window | nil | When 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-position | left | Position of treemacs buffer. Valid values are left , right . |
Treemacs defines and uses the following faces:
Face | Inherits from | Description |
---|---|---|
treemacs-directory-face | font-lock-function-name-face | Face used for directories. |
treemacs-file-face | default | Face used for files. |
treemacs-header-face | font-lock-constant-face (underlined & size 1.4) | Face used for the treemacs header. |
treemacs-term-node-face | font-lock-string-face | Face for directory node symbols used by treemacs when it runs in a terminal. |
treemacs-git-*-face | various font lock faces | Faces used by treemacs for various git states. |
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.
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"))
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)
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.
Action | Description |
---|---|
treemacs | Open 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-projectile | Open 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-toggle | If 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-projectile | If 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-file | Find and move point to PATH (or the current file) in the treemacs buffer. Expand folders if needed. |
treemacs-select-window | Select the treemacs window if it is visible. Call treemacs-toggle if it is not. |
treemacs-delete-other-windows | Same as delete-other-windows , but will not delete the treemacs window. |
treemacs-push-button-select-sort | Same 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. |
By default Treemacs’s keymap looks as follows:
Key | Action | Description |
---|---|---|
? | treemacs-helpful-hydra | Summon the helpful hydra to show you the treemacs keymap. |
j/n | treemacs-next-line | Goto next line. |
k/p | treemacs-previous-line | Goto previous line. |
h | treemacs-uproot | Switch treemacs’ root directory to current root’s parent, if possible. |
l | treemacs-change-root | Use currently selected directory as new root. Do nothing for files. |
M-j/M-n | treemacs-next-neighbour | Select next node at the same depth as currently selected node, if possible. |
M-k/M-p | treemacs-previous-neighbour | Select previous node at the same depth as currently selected node, if possible. |
th | treemacs-toggle-show-dotfiles | Toggle the hiding and displaying of dotfiles. |
tw | treemacs-toggle-fixed-width | Toggle whether the treemacs window should have a fixed width. See also treemacs-width. |
tf | treemacs-follow-mode | Toggle treemacs-follow-mode (see above). |
ta | treemacs-filewatch-mode | Toggle treemacs-filewatch-mode (see above). |
w | treemacs-reset-width | Reset the width of the treemacs window to treemacs-width . If a prefix argument is provided read a new value for treemacs-width first. |
TAB | treemacs-push-button | Push 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. |
mouse1 | treemacs-click-mouse1 | Do the same as treemacs-push-button when mouse1-clicking on an line. |
g/r/gr | treemacs-refresh | Refresh and rebuild the treemacs buffer. |
d | treemacs-delete | Delete node at point. A delete action must always be confirmed. Directories are deleted recursively. |
cf | treemacs-create-file | Create a file. |
cd | treemacs-create-dir | Create a directory. |
R | treemacs-rename | Rename the currently selected node. Reload buffers visiting renamed files or files in renamed direcotries. |
u | treemacs-goto-parent-node | Select parent of selected node, if possible. |
q | treemacs-toggle | Hide/show an existing treemacs window. |
Q | treemacs-kill-buffer | Kill the treemacs buffer. |
RET | treemacs-visit-node-default-action | Run the action defined in treemacs-default-actions for the current button. |
ov | treemacs-visit-node-vertical-split | Open current file or tag by vertically splitting next-window. Stay in current window with a prefix argument. |
oh | treemacs-visit-node-horizontal-split | Open current file or tag by horizontally splitting next-window. Stay in current window with a prefix argument. |
oo/RET | treemacs-visit-node-no-split | Open current file or tag, performing no split and using next-window directly. Stay in current window with a prefix argument. |
oaa | treemacs-visit-node-ace | Open current file or tag, using ace-window to decide which window to open the file in. Stay in current window with a prefix argument. |
oah | treemacs-visit-node-ace-horizontal-split | Open current file or tag by horizontally splitting a window selected by ace-window. Stay in current window with a prefix argument. |
oav | treemacs-visit-node-ace-vertical-split | Open current file or tag by vertically splitting a window selected by ace-window. Stay in current window with a prefix argument. |
ox | treemacs-visit-node-in-external-application | Open current file according to its mime type in an external application. Linux, Windows and Mac are supported. |
yy | treemacs-yank-path-at-point | Copy the absolute path of the node at point. |
yr | treemacs-yank-root | Copy the absolute path of the current treemacs root. |
If you’ve need to delve into treemacs’ code base check out the wiki for some general pointers.
- emacs >= 25.1
- f.el
- s.el
- dash
- cl-lib
- ace-window
- pfuture
- hydra
- (optionally) evil
- (optionally) projectile
- (optionally) winum