Skip to content

Latest commit

 

History

History
530 lines (389 loc) · 22.9 KB

vifm.mkd

File metadata and controls

530 lines (389 loc) · 22.9 KB

vifm -- file manager with vim-like key bindings

(last updated: March 2019)

This is not meant to be a how-to-use-vifm; the documentation on the website is pretty detailed, and comes in two slightly different forms.

Think of this as part "review" and part "tips and tricks" from my point of view. It could help you if you were considering switching to vifm, or even if you have already switched but need a more detailed perspective than you've found so far.

(Note that vifmrc generally means ~/.config/vifm/vifmrc. Also note that many parts of my vifmrc have been snarfed from other people, especially from the author's own vifmrc!)

features I really like

  • undo: I don't know if I've been living under a rock, but I've never seen a file manager with undo! Is this common?

    That said, after the initial excitement I found I don't make many mistakes anyway (hem hem!) but still, it's nice to know most things are undoable. (And of course there are things that cannot be undone, such as when content is overwritten. Also it's worth remembering that unlike vim, vifm cannot remember undo across sessions, so don't exit if you want to undo!)

  • tmux integration: While gvim is fine for local use, nothing beats tmux for remote sessions, and vifm happily supports tmux (and screen); just add the line screen! in your vifmrc.

    Now, when you hit enter to open a file in vim, it creates a new tmux window and runs vim in there. The window closes when you exit the editor. Very, very, cool, especially when you consider that this is something you simply cannot manually work-around if the fm does not support it!

    (There are a few exceptions; for instance see opening all the results of a :grep in a vim quickfix list, for good reasons, so just be aware of them and watch your tmux statusbar.)

  • synchronised registers: For many things that do not require permanent files, I tend to open a temporary directory (see cli-tips.mkd). I sometimes have several tmux windows with short-lived files in them, and occasionally I need to move or copy files between them. Granted, this is rare, but when it happens, it's a real pain and a major slowdown because those temporary pathnames are quite random!

    But by adding set syncregs=foo in my vifmrc, all my vifm sessions are automatically synchronised as far as register contents go. This makes it trivial to copy or move files from one session to another. Open up vifm in both places, hit yy on the source files, switch to the other tmux sessions, and hit either p (for copy) or P (upperase P, for move). Done.

  • custom commands are so much simpler than in my old file manager, I'm adding it here even though this should be a no-brainer for any fm.

    Here're 3 examples from my vifmrc:

    command! Tar tar cf %c.tar %c
    command! Tgz tar zcf %c.tgz %c
    command! Mkcd :mkdir! %a | cd %a
    

    User defined commands are run by the shell, by default. If you want them to be run by vifm, like in the last example above, start with a :.

    (You can look up %c, %C, %a and all the others in the section on "Command Macros". (Hint: ignore the second column, which has macros starting with %"; those are for Windows).

  • previewing directories with a custom command. You cannot imagine, when browsing a git repo, how nice it is to see a "git log" of the file or directory in the preview window. While most fm's will probably allow that for files, I haven't seen one that lets me do this for a directory. (Details later in this document.)

  • custom views (as vifm calls them) allow you to load a filelist generated by a program. I've always struggled with tasks like finding the most recent 10 files, the largest 20 files, or whatever, because I always had to get out of the file manager.

    Not anymore! See section on "finding files" later.

  • sorting display: whatever field you choose to sort by, that is the field you will see next to the filename!

    It has always bothered me that I can sort by inode change time (ctime), but I can't see that same ctime by default, and in some cases not even with a lot of fiddling.

    We all know that space is limited, so tying what is displayed next to the name, to what is chosen as the sort field, is just brilliant!

  • marks that get automatically saved. TBH, I suspect many file managers have this; I know my old one did.

things you'll see right away

  • 2-pane file manager, a la midnight commander. You can also make it show just one pane; I do that sometimes when the filenames are too long and I need to see them in full. Note that the other pane is still there, it's just not shown -- if you hit <Tab> you can still switch between them.

    Also, if you are used to Miller Columns, you can also use those, though I have not used them much with vifm.

    You can also have tabs, but I've never been much of a tab user, even in vim, so I can't say much about them. I just know that Vifm lets you have tabs in panes, as well as panes in tabs, which should cater to all tastes! (There are some screenshots on the official website.)

    If you're used to the file manager always starting in the current directory, instead of the directory you last visited, set the vifminfo option in vifmrc to a list of values that does not include savedirs (the default includes it).

  • To see hidden files, add set dotfiles to vifmrc. You can always toggle them off with za if you wish.

  • Symbolic links are a bit harder. The color might help, but to actually see the target the best option is to set a statusline containing %T somewhere. If symlinks are rare, the simplest way is to just hit enter on it and it will take you to the target. (Hit '' to go back).

    You also can temporarily change the sort to "link target" (hit :sort<cr> then T); you'll see all the targets on the right side of the pane.

  • Basic movements are all fairly similar to vim. I don't expect people who don't like vim to even get this far into this document, so I assume you're fine with that :)

    There are probably some subtle differences here and there, reflecting the fact that editing text is not precisely the same as managing files :) but by and large it's all the same.

    Example: when you use visual selection, lowercase v and uppercase V both seem to work, which is kinda obvious since the distinction that vim has, does not make sense here).

    Another example, searching for files is as you might expect; just use a "/". But the f command (which is a character search on the same line, in vi/vim), is a very convenient way to find the next file starting with the letter you type after f. This wraps around, so even if you start on a file at the bottom, and look for, say, 'a', it works. (Needless to say, , and ; also work as they do in vim, with the exception that vim does not wrap around when the last one is found).

basic file operations

  • Most basic operations work as you might expect. For example, to copy files, you might hit 3yy with the cursor on a file or directory, which will yank that and the next 2 objects. Then you go somewhere else (or hit TAB to go to the other pane) and hit p to paste them.

  • Deleting files comes in two flavours: dd to soft delete (moves them to some trash directory), and DD to permanently delete. The latter, of course, cannot be undone.

  • Moving files needs a bit of explanation. When you cut and paste files using dd then p, it first moves the files to trash when you type dd, and moves them again to the new destination when you hit p. If you're not comfortable with that, the correct way to do this is to use yy, then P (uppercase P). That will move the files in one shot.

    vifm can do this because it doesn't need to make the same distinction between uppercase and lowercase p that vim does.

  • bulk rename of files, especially if you have a pattern, is very easy. Just select the files, and hit cw (or :rename). Vim opens up with the filenames preloaded; change them how you like and save, and the rename happens. (Cyclic renames are also handled correctly).

    Even better, if you're able to express the rename as a pattern match and replace, you can use :s/foo/bar/. You can also use groups here (for example, :%s/^([0-9])-/0\1-/ will prefix an extra 0 to files whose names start with a single digit and a hyphen. This also takes /i and /g options.

other file operations

  • chmod is easy: just select the files and hit cp to get a menu; fill it in and hit enter. Or type :chmod u+x or something like that. You can add a -R or just use chmod! to get it to work recursively.

selecting files

  • t manually selects a file. (I suggest nmap <space> tj in your vifmrc so that you can just hit <space> to select a file and move to the next one).

    You can also select using :1,10sel and so on. Or you can use the search function: /foo<cr> will select all files containing foo. Even better, you can :select /foo|bar|baz/ to get multiple selections in one go. And then you can finetune that selection by using :unselect to shave a few files off from that selection!

    And you can combine any and all these methods however you want. (And that's not even talking about visual selection, which I won't talk about.)

  • You can save selections into registers, just like in vim, using for example "ayy, and restore the selection later using "ags (in this example using register a). And, just like in vim, uppercase register names (A-Z) accumulate entries, so you can make multiple selections using various criteria, and keep adding them to a register if you wish.

opening files

A quick note: %c is replaced by the name of the file under the cursor, %f by the names of all the files selected (if any; if not, it is the same as %c).

Some samples from my vifmrc:

" view manpages within downloaded software you're considering installing
filetype *.[1-8] man ./%c

" example showing two choices of app to use
filextype *.epub,*.pdf,*.ps {zathura}zathura %f %i &, okular %f %i &,
" you'll notice this one is using %f, because both zathura and okular can
" handle multiple arguments quite fine.

" example showing multiple lines.  The text within braces shows up in
" the popup, by the way.
filetype *.tar,*.tar.bz2,*.tbz2,*.tgz,*.tar.gz,*.tar.xz,*.txz
        \ {Yaay! Vim!}
        \ vim %c,
        \ {View contents}
        \ tar -tvf %c | less,
        \ {Extract to %D}
        \ tar -C %D -xf %c | less,
" Notice we're back to %c, because tar cannot handle more than one tar
" file at a time.

Here's how these multiple choices work. If you put the cursor on a PDF and type :f<space><tab> ('f' is short for 'file'), a list will pop up that contains your choices, mixed in with several others that the desktop environment has decided are appropriate apps for that filetype.

As a convenience, you can hit f<space>X<tab>, where X is one or more letter, then the list that shows up will be limited to applications that start with those letters. (E.g., on a PDF, with the settings above, I can hit f z<cr> to run zathura.)

previewing files

Before I get to the mundane stuff, let me get the cool stuff out of the way:

nnoremap l :if &previewprg == '' | set previewprg='git log --color -- %c 2>&1' | view! | else | set previewprg='' | view | endif<cr>

This little beauty shows me the git log output in the other pane once I hit l to toggle it on. It's easily one of the biggest wins for me with vifm, considering how often I review mine or other people's work in a git repo.

I'm sure many file managers can get you this for a file, but vifm allows previews for directories also to have some custom external command, and this covers both (after all, git log works fine on both files and directories).

(I must say, though, that vifm's rendering sometimes does not appear to clear the screen properly. I suspect if I leave out the "--color" things may improve, but YMMV).


Coming back to the boring stuff, here are a few samples from my vifmrc. Note that all of them use %c, since %f simply does not make sense in a preview command (which by definition operates on the file/directory under the cursor!)

" some really simple ones
fileviewer *.epub pandoc %c -t plain
fileviewer *.tar,*.tar.bz2,*.tbz2,*.tgz,*.tar.gz,*.tar.xz,*.txz tar -tvf %c
fileviewer *.odt,*.doc,*.docx unoconv -f text --stdout %c
fileviewer *.ods,*.xls,*.xlsx unoconv -f csv  --stdout %c

" view manpages within downloaded software you're considering installing
fileviewer *.[1-8] man ./%c | col -b
" notice the difference between the corresponding `filetype` setting; that
" one does not pipe to `col -b`

" if all else fails, just let the `highlight` command figure out what type
" of file it is and show it in nice colors.  (You may want to change
" "pablo" to something else)
fileviewer *[^/] highlight -O xterm256 --force -s pablo %c

image preview

Sadly, this is still a pain, because there are so many terminal emulators, and so much variation between them (and tmux/screen also muck up things a little too!) My solution:

fileviewer *.bmp,*.jpg,*.jpeg,*.png,*.gif,*.xpm,*.tif,*.tiff
        \ bgee %c,

The bgee script, which should be placed somewhere in your PATH, is just this:

#!/bin/bash

mediainfo "$1"
( ( geeqie --remote "$1" >/dev/null 2>&1 ) & )

Here's what's happening:

  • the mediainfo produces textual output that the preview pane can show. As far as vifm is concerned this is all that is happening.

  • the double fork runs geeqie with a --remote option. Now this is where the choice of image viewer makes a difference: you need one that (a) can be controlled remotely by running a command and (b) does not keep changing it's window size depending on the image it is currently displaying.

When the first image comes under the vifm cursor, geeqie opens up. I then resize it and move it to a corner of the screen, and continue using vifm as usual; images simply show up in that window in the corner whenever I come upon one in my vifm browsing. I can tell you this is a lot more predictable and repeatable than all the stupid w3m tricks I had been forced to pull in the past (and which often failed under tmux or screen anyway!)

mapping common tasks

Just like vim, vifm uses variants of the map command to customise your usage of it. Some samples from my vifmrc follow:

" quick way to select all files in the view
nnoremap VV :%select<cr>

" move the cursor in the other window
nnoremap <silent> J <space>j<space>
nnoremap <silent> K <space>k<space>

" shortcut to sort command
nnoremap S :sort<cr>

" toggle preview, and within preview toggle wrap
nnoremap w :view<cr>
nnoremap W :set wrap!<cr>

" grow/shrink window by 4 columns at a time
nnoremap < 4<c-w><
nnoremap > 4<c-w>>

" tag a file and move down to the next one
nmap <space> tj

" cd should be faster than it is :)
nnoremap cd :cd<space>

" make vimdiff as easy as possible, assuming a file of the same name
" exists in the other panel
nnoremap dv :!vimdiff %c %D/%c<CR>

" rename file; I inserts at the beginning, A appends at the end.
nnoremap I cw<c-a>
nnoremap A cw

The following examples are bit more involved.

Simulating ncdu: I came up with the following:

nnoremap ss :%select<CR>ga:set sort=-size<cr>

works great, but the actual size determinations happens in another thread so for large directories it may be best to wait a while and then sort by size again.

Faster deletion: As mentioned earlier, vifm lets you delete files either by moving them to trash, or permanently. By default, both operations require confirmation by typing "y". I prefer permanent deletion, and I also prefer the confirmation to be simpler, say just hitting "enter". To make it a bit harder, I map this to TWO strikes of the Delete key:

nnoremap <delete><delete>   :!ls -ald %f; echo -n "remove these files? "; vifm-pause; rm -rf %f<cr>

You'll see that I am reusing a small script that comes with vifm itself to do the pause and wait for the user to hit enter.

finding files

vifm comes with the ability to use the find command, but I hate the find command. (For a proper rant on find, see the comments in my sf command!)

Worse, vifm's way of helping you use the find command inserts -name somewhere, and although there's a way to get around that (see the help for findprg), I steer clear.

Luckily, vifm has also a locateprg option, which is far simpler. So here's what I do:

set locateprg="find | grep -i %a"
nnoremap // :locate<space>

Now, hitting // then some word, finds me all files whose path name (relative to current PWD) contains that word. Vifm shows this in some kind of an output window.

Here's where the fun starts. Hit b, and these files will be loaded in the active pane as a custom view. You can preview those files, delete them, edit them, whatever. When you're done, type gh to come back to the regular view.

finding the latest, or largest, files

I mentioned this up at the top, but here's how you get the largest N or newest N files.

command! xm :set viewcolumns=*{name}..,24{mtime}| InternalXM %a
command! xs :set viewcolumns=*{name}..,8{size}|   InternalXS %a
command! InternalXM find -type f -print0 | xargs -0 ls -tr | tail -%a | tac %U
command! InternalXS find -type f -print0 | xargs -0 ls -Sr | tail -%a | tac %U

You run this by typing :xs 10 to get the largest 10 files (s for 'size'), or, say, :xm 20 to get the newest 20 files (m for 'mtime'), and they will be loaded in a custom view.

The %a is replaced by the 10 or 20 or whatever you supplied. However, the %U is what makes all this work: it basically takes the command output and creates a "custom view" out of it! (I use %U instead of %u because I don't want vifm to needlessly sort it on some other key, when it's already sorted!)

You can make some adjustments to the options supplied to ls if you want, say, oldest files, or smallest files etc. (Do not be tempted to convert the tail to a head; that often results in a pipe error. Not harmful but ugly and disconcerting.)

finding text within files

Speaking for myself, I don't use any IDE, and vim has always been sufficient for my needs. A few plugins (like fugitive and gv), a couple of little functions and some maps, and it does a great job meeting the needs of "explore a new project's code" that I have.

As such, this part of vifm is not that exciting for me, but just for completeness I will describe it.

Using vifm's built-in grep command can be as simple as :grep pattern, or, if you wish, you can make it a bit more complex:

:grep -i -e pattern_1 -e pattern_2

(You can also use "grep -i -E 'pattern_1|pattern_2', but I think separate -e patterns looks cleaner).

What this does is open up a result window with all the matches. You can:

  • hit enter on any of the lines to be taken to that line in that file in vim. If you're running in tmux or screen, and you have screen! in your vifmrc, this will be opened in a new window.

    Before you do this, you can use /pattern_3 to find lines within this result set that contained pattern_3, if you wish to. They will be highlighted and you can use n or N to go travel back and forth between them. This helps to further finetune your search.

  • hit b and all the files that matched will be loaded into a custom view in vifm.

  • hit v and all the matches will be loaded into a vim quickfix list. From there it's between you and your mad vim skills!

    (As mentioned earlier, this is one of those cases where it's very hard to open this quickfix list in a new tmux window, so the current window will be used).

external commands

  • :!command runs the command, and when it is done, comes back to vifm pane (it pauses only if the exit code was non-zero).

  • :!!command runs the command, and pauses for you to hit enter when it is done

  • :!command & runs the command in the background.

ouch!

  • file filters: I find this tanatlisingly useful, but it is somewhat confusing.

    There are actually 3 kinds of filters. I suggest playing with it, or sticking to one type for now. Just to share my confusion, here's what they are:

    • =foo|bar|baz, called a "local" filter, shows only files that contain one of those strings in the filename

    • :filter foo|bar|baz show all except those files

    • :filter! foo|bar|baz (note the !) to show those files, making this the same as the =foo|bar|baz example, but these two are different filters!

    • selecting files however you want and pressing zf to filter them out. Even though you're manually choosing what to filter, this is called an "automatic filter".

    • there are various zX key maps to apply or remove various filters.

    My head hurts! This bit looks as if two differemt people came up with a solution, and both were accepted. Or rather, three in this case. It's not at all clear why you'd need all this complexity.

    I'll probably stick to the "=" filter, and if I need more, then I will use the select/unselect/manually select process I described earier, then :invert s, then zf. A suitable mapping can always be made if this gets frequently used.

    (Side note: the behaviour of :filter can be switched by dropping the f flag from cpoptions, should you wish to.)