- Workflow still centered around native functionality.
- Highly customizable look and feel thanks to custom formatters and an extensive range of options.
- Provides useful shortcuts for setting marks automatically without having to pick a letter by yourself.
- Change and delete marks more effectively directly from the interactive mark list window.
- Delete and "resurrect" buffers directly from the buffer list window.
- Pin important buffers and quickly access them even from outside the buffer list window.
You can install the plugin with your favorite plugin manager.
The plugin provides a couple of basic commands to get you started:
:Marksto open up a nicely formatted window with all defined[a-z][A-Z]marks:Jumpsto open up a window with the jump list:Buffersto open up a window with the buffer list
Commands are not automatically created, so in order to create them you need to call the usual setup function and set the create_commands option. As you can see below, you can even change their default names if you wish to do so. If you prefer using mappings instead, skip ahead to the next section.
require("vessel").setup({
create_commands = true,
commands = { -- not required unless you want to customize each command name
view_marks = "Marks",
view_jumps = "Jumps",
view_buffers = "Buffers"
}
})Calling the setup function is not required for using the plugin as internal <plug> mappings are automatically set up for you.
| Plug Mapping | Action |
|---|---|
<plug>(VesselViewMarks) |
Show all global (uppercase) and local marks (lowercase) grouped by file. |
<plug>(VesselViewLocalMarks) |
Show only local (lowercase) marks. |
<plug>(VesselViewGlobalMarks) |
Show only global (uppercase) marks. |
<plug>(VesselViewBufferMarks) |
Show both local and global marks in the current file. |
<plug>(VesselViewExternalMarks) |
Show only global marks belonging to other files. |
<plug>(VesselSetLocalMark) |
Automatically set/unset a local mark on the current line. |
<plug>(VesselSetGlobalMark) |
Automatically set/unset a global mark on the current line. |
| Plug Mapping | Action |
|---|---|
<plug>(VesselViewJumps) |
Show the whole jump list. |
<plug>(VesselViewLocalJumps) |
Show only jumps inside the current file. |
<plug>(VesselViewExternalJumps) |
Show only jumps outside the current file. |
| Plug Mapping | Action |
|---|---|
<plug>(VesselViewBuffers) |
Show the buffer list. Only normal listed buffers will be displayed. |
<plug>(VesselPinnedNext) |
Switch to the next buffer in the pinned list (relative to buffer %). See Pinned Buffers. |
<plug>(VesselPinnedPrev) |
Switch to the previous buffer in the pinned list (relative to buffer %). See Pinned Buffers. |
Both <plug>(VesselPinnedNext) and <plug>(VesselPinnedPrev) will fall back respectively to the first and last buffer in the pinned list in case the current buffer is not in the pinned list as well. See also option buffers.wrap_around.
Note
- A normal buffer is a buffer with the
buftypeoption empty. - Unlisted buffers can be toggled later directly inside the buffer list window.
Here how to use <plug> mappings in lua
vim.keymap.set("n", "gl", "<Plug>(VesselViewLocalJumps)")
vim.keymap.set("n", "gL", "<Plug>(VesselViewExternalJumps)")and vimscript
nnoremap m. <plug>(VesselSetLocalMark)
nnoremap m, <plug>(VesselSetGlobalMark)By default the mark list window shows all global and local marks grouped by the file they belong to. By default, marks are sorted by line number. You can change the default sorting with the marks.sort_marks option.
Once inside the window, the following mappings are available:
| Mapping | Action |
|---|---|
q, <ESC> |
Close the floating window. |
<C-J> |
Move to the next mark group (path header). |
<C-K> |
Move to the previous mark group (path header). |
d |
Delete the mark under cursor. Pressing d on the file path will delete all of its marks. |
l, <CR> |
Jump to the mark (or path) under cursor. |
o |
Jump to the mark under cursor (does not change the jump list). |
v |
Open the mark under cursor in a vertical split. |
V |
Open the mark under cursor in a vertical split with (does not change the jump list). |
s |
Open the mark under cursor in a horizontal split. |
S |
Open the mark under cursor in a horizontal split (does not change the jump list). |
t |
Open the mark under cursor in a new tab. |
T |
Open the mark under cursor in a new tab (does not change the jump list). |
<SPACE> |
Cycle sorting type. It will be remembered once you close and reopen the window. |
m{a-zA-Z} |
Change the mark under cursor. |
'{a-z-A-Z} |
Jump directly to a mark. |
? |
Show help message. |
By default the jump list window shows the entire jump list with jumps spanning multiple files. Jumps are displayed top to bottom, with the most recent jump being on top. The cursor is automatically placed on the current position in the jump list. On the left column you can see jump positions relative to the current one. You can use those relative position as a count to <c-o> and <c-i>.
Once inside the window, the following mappings are available:
| Mapping | Action |
|---|---|
l, <CR> |
Jump to the line under cursor. |
q, <ESC> |
Close the floating window. |
C |
Clear the entire jump list. |
<C-O> |
Move backwards in the jump list (towards the bottom). |
<C-I> |
Move forward in the jump list (towards the top). |
? |
Show help message. |
Tip
As a count to <C-O> and <C-I>, you can use the relative number displayed on the left column.
Note
The relative positions you see by default on the left column are not the real relative positions you would use as a count outside the jump list window. This is because the list can be filtered and you could potentially see big gaps between these positions otherwise.
By default both mark and jump lists have the preview window enabled. In this window you can see context of the line under cursor. To disable this feature you can use respectively the options marks.preview and jumps.preview. For the buffer list the preview window is disabled by default but it can be enabled with the option buffers.preview. The option window.gravity controls how both the windows are positioned relative to each other.
See also Preview Window Options.
By default the buffer list window shows all the normal buffers with the listed option set. Showing unlisted buffers can be toggled with the press of a key. By default buffers are sorted by their directory name. Head over to the configuration section and look for the sort_buffers option to see how you can customize buffer sorting.
Once inside the window, the following mappings are available:
| Mapping | Action |
|---|---|
q, <ESC> |
Close the floating window. |
l, <CR> |
Edit the buffer under cursor. Takes a count. Also expand a collapsed directory in tree mode. |
t |
Edit the buffer undeer cursor in a new tab. |
s |
Edit the buffer under cursor in a horizontal split. |
v |
Edit the buffer under cursor in a vertical split. |
d |
Delete the buffer under cursor. Fails if there is any unsaved change. Executes :bdelete on the buffer. |
D |
Force delete the buffer under cursor. All unsaved changes will be lost! Executes :bdelete! on the buffer. |
w |
Wipe buffer under cursor. Fails if there is any unsaved change. Executes :bwipeout on the buffer. |
W |
Force wipe the buffer under cursor. All unsaved changes will be lost! Executes :bwipeout! on the buffer. |
<SPACE> |
Cycle sorting type. It will be remembered once you close and reopen the window. |
a |
Toggle showing unlisted buffers (Buffers on which you executed :bdelete). |
p |
Pin/unpin the buffer under cursor. |
P |
Add to the buffer list the directory of the the buffer under cursor. See also directory handler. |
<C-X> |
Decrease the buffer position in the pinned list (moves the buffer up). |
<C-A> |
Increase the buffer position in the pinned list (moves the buffer down). |
g |
Create or delete group under cursor. See Buffer List Tree View. |
h |
Collapse the directory under cursor. If a buffer is selected, its parent directory will be collapsed. |
m |
Switch between "flat" and "tree" view modes. |
? |
Show help message. |
Note
Don't be afraid to delete buffers. You can still re-open them later by simply toggling unlisted buffers and re-editing them. This can help keeping the buffer list clean and tidy. On the other end, by wiping out the buffer you won't be able to reopen it directly from the buffer list and you'll need to use other means. See :help :bdelete and :help :bwipeout for the specific effects that each command has on buffers.
Tip
The mappings l or <cr> (buffers.mappings.edit) take a line number as a count. When the buffers.quickjump option is off and line numbers are shown, you can simply type the line number and then press l or <cr> to instantly edit the buffer on that line.
Pinned buffers are buffers that always stay at the top of the window and and are not influenced by the current sort type. Together they form the pinned list and are separated from other buffers by a separator.
This list is particularly useful when combined with the buffers.quickjump option. With this option enabled, you can quickly jump to the top [1-9] buffers just by pressing a number. Buffers positions follow the natural order of line numbers so, in order to select the right buffer, you need to either enable line numbers for the whole window with the option window.number or, if you only want to display numbers for the pinned list, the option buffers.show_pin_positions.
The order of buffers in the pinned list can be manually adjusted. See mappings buffers.pin_increase and buffers.pin_decrease.
Note
When enabled, the buffers.quickjump also works for unpinned buffers, but it's going to be less effective since you can't control the buffers positions unless they are in the pinned list.
You can switch to pinned buffers even from outside the buffer list window. Use the provided mappings <plug>(VesselPinnedNext) and <plug>(VesselPinnedPrev) or directly use the Buffers API. See also option buffers.wrap_around.
With tree view enabled, all buffers will be grouped and displayed as multiple directory trees, one for the current working directory, one for the home directory, and one for the root directory.
You can create as many additional separate trees as you want by pressing g on a directory or buffer. A new tree will be created for that directory and all the contained buffers will be grouped under that tree. Buffers will always be grouped by the most specific tree root path that matches their path. Note that if you press g on a file, a new tree will be created for its parent directory instead. You can delete a group by pressing g again on the group and buffers will be re-grouped automatically in other trees.
To keep things organized you also have the possibility to hide buffers by collapsing directories with h. You can then expand them again with l or <CR>.
Note
Pinned buffers will always be displayed on top as a flat list and won't be displayed along other buffers in directory trees.
Below all options specific for tree view:
| Option | Description |
|---|---|
| buffers.view | Set the default view: "flat" or "tree". |
| buffers.directories_first | Whether directories are ordered first or last (also works with flat view). |
| buffers.squash_directories | Squash directories that contain a single directory child. |
| buffers.mappings.toggle_view | Switch between flat and tree view. |
| buffers.mappings.toggle_squash | Toggle directory squashing. |
| buffers.mappings.collapse_directory | Collapse directories. |
| buffers.mappings.toggle_group | Create or delete tree groups. |
| buffers.mappings.move_group_down | Move the current tree group down. |
| buffers.mappings.move_group_up | Move the current tree group up. |
| buffers.mappings.prev_group | Move to the previous group. |
| buffers.mappings.next_group | Move to the next group. |
All API functions take a single optional opts table argument if you want to override the default options or every option you passed to the setup function.
| Function | Action |
|---|---|
vessel.view_marks(opts, filter_func) |
Show all global (uppercase) and local marks (lowercase). |
vessel.view_local_marks(opts) |
Show only local (lowercase) marks. |
vessel.view_global_marks(opts) |
Show only global (uppercase) marks. |
vessel.view_buffer_marks(opts) |
Show both local and global marks in the current file. |
vessel.view_external_marks(opts) |
Show only global marks belonging to different files. |
vessel.set_local_mark(opts) |
Automatically set/unset a local mark on the current line. |
vessel.set_global_mark(opts) |
Automatically set/unset a global mark on the current line. |
filter_func is a function used to filter out entries in the mark list. If the function returns false, the mark won't be displayed. The function takes two arguments:
marktable parameter representing the mark currently being filtered.contexttable parameter that contains information about the current window/buffer.
-- Example usage of a filter function to show only lowercase marks
vim.keymap.set("n", "gm", function()
require('vessel').view_marks({}, function(mark, context)
return string.match(mark.mark, "%l")
end)
end)| Function | Action |
|---|---|
vessel.view_jumps(opts, filter_func) |
Show the whole jump list. |
vessel.view_local_jumps(opts) |
Show only jumps inside the current file. |
vessel.view_external_jumps(opts) |
Show only jumps outside the current file. |
filter_func is a function used to filter out entries in the jump list. If the function returns false, the entry won't be displayed. The function takes two arguments:
jumptable parameter representing the jump entry currently being filtered.contexttable parameter that contains information about the current window/buffer.
-- Usage of a filter function to filter out jumps outside the current working directory
vim.keymap.set("n", "gL", function()
require('vessel').view_jumps({}, function(jump, context)
return vim.startswith(jump.bufpath, vim.fn.getcwd() .. "/")
end)
end)| Function | Action |
|---|---|
vessel.view_buffers(opts?, filter_func?) |
Show the buffer list. Only normal listed buffers will be displayed. |
vessel.get_pinned_next(bufnr?) |
Get buffer number of the buffer after bufnr (deafults to buffer %) in the pinned list. |
vessel.get_pinned_prev(bufnr?) |
Get buffer number of the buffer before bufnr (deafults to buffer %) in the pinned list. |
vessel.get_pinned_list() |
Get list of all buffer numbers in the pinned list. |
Note
- A normal buffer is a buffer with the
buftypeoption empty. - Unlisted buffers can be toggled later directly inside the buffer list window.
filter_func is a function used to filter out entries in the buffer list. If the function returns false, the buffer won't be displayed. The function takes two arguments:
buffertable parameter representing the buffer currently being filtered.contexttable parameter that contains information about the current window/buffer.
-- Example usage of a filter function to show only init.lua files
vim.keymap.set("n", "gm", function()
require('vessel').view_buffers({}, function(buffer, context)
return vim.fs.basename(buffer.path) == "init.lua"
end)
end)Throughout the API documentation we will refer to the context as something that contains information about the current window/buffer, that is the buffer currently being edited. It is a table object with the following keys:
bufnrCurrent buffer numberbufpathCurrent buffer full pathwininfoWindow information as returned byvim.fn.getwininfo()curposCursor position as returned byvim.fn.getcurpos()
The Mark object is table with the following keys:
markMark letter.lnumMark line number.colMark column number.lineLine on which the mark is positioned. Can benilwhen the mark is invalid (erris notnil).fileFile the mark belongs to.errThe mark has an error. Usually when file cannot be read or line does not exist anymore.
The Jump object is table with the following keys:
currentWhether this jump is the current position in the jump list.posPosition of the jump in the jump list.relposPosition of the jump relative to the current position in the jump list.bufnrBuffer number.bufpathBuffer full path.lnumJump line number.colJump column number.lineLine on which the jump is positioned. Can benilwhen the mark is invalid (erris notnil).errThe jump has an error. Usually when file cannot be read or line does not exist anymore.
The Buffer object is table with the following keys:
nrBuffer number.pathBuffer full path.pinposPosition in the pinned list.-1if buffer is not pinned.listedWhether the buffer is listed (visible in the buffer list).isdirectoryWhether the buffer is a directory.filetypeBuffer file type.modifiedWhether the buffer is modified/changed.changedtickNumber total changes made to the buffer.loadedWhether the buffer is loaded.hiddenWhether the buffer is hidden.lastusedWhen the buffer was last used (unix time).
Modes represent how you are jumping to the targeted location. They are defined as follows:
local util = require("vessel.util")
util.modes = {
BUFFER = 1,
SPLIT = 2,
VSPLIT = 3,
TAB = 4,
}The plugin defines User autocommands for certain events:
| Autocommand | Description |
|---|---|
User VesselBufferlistEnter |
After the window is opened but before any content is displayed in the buffer. |
User VesselBufferlistChanged |
Each time the buffer list window content changes. |
User VesselMarklistEnter |
After the window is opened but before any content is displayed in the buffer. |
User VesselMarklistChanged |
Each time the mark list window content changes |
User VesselJumplistEnter |
After the the window is opened but before any content is displayed in the buffer. |
User VesselJumplistChanged |
Each time the jump list window content changes. |
The example below shows how you can setup your own mappings in the buffer window with the help of custom autocommand events. Specifically, with the snippet below we try to open a file browser directly from the buffer list if we realize the buffer we're looking for is not in the list.
In the example below we pretend :FilExplorer is a real command that takes a path as argument and opens up a file browser for that path.
local vessel_aug = vim.api.nvim_create_augroup("VesselCustom", { clear = true })
vim.api.nvim_create_autocmd("User", {
group = vessel_aug,
-- use the custom event name as pattern
pattern = "VesselBufferlistEnter",
callback = function()
vim.keymap.set("n", ".", function()
-- grab the selected buffer entry
local sel = vim.b.vessel.get_selected()
-- get_selected() can return nil on an empty list
local path = sel and vim.fs.dirname(sel.path) or vim.fn.getcwd()
-- close the buffer list window with the provided function
vim.b.vessel.close_window()
-- open up the file explorer for the given path
vim.cmd("FileExplorer " .. vim.fn.fnameescape(path))
end, { buffer = true })
end,
})For each list, the plugin sets a buffer-local variable named vessel that can be accessed directly with vim.b.vessel. This variable is a table that contains with the following keys:
mapA table mapping every line to a mark, jump or buffer on that line.get_selectedFunction to retrieve the object on the current line. Can returnnilin case the list is empty.close_windowFunction to close the vessel window.
Important
This buffer-local variable is only available after the events VesselMarklistChanged, VesselJumplistChanged and VesselBufferlistChanged.
You can configure the plugin in different ways. The most obvious one is by calling the classic setup function. Calling this function is required if you want to create all predefined commands.
require("vessel").setup({
create_commands = true,
commands = {
view_marks = "Marks",
view_jumps = "Jumps"
view_buffers = "Buffers"
},
...
window = {
relativenumber = true
}
...
})The plugin also offers a more succinct way of setting options by providing an opt interface object
local vessel = require("vessel")
vessel.opt.highlight_on_jump = true
vessel.opt.window.max_height = 50
vessel.opt.marks.mappings.close = { "Q" }
vessel.opt.buffers.name_align = "right"The third way of setting options is by directly passing a table argument to API functions. These options will override anything you passed previously to the setup function or set via the opt interface object.
vim.keymap.set("n", "g", function()
require('vessel').view_jumps({ window = { max_height = 90 } })
end)Whether you use the setup function or set options via the opt interface, some basic type validation is alsways performed before options are actually being set. Specifically, if you decide to go the opt interface route, you should know that each option is validated the moment it is assigned. The moment you mistakenly try to assign a wrong value type to an option, you'll get a nice error message about what you need to fix, but everything will keep working and the option will retain its original value.
Control how much noisy the plugin is. One of vim.log.levels.
vessel.opt.verbosity = vim.log.levels.INFOSet cursorline vim option for a brief period of time after a jump for highlight_timeout milliseconds.
vessel.opt.highlight_on_jump = false
vessel.opt.highlight_timeout = 250Function executed after each jump. By default it just centers the cursor vertically unless vim.o.jumpotions is set to "view".
This function takes two parameters: mode and context.
vessel.opt.jump_callback = <function>Whether to create commands or not.
Note
You need to call the setup function to actually create commands
vessel.opt.create_commands = falseCustomize each command name.
vessel.opt.commands.view_marks = "Marks"
vessel.opt.commands.view_jumps = "Jumps"
vessel.opt.commands.view_buffers = "Buffers"Key used to show help message.
vessel.opt.help_key = "?"Controls the positioning of the main popup window. This option have different effects whether the preview window is enabled or not.
Without the preview window enabled:
centerThe window is centered vertically in the screen.topThe window is positioned towards the top of the screen. The max top position is determined by the window.max_height option. The more this option is closer to100(100%), the highest the window will be positioned.
With the preview window enabled:
center: When the preview window height is higher than the main popup window height, the latter will be vertically centered relative to the preview window.top: When the preview window height is higher than the main popup window height, the top margin of both windows will be aligned.
vessel.opt.window.gravity = "center"Control the maximum height of the popup window as a percentage of the nvim UI.
vessel.opt.window.max_height = 80Enable/disable cursorline neovim option in the window.
vessel.opt.window.cursorline = trueEnable/disable number neovim option in the window.
vessel.opt.window.number = falseEnable/disable relativenumber neovim option in the popup window.
vessel.opt.window.relativenumber = falseControl how the popup looks. These options are passed directly to the vim.api.nvim_open_win() function. See :help api-floatwin.
vessel.opt.window.options.style = "minimal"
vessel.opt.window.options.border = "single"Width of the popup window as a percentage of the Neovim UI. This can be either a function or a table with 2 numbers.
The first value is the popup width with no side preview popup displayed, the second value is the total width of both the main popup and the preview popup when the latter is displayed on the right side of the main popup.
vessel.opt.window.width = <function>Below the default implementation:
function popup_width()
return vim.o.columns < 120 and { 90, 90 } or { 75, 90 }
endControl how the preview popup looks. These options are passed directly to the vim.api.nvim_open_win() function. See :help api-floatwin.
vessel.opt.preview.options.style = "minimal"
vessel.opt.preview.options.border = "single"Debounce delay of the preview window, in milliseconds.
vessel.opt.preview.debounce = 40Whether to position the preview popup on the right side or on the bottom side of the main popup window. Can be either right or bottom.
vessel.opt.preview.position = "right"Width of the preview window as a percentage of window.width.
vessel.opt.preview.width = 50If the main popup width is less than this amount of columns, the preview popup is pushed to the bottom side of the main popup.
vessel.opt.preview.width_threshold = 80Minimum height of the preview window, expressed in lines.
vessel.opt.preview.min_height = 21Enable or disable preview window.
vessel.opt.marks.preview = trueThe pool of marks the plugin chooses from when automatically picking the letter for you.
vessel.opt.marks.locals = "abcdefghijklmnopqrstuvwxyz"
vessel.opt.marks.globals = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"Function used to sort groups. A group is a set of marks belonging to the same file.
vessel.opt.marks.sort_groups = function(a, b)
return a > b
endList of functions used to sort marks in the each groups. First item is the function used by default the first time you open the window.
See also marks.mappings.cycle_sort.
local sorters = require("vessel.config.sorters")
vessel.opt.marks.sort_marks = { sorters.marks.by_lnum, sorters.marks.by_mark }Available sorters are:
sorters.marks.by_lnumSort by mark line number.sorters.marks.by_markSort by mark letter (capitals first).
You can also define your own sorter function. The function must return two values:
- A function with the signature:
function(MarkA, MarkB) return boolean end - A description string that will be used to give feedback to the user when cycling between these function, or empty string for no feedback
Example function:
function sort_by_lnum()
local fn = function(a, b)
return a.lnum < b.lnum
end
return fn, "sorting by line number"
endControls the style of the file path header. Can be one of:
fullFull file pathshortShortest unique suffix among all pathsrelhomeRelative to the home directoryrelcwdRelative to the current working directory
Note
Has effect only when using default formatters.
vessel.opt.marks.path_style = "relcwd"Enable/disable unsetting a mark when trying to mark an alredy marked line.
vessel.opt.marks.toggle_mark = trueUse backtick instead of apostrophe for jumping to marks. See :help mark-motions.
vessel.opt.marks.use_backtick = falseMessage used when the mark list is empty.
vessel.opt.marks.not_found = "No marks found"Position the cursor on the first line of a mark group.
vessel.opt.marks.move_to_first_mark = truePosition the cursor on the closest mark relative to the current position in the buffer. If a mark is farther from the cursor than proximity_threshold lines, it won't be considered.
vessel.opt.marks.move_to_closest_mark = true
vessel.opt.marks.proximity_threshold = 50Force displaying the group header (file path) even when there is just one group.
Note
Has effect only when using default formatters.
vessel.opt.marks.force_header = falseDecorations used as prefix to each formatted mark. Last item is for last entries in each group.
Note
Has effect only when using default formatters.
vessel.opt.marks.decorations = { "├ ", "└ " }Show/hide mark column number.
Note
Has effect only when using default formatters.
vessel.opt.marks.show_colnr = falseStrip leading white spaces from lines.
Note
Has effect only when using default formatters.
vessel.opt.marks.strip_lines = trueFunctions used to format each mark / group header line. See Formatters section for more info.
vessel.opt.marks.formatters.mark = <function>
vessel.opt.marks.formatters.header = <function>Highlight groups used by default formatters.
Note
Have effect only when using the default formatters.
vessel.opt.marks.highlights.path = "Directory"
vessel.opt.marks.highlights.not_loaded = "Comment"
vessel.opt.marks.highlights.decorations = "NonText"
vessel.opt.marks.highlights.mark = "Keyword"
vessel.opt.marks.highlights.lnum = "LineNr"
vessel.opt.marks.highlights.col = "LineNr"
vessel.opt.marks.highlights.line = "Normal"Close the mark list window.
vessel.opt.marks.mappings.close = { "q", "<esc>" }Delete the mark under cursor.
vessel.opt.marks.mappings.delete = { "d" }Move to the next group header.
vessel.opt.marks.mappings.next_group = { "<c-j>" }Move to the previous group header.
vessel.opt.marks.mappings.prev_group = { "<c-k>" }Jump to the mark (or path) under cursor.
vessel.opt.marks.mappings.jump = { "l", "<cr>" }Jump to the mark under cursor (does not change the jump list).
vessel.opt.marks.mappings.keepj_jump = { "o" }Open the mark under cursor in a new tab.
vessel.opt.marks.mappings.tab = { "t" }Open the mark under cursor in a new tab (does not change the jump list).
vessel.opt.marks.mappings.keepj_tab = { "T" }Open the mark under cursor in a horizontal.
vessel.opt.marks.mappings.split = { "s" }Open the mark under cursor in a horizontal split (does not change the jump list).
vessel.opt.marks.mappings.keepj_split = { "S" }Open the mark under cursor in a vertical split.
vessel.opt.marks.mappings.vsplit = { "v" }Open the mark under cursor in a vertical split with (does not change the jump list).
vessel.opt.marks.mappings.keepj_vsplit = { "V" }Cycle sorting functions. See also marks.sort_marks.
vessel.opt.marks.mappings.cycle_sort = { "<SPACE>" }Enable or disable preview window.
vessel.opt.jumps.preview = trueDisplay real jump entries positions. There might be gaps when filters are applied to the list.
vessel.opt.jumps.real_positions = falseStrip leading white spaces from lines.
vessel.opt.jumps.strip_lines = falseFilter jump entries that point to empty lines.
vessel.opt.jumps.filter_empty_lines = trueMessage used when the jump list is empty.
vessel.opt.jumps.not_found = "Jump list empty"Prefix used for each formatted jump entry. First item is the line of the current position in the jump list.
Note
Has effect only when using the default formatter.
vessel.opt.jumps.indicator = { " ", " " }Show/hide jump entries column numbers.
Note
Has effect only when using the default formatter.
vessel.opt.jumps.show_colnr = falseFunctions used to format each jump entry line. See Formatters section for more info.
vessel.opt.jumps.formatters.jump = <function>Mapping used to move backwards in the jump list (to the bottom of the window). Takes a count.
vessel.opt.jumps.mappings.ctrl_o = "<c-o>"Mapping used to move forwards in the jump list (to the top of the window). Takes a count.
vessel.opt.jumps.mappings.ctrl_i = "<c-i>"Jump to the entry under cursor.
vessel.opt.jumps.mappings.jump = { "l", "<cr>" }Close the jump list window.
vessel.opt.jumps.mappings.close = { "q", "<esc>" }Clear the jump list. Executes :clearjumps.
vessel.opt.jumps.mappings.clear = { "C" }Highlight groups used by the default formatter.
vessel.opt.jumps.highlights.indicator = "Comment"
vessel.opt.jumps.highlights.pos = "LineNr"
vessel.opt.jumps.highlights.current_pos = "CursorLineNr"
vessel.opt.jumps.highlights.path = "Directory"
vessel.opt.jumps.highlights.lnum = "LineNr"
vessel.opt.jumps.highlights.col = "LineNr"
vessel.opt.jumps.highlights.line = "Normal"
vessel.opt.jumps.highlights.not_loaded = "Comment"Enable or disable preview window.
vessel.opt.buffers.preview = falseBuffer list view mode. Can be one of:
flatBuffers displayed as a simple list.treeBuffers displayed as directory a tree. Buffers will be grouped in different directory trees depending on the most specific path prefix match: one group for the current working directory, one for the home directory and one for the root directory.
You can switch between the two view modes with buffers.mappings.toggle_view.
Note
In tree view mode, pinned buffers will still be displayed as a list.
vessel.opt.buffers.view = "flat"When navigating to next/previous buffers in the pinned list with the API or <plug> mappings, wrap around the list when reaching its start or end.
vessel.opt.buffers.wrap_around = trueMessage used when the buffer list is empty
vessel.opt.buffers.not_found = "Buffer list empty"Label used for unnamed buffers.
vessel.opt.buffers.unnamed_label = "[no name]"Remap numbers [1-9] in normal mode to quickly edit the 9 buffers at the top of the window.
vessel.opt.buffers.quickjump = trueFunction called for buffers that are directories. By default assumes Netrw is enabled (vim.g.loaded_netrwPlugin == 1) and simply executes :edit command on the buffer. Can be useful to open up your favorite file explorer or fuzzy finder.
This function takes two parameters: path and context.
vessel.opt.buffers.directory_handler = <function>List of functions used to sort buffers. First item is the function used by default the first time you open the window.
See also buffers.mappings.cycle_sort.
local sorters = require("vessel.config.sorters")
vessel.opt.buffers.sort_buffers = {
sorters.buffers.by_path,
sorters.buffers.by_basename,
sorters.buffers.by_lastused,
sorters.buffers.by_changes,
}Available sorters are:
sorters.buffers.by_pathSort by buffer directory.sorters.buffers.by_basenameSort by buffer basename.sorters.buffers.by_lastusedSort by last time the buffer was used/visited.sorters.buffers.by_changesSort by the total number of changes made in the buffer.
You can also define your own sorter function. The function must return two values:
- A function with the signature:
function(BufferA, BufferB) return boolean end - A description string that will be used to give feedback to the user when cycling between these function, or empty string for no feedback
Example sorter function:
function sort_by_basename()
local fn = function(a, b)
return vim.fs.basename(a.path) < vim.fs.basename(b.path)
end
return fn, "sorting by basename"
endFunction used to sort directories.
vessel.opt.buffers.sort_directories = function(path_a, path_b)
return path_a < path_b
endWhether to squash the directory structure when directories only have a single directory child.
This option can be toggled directly from the buffer list window with buffers.mappings.toggle_squash.
vessel.opt.buffers.squash_directories = trueExample of a non-squashed directory structure (/home/user is the root directory in this case, which is always displayed):
/home/user
└─ .dotfiles
└─ nvim
└─ lua
└─ init.lua
With buffers.squash_directories set to true.
/home/user
└─ .dotfiles/nvim/lua
└─ init.lua
Whether directories should be put first or last in the buffer list or tree.
vessel.opt.buffers.directories_first = falseWhether line numbers are diplayed next to pinned buffers.
Useful when line numbers are not enabled for the window or the buffers.quickjump option is enabled.
Note
Has effect only when using the default formatter.
vessel.opt.buffers.show_pin_positions = trueBuilding blocks of the tree in tree view mode. All must have equal length.
Note
Has effect only in tree view mode.
vessel.opt.buffers.tree_lines = { "│ ", "├─ ", "└─ ", " " }Icons used besides directory names in tree view mode. First item is for open directories, while the second item is for collapsed directories.
Note
Has effect only in tree view mode.
vessel.opt.buffers.tree_folder_icons = { "", "" }Character used as separator between the pinned list and the rest of the buffers. Use an empty string to hide the separator. Its color is controlled by the option buffers.highlights.pin_separator.
See also Pinned Buffers.
vessel.opt.buffers.pin_separator = "─"Character used as separator between different tree groups. Use an empty string to hide the separator.
The color can be set with the option buffers.highlights.group_separator.
vessel.opt.buffers.group_separator = "─"How to align the buffer name. Can be one of:
leftLeft alignmentrightRight alignmentnoneNo alignment
Note
Has effect only when using the default formatter.
vessel.opt.buffers.bufname_align = "left"Buffer name style. Can be one of:
basenameBuffer base nameuniqueShortest unique suffix among all pathshideHide bufname completely
Note
Has effect only when using the default formatter.
vessel.opt.buffers.bufname_style = "unique"Buffer path style. Can be one of:
fullFull file pathshortShortest unique suffix among all pathsrelhomeRelative to the home directoryrelcwdRelative to the current working directoryhideHide buffer path completely
Note
Has effect only when using the default formatter.
vessel.opt.buffers.bufpath_style = "relcwd"Spacing between formatted items (line numbers, bufname and bufpath).
Note
Has effect only when using the default formatter.
vessel.opt.buffers.formatter_spacing = " "Cycle sorting functions. See also buffers.sort_buffers.
vessel.opt.buffers.mappings.cycle_sort = { "<space>" }Toggle pinned status on the buffer under cursor.
See also Pinned Buffers.
vessel.opt.buffers.mappings.toggle_pin = { "p" }Create new tree group for the parent directory of the selected buffer or directly for the selected directory.
Note
Has effect only in tree view mode.
vessel.opt.buffers.mappings.toggle_group = { "g" }Toggle squash option option.
Note
Has effect only in tree view mode.
vessel.opt.buffers.mappings.toggle_squash = { "_" }Toggle buffers.view option. Switch between "flat" and "tree" view.
vessel.opt.buffers.mappings.toggle_view = { "m" }Collapse directory under cursor and hide all of its content. If a buffer is selected instead, its parent directory will be collapsed. To expand a collapsed directory, use buffer.mappings.edit
Note
Works only in tree view mode.
vessel.opt.buffers.collapse_directory = { "h" }Add to the buffer list the directory of the buffer under cursor.
vessel.opt.buffers.mappings.add_directory = { "P" }Move current group up.
vessel.opt.buffers.mappings.move_group_up = { "{" }Move current group down.
vessel.opt.buffers.mappings.move_group_down = { "}" }Move to previous group.
vessel.opt.buffers.mappings.prev_group = { "[" }Move to next group.
vessel.opt.buffers.mappings.next_group = { "]" }Move the buffer under cursor down in the pinned list. The buffer is pinned if not already in the pinned list.
Note
Incrementing the position essentially moves the buffer down.
See also Pinned Buffers.
vessel.opt.buffers.mappings.pin_increment = { "<c-a>" }Move the buffer under cursor up in the pinned list. The buffer is pinned if not already in the pinned list.
Note
Decrementing the position essentially moves the buffer up.
See also Pinned Buffers.
vessel.opt.buffers.mappings.pin_decrement = { "<c-x>" }Toggle unlisted buffers.
vessel.opt.buffers.mappings.toggle_unlisted = { "a" }Edit the buffer under cursor.
vessel.opt.buffers.mappings.edit = { "l", "<cr>" }Edit the buffer under cursor in a new tab.
vessel.opt.buffers.mappings.tab = { "t" }Edit the buffer under cursor in a horizontal split.
vessel.opt.buffers.mappings.split = { "s" }Edit buffer under cursor in a vertical split.
vessel.opt.buffers.mappings.vsplit = { "v" }Executes :bdelete on the buffer under cursor (fails with unsaved changes).
Basically sets the buffer unlisted. The buffer can then be re-openend by toggling unlisted buffers with buffers.mappings.toggle_unlisted.
vessel.opt.buffers.mappings.delete = { "d" }Executes :bdelete! on the buffer under cursor.
Caution
All unsaved changes will be lost!
vessel.opt.buffers.mappings.force_delete = { "D" }Executes :bwipeout buffer under cursor (fails with unsaved changes).
vessel.opt.buffers.mappings.wipe = { "w" }Executes :bwipeout! on the buffer under cursor.
Caution
All unsaved changes will be lost!
vessel.opt.buffers.mappings.force_wipe = { "W" }Close the buffer list window.
vessel.opt.buffers.mappings.close = { "q", "<esc>" }Functions used to format each buffer entry line. See Formatters section for more info.
vessel.opt.buffers.formatters.buffer = <function>,Function used to format each tree root directory.
Note
Used in tree view mode (buffers.view).
vessel.opt.buffers.formatters.tree_root = <function>Function used to format each tree directory node.
Note
Used in tree view mode (buffers.view).
vessel.opt.buffers.formatters.tree_directory = <function>Function used to format each tree buffer leave.
Note
Used in tree view mode (buffers.view).
vessel.opt.buffers.formatters.tree_buffer = <function>Highlight groups used by the default formatter.
vessel.opt.buffers.highlights.bufname = "Normal"
vessel.opt.buffers.highlights.bufpath = "Comment"
vessel.opt.buffers.highlights.unlisted = "Comment"
vessel.opt.buffers.highlights.directory = "Directory"
vessel.opt.buffers.highlights.modified = "Keyword"
vessel.opt.buffers.highlights.pin_position = "LineNr"
vessel.opt.buffers.highlights.pin_separator = "NonText"
vessel.opt.buffers.highlights.group_separator = "NonText"
vessel.opt.buffers.highlights.tree_root = "Keyword"
vessel.opt.buffers.highlights.tree_lines = "Comment"
vessel.opt.buffers.highlights.hidden_count = "Comment"Formatters are functions that let you customize how each line of the floating window is going to look.
All formatter functions take four arguments: the object being formatted, the context object, a meta table object, and a config table object. They all should return a string and an optional special table used by the plugin for setting up highlighting.
Most of the time you'll want to highlight specific parts of the formatted line. To make things easier the plugin provides a special format function you can call in order to automatically generate the correct return values. This utility function is very similar to the lua native string.format(), but the unlike it, our format function only accepts %s placeholders.
> format = require("vessel.util").format
> line, hl = format("%s : %s %s", {"foo", "Normal"}, "bar", {"baz", "LineNr"})
> print(line)
foo : bar baz
> vim.inspect(hl)
{ {
startpos = 1
endpos = 3,
hlgroup = "Normal",
}, {
startpos = 11
endpos = 13,
hlgroup = "LineNr",
} }local util = require("vessel.util")
-- Note: You can return nil from a header formatter to prevent
-- the line from being displayed in the list
local function header_formatter(path, meta, context, config)
local path = meta.suffixes[path]
return util.format("# %s", {path, "Directory"})
end
local function mark_formatter(mark, meta, context, config)
-- different colors for uppercase and lowercase marks
local hl = string.match(mark.mark, "%u") and "Blue" or "Red"
return util.format(" [%s] %s:%s %s",
{mark.mark, hl},
{mark.lnum, "LineNr"},
{mark.col, "LineNr"},
{mark.line, "Normal"}
)
endIn this more complex example we'll remove the header and display the file name on each line instead:
local util = require("vessel.util")
local vessel = require("vessel")
vessel.opt.marks.formatters.header = function(path, meta, context, config)
return
end
vessel.opt.marks.formatters.mark = function(mark, meta, context, config)
-- Makes sure each line number is vertically aligned
local lnum_fmt = "%" .. #tostring(meta.max_lnum) .. "s"
local lnum = string.format(lnum_fmt, mark.lnum)
local line, line_hl
if mark.line then
-- strips leading white spaces from each line
line = string.gsub(mark.line, "^%s+", "")
line_hl = "Normal"
else
-- if line is nil, it could mean the mark is invalid
line = mark.err or ""
line_hl = "Comment"
end
-- Display a vertically aligned file name
local path_fmt = "%-" .. meta.max_suffix .. "s" -- align file names
local path = string.format(path_fmt, meta.suffixes[mark.file])
return util.format(
" [%s] %s %s %s",
{ mark.mark, "Keyword" },
{ path, "Directory" },
{ lnum, "LineNr" },
{ line, line_hl }
)
endvessel.opt.marks.formatters.header = <function>Controls how each group header (file path) in the mark list is formatted. Takes the following four arguments:
| Parameter | Description |
|---|---|
path |
The full path being formatted. |
context |
Table containing information about the current window/buffer. See the context object section. |
config |
Table containing the complete configuration. |
meta |
Table containing additional contextual information. |
The meta table has the following keys:
| Key | Description |
|---|---|
groups_count |
Total number of groups. |
suffixes |
Table mapping each full path to its shortest unique suffix among all paths. |
max_suffix |
Maximum length among all suffixes above. |
vessel.opt.marks.formatters.mark = <function>Controls how each mark in the mark list is formatted. Takes the following four arguments:
| Parameter | Description |
|---|---|
mark |
The mark being formatted. See the mark object section. |
context |
Table containing information about the current window/buffer. See the context object section. |
config |
Table containing the complete configuration. |
meta |
Table containing additional contextual information. |
The meta table has the following keys:
| Key | Description |
|---|---|
pos |
Position of the mark being formatted in the group. |
is_last |
Whether the mark being formatted is last in the group. |
groups_count |
Total number of mark groups. |
max_lnum |
Highest line number among all mark groups. |
max_col |
Highest column number among all mark groups. |
max_group_lnum |
Highest line number in the current group. |
max_group_col |
Highest column number in the group. |
suffixes |
Table mapping each full path to its shortest unique suffix among all paths. |
max_suffix |
Max string length among all suffixes above. |
vessel.opt.jumps.formatters.jump = <function>Controls how each line of the jump list is formatted. Takes the following four arguments:
| Parameter | Description |
|---|---|
jump |
The jump being formatted. See the jump object section. |
context |
Table containing information about the current window/buffer. See the context object section. |
config |
Table containing the complete configuration. |
meta |
Table containing additional contextual information. |
The meta table has the following keys:
| Key | Description |
|---|---|
jumps_count |
Total number of jumps. |
current_line |
Line number of the jump being formatted. |
current_jump_line |
Line number of the current jump position. |
max_lnum |
Max line number among all jumps. |
max_col |
Max column number among all jumps. |
max_relpos |
Max relative number among all jumps. |
max_basename |
Max basename length among all jumps paths. |
suffixes |
Table mapping each full path to its shortest unique suffix among all paths. |
max_suffix |
Max string length among all suffixes above. |
vessel.opt.buffers.formatters.buffer = <function>Controls how each line of the buffer list is formatted. Takes the following four arguments:
| Parameter | Description |
|---|---|
buffer |
The buffer being formatted. See the buffer object section. |
context |
Table containing information about the current window/buffer. See the context object section. |
config |
Table containing the complete configuration. |
meta |
Table containing additional contextual information. |
The meta table has the following keys:
| Key | Description |
|---|---|
current_line |
Line number of the buffer being formatted. |
max_basename |
Max basename length among all buffer paths. |
suffixes |
Table mapping each full path to its shortest unique suffix among all paths. |
max_suffix |
Max string length among all suffixes above. |
pinned_count |
Number of pinned buffers. |
vessel.opt.buffers.formatters.tree_buffer = <function>Controls how each buffer is formatted in tree view. Takes the following four arguments:
| Parameter | Description |
|---|---|
buffer |
The buffer being formatted. See the buffer object section. |
context |
Table containing information about the current window/buffer. See the context object section. |
config |
Table containing the complete configuration. |
meta |
Table containing additional contextual information. |
The meta table has the following keys:
| Key | Description |
|---|---|
prefix |
Decoration lines of the tree line being rendered. |
root |
Tree root path. |
vessel.opt.buffers.formatters.tree_directory = <function>Controls how each directory is formatted in tree view. Takes the following four arguments:
| Parameter | Description |
|---|---|
path |
The full path of the directory being formatted. |
context |
Table containing information about the current window/buffer. See the context object section. |
config |
Table containing the complete configuration. |
meta |
Table containing additional contextual information. |
The meta table has the following keys:
| Key | Description |
|---|---|
prefix |
Decoration lines of the tree line being rendered. |
root |
Tree root path. |
rel_path |
Path relative to the tree root. |
collapsed |
Whether the current directory is collapse. |
hidden_buffers |
Number of hidden buffers when the directory is collapsed. |
squashed |
Whether the directory is squashed. |
squashed_path |
Relative path to the next buffer when the directory is squashed. |
vessel.opt.buffers.formatters.tree_root = <function>Controls how each root directory is formatted in tree view. Takes the following four arguments:
| Parameter | Description |
|---|---|
path |
The tree root path of the directory being formatted. |
context |
Table containing information about the current window/buffer. See the context object section. |
config |
Table containing the complete configuration. |
meta |
Table containing additional contextual information. |
The meta table has the following keys:
| Key | Description |
|---|---|
prefix |
Decoration lines of the tree line being rendered. |
This project is licensed under the MIT License. See the LICENSE.txt file for details.




