Tips, tricks, and traps
Changing the view and the preview
You’ve already seen these, in this section:
fzfm -c 'du -sk *|sort -rn|cut -f2' # sort descending by disk usage
# ...OR...
fzfm -c 'rg -l pattern' -p 'rg -C5 --color=always pattern {}'
If you use commands like these often, you may have added them to your bashrc or similar. Another way is to add them to your cmd_hist, because then you can invoke them from within fzfm. The equivalents for those are:
: key=:sddu sort desc by disk usage ; set view_cmd "du -sk *|sort -rn|cut -f2" # ^^^^ ----------------------- : key=:myrg run rg with given pattern ; set view_cmd "rg -l $query"; set preview_cmd "rg -C5 --color=always $query {}" # ^^^^ -------------------------
Notes:
-
These are run by typing
:sddu, or:myrg some_pattern, and hitting enter. -
The parts marked by
^^^^(i.e., “sddu”, “myrg”) are your choice; use whatever mnemonic you like. -
The parts marked by the dashes are optional (as you already know, from here).
-
The first example is no different from adding
: key=:sddu sort desc by disk usage ; du -sk *|sort -rn|cut -f2
to the view history file, which is probably a better way to do this when you don’t also need to set a preview command.
Traversing the directory history
Just hit alt-h and it will show you a directory history. (This comes straight from fish; fzfm is not doing anything special here!)
If you first type something in the query field before hitting alt-h, it is used to pre-filter the list,
Pause after running a command
To pause after running a command, just end the command with ; pause.
You can add an optional message, e.g., pause "remove these files?". The
actual message will have [Y/n] appended. By convention, this means that
hitting enter implies y (the capitalised option). If you want the
opposite, hit n then enter.
You can reverse this by adding [y/N] in your message, e.g., pause "update source archive? [y/N]". Now hitting enter implies n and y
needs to be explicitly typed.
If you don’t want every occurrence of the command to pause for you to eyeball the output, you can use this trick to check it only when needed:
- Hit
alt-sto spawn a shell. You will see the output of the previous command just above the prompt. If your terminal has scollback, you should be able to use that also. - When done, hit
ctrl-dto get back tofzfm.
Colon commands don’t have to start with a “:”
(but please do start them with a “:”!)
All the colon commands we showed so far, and most of them in the shipped
default, are like key=alt-up (fzf recognises them as “expect” keys), or like
key=:cp, which means you make your selection using TAB, then type in :cp
and hit enter.
But, strictly speaking, you don’t need to start these “colon commands” with a “:”. For example, the command list that comes with fzfm has these:
: key=... cd up 2 levels ; cd ../..
: key=.... cd up 3 levels ; cd ../../..
However, for your sanity I recommend you start them consistently with a special character that is unlikely to be part of most file names.
(Why? Here’s a hypothetical scenario: You have a command called “md” for
“mkdir” but you rarely use it so you forgot you had it. One day you filter on
your markdown files (‘md’), and hit enter. Instead of opening that markdown
file in your editor, it tries to run mkdir).
Internal variables used
The command history file as well as the config file (~/.config/fzfm/cmd_hist
and ~/.config/fzfm/config, respectively) make use of some “internal”
variables to do certain things, which are not adequately documented right now.
goto_item
query
view_cmd
preview_cmd
FZFM_DEF_VIEW_CMD
FZFM_DEF_PREVIEW_CMD
selection
fzfm_mode
fzfm_mode_keys
fzfm_yyddbuf
Their values can be seen by hitting ctrl-d. Note that if no files are currently in the copy/cut buffer, the last variable will not show up.
$query is a particularly interesting one; see next item. fzfm_yyddbuf is
for copy/cut-paste; see that section for more.
Using $query in a command
Some commands include the word “$query”. These commands cannot be run by
hitting ctrl-r or ctrl-v (as the case may be) and picking the command to run.
They must be run directly from the main window, because the word $query
is replaced by the arguments you give to the command in the fzf query
window.
(This is one of the quirks of using fzf!)
-
This example is from the “view” list:
: key=:/ run locate ; locate -b -e -i $queryThe way you run it is you just type
:/ foo, and it will locate all the files whose basenames containfooand will show them in the main window. Thefoois the argument you are supplying, which can only come from the fzf query field. -
This example is from the “commands” list:
: key=:sa SET alt dir ; test -d "$query" && set ALT_DIR $query || set ALT_DIR $PWDThis is interesting because the argument is optional. If you type just
:saand hit enter, it sets ALT_DIR to PWD. If you give it an argument, e.g.,:sa /tmp, then it will make that the ALT_DIR.
using your own (fish) functions
Fzfm’s command and view history files, and ad hoc commands, can only be one line. Of course, you can srill do complex things, such as this:
: key=f2 rename file/s ; if test $FZFM_SEL_COUNT -gt 1; vidir %f; else; echo "rename: %f"; mv -vi %f (read -P "to....: " -c %f); pause; end
But it does get hard to maintain.
Luckily, you can add any number of functions to ~/.config/fzfm/config.
Those are examples that work for me; no doubt you’ll have your own.
A note about the language: These functions must be written in fish; indeed the whole file is “source”-d into the fzfm script.
However, if a given function has no need to touch fzfm’s internal variables, then it can be written as an external command, in any language you like.
Enabling hidden files
If the first argument is -., then the default view (file list) command (ls -N --color=always) gets a -A added so that hidden files become visible.
Curiously, this is not part of the main fzfm script; it happens in the
user-customisable ~/.config/fzfm/config file :-)
Shipped command and features
The cmd_hist and view_hist files come with a lot of commands. Most of them are self-explanatory, so you really should go through them to see what is available.
But there are some shipped features that are complex enough to need extra documentation. This is a loose collection of those.
copy/cut and paste files
To copy/cut then paste files:
- Select one or more files.
- Hit alt-shift-y to copy, alt-shift-d to cut.
- Notice the 4th line of the header changes to something like
cp: 3 filesormv: 4 files.
- Notice the 4th line of the header changes to something like
- Go to the target directory and type
:pand hit enter.- This works across invocations of fzfm
- Answer “y” or just hit enter on the prompt that comes up
- If you realised this is not the right destination, answer “n”, go to
the right directory, and try
:pagain.
Some other notes:
- The yy/dd buffer will be cleared if any fzfm instance (of the same
$USER) hitsEscape. - The buffer will be cleared after a successful paste operation.
- It will not be cleared if you answered “n” to the prompt asking to confirm the paste.
- The buffer will persist until one of the above two events happen.
You can even quit and re-run fzfm, and the 4th line will still show the
cp: ...ormv: ...message as a reminder. - To see the current contents, hit ctrl-d. See the internal variables section for more on that.
The example we used in the Hotkeys vs colon-commands section showed the code for this, by the way.
Bookmarking a directory
Setting a bookmark: Just cd to the right place and press alt-b. A bookmark will get added.
Actually, it bookmarks the directory and the file currently selected. You’d be surprised how nice it is to jump to a directory and be positioned at a specific file than at the top! (If you select multiple files and hit alt-b, only the last one gets added.)
Jumping to a bookmark: alt-j will show a list of existing bookmarks to pick from.
If you type a string of at least two characters before hitting that hotkey, it is used to pre-filter the list. This is usually the same as typing the string after you hit alt-j, but there’s a subtle difference if you type two words before hitting alt-j: that second word is used to find the cursor target within the directory you’re jumping to.
E.g., I type lite ins, then hit Alt-J. The lite would match
/home/sitaram/code/gitolite in my bookmarks file (the ins would be ignored
for the purposes of finding the entry in the bookmark file). After that it
would look for a file within that directory that matched ins, which is
“install”, and the cursor would land on that file.
If, instead, I typed lite con then hit alt-j, it would show me an fzf picker
to choose between contrib (a directory) and CONTRIBUTING (a file), to land
the cursor on.
(Note that none of this happens if you type Alt-J first, then type lite ins; it’s just a normal fzf query then).
Editing bookmarks: The colon-command :be (for bookmark edit) will open
up the bookmark file in your $EDITOR. You can use this to delete bookmarks
if needed.
Jumping to a Vim mark: Remember up above we said “If you type a string of
at least two characters”? If you type just one character and hit Alt-J, it
will convert that to uppercase and open up vim on that bookmark. It expects
the EDITOR environment variable is set to vim or gvim (I prefer gvim for
this specific use case).
:rg
:rg pattern will set the view command to rg -l, and the preview command to rg -C5 so that you can see matching lines, with 5 lines of context, on the right side.
:cds
The “:cds” command is “stolen” from vifm, my other favourite file manager, but with a couple of twists.
The main purpose is to go from, say, fin/2024/tax, to fin/2025/tax, with a “ctrl-right” key (that’s the key mapped to _fzfm_cds :next in cmd_hist). This is done by incrementing the last sequence of digits in the directory name. Similarly, decrement instead of increment (mapped to ctrl-left in cmd_hist)
The other way to use it, is to replace “old” with “new” in the directory name to change directories. Fzfm has a few more tricks here though:
- allow partial names
- be relaxed about the exact new path being available
This works by replacing the last occurrence of “old”, and making any adjustments needed to get to the deepest directory that satisfies the change.
Example: if you have the following directories (notice the asymmetries; fin has 2022 but no 2025, and med/2023 has “reports” instead of “PDFs”):
fin/2022/PDFs/
fin/2023/PDFs/
fin/2024/PDFs/
medical/2023/reports/
medical/2024/PDFs/
medical/2025/PDFs/
Then, for each of them, here’s the result of running the command.
PWD COMMAND NEW PWD
fin/2022/PDFs/ :cds fin med medical
fin/2023/PDFs/ :cds fin med medical
fin/2024/PDFs/ :cds fin med medical/2024/PDFs
medical/2023/reports/ :cds med fin fin
medical/2024/PDFs/ :cds med fin fin/2024/PDFs
medical/2025/PDFs/ :cds med fin fin
Also notice we used “med” not “medical”, but even a partial name works.
Toggle reversing a list with alt-r
Alt-r will toggle between the list as your view_cmd presents it, and the reverse. This is achieved by the simple expedient of appending | tac to the command, if it is not already present, and removing it if it is.
(2026-10-08) Directory specific view/preview commands
As you know by now, Fzfm has any number of ways to view a file list. Sometimes you want a specific view always applied to a specific directory. Automatically, without having to type in any commands.
My actual use cases for this:
- For some directories, I’d like to see the most recently edited files at the top.
- Some directories (e.g., “fin”, “med”, …) contain subdirectories 2024, 2025, 2026, and so on. I’d like the listing to show up in reverse (i.e., 2026 at the top, because that’s where all the action is and it’s boring to scroll). (Also see footnote “year first” below).
- My student-project reviews directory has files named after the year, and apart from showing 2026 first, as above, I also want the preview to show a sorted list of second level markdown headings. Those are the names of the projects, and that’s more interesting in a preview than seeing several lines about whatever happens to be the first project in the file!
(You could argue that the second example is a special case of the first. But it’s not exactly the same. You could also argue that this is sheer laziness, to avoid typing two characters and hitting enter. I’d ask you to lookup “three great virtues of a programmer”, and remember I’m a perl guy at heart.)
Using this feature is simple. Just set whatever view and preview you want in the current directory, then type in :svp and hit Enter. That’s it. Next time you cd to this directory, the view will change.
Specifically, using the 3 examples above:
-
Type
:m, hit enter, type:svp, hit enter. (:mis pre-defined in the shippedview_histfile asls -t --color=always) -
Type
:r, hit enter, type:svp, hit enter. (alt-ris pre-defined in the shippedcmd_histfile; look it up) -
This is a bit more complicated. Type
:!set preview_cmd "rg --color=always '^##' {} | LANG=C sort -f"hit enter, check that the output is what you wanted, then type
:svpand hit enter.
Notes:
- You can do this any number of times for a given directory. The last setting is what will be in effect.
- There is no built in way to delete dir-specific view/preview for a given directory. You’d have to edit
~/.config/fzfm/dband manually delete three lines. (It’s a simple text file in the git-config format.) - If you would like to see the default view and/or preview, you can hit Escape. Escape toggles between the default view/preview and the directory-specific view/preview.
Important
One caveat: Directory specific view and preview commands will take effect only if the current view and preview commands are both set at the default. If the current view or preview are not defaults and you navigate to a directory which has directory specific view and preview commands defined for it, they will not take effect. The idea is that the “temporary/ad hoc” custom view you specify at runtime takes precedence over a “permanent” directory specific view/preview.
Footnotes
“year first”
What I actually do, for this, is that I have a simple fish function called year_first (this is not shipped with fzfm; it’s part of my personal fzfm config):
function year_first begin ls | rg '^20\d\d' | tac ls | rg -v '^20\d\d' end | xargs_ls end
and my view command for those directories is just years_first.
The xargs_ls function is shipped with fzfm, and it’s definition is
function xargs_ls # This is useful to pipe to at the end of any custom view command, and it # became tedious to apply it everywhere. xargs -r -d\n ls -U -d -N --color=always # Note especially the "-U" end