strata
Documentation menu

Plugins

Plugins are Lua 5.4 files. strata loads every *.lua file and every */init.lua in ~/.config/strata/plugins/ when it starts. List names under plugins.disabled to skip some.

-- ~/.config/strata/plugins/hello.lua
strata.map("g p", function(ctx)
  strata.cd(os.getenv("HOME") .. "/projects")
end, "Go to projects")
 
strata.command("hello", function(ctx, args)
  strata.notify("hello " .. args .. " from " .. ctx.cwd)
end, "Say hello")

Installing plugins

strata plugin installs plugins from git repositories. A repository holds one plugin, with init.lua at its root or in the folder --path names:

strata plugin add someone/strata-foo              # GitHub owner/repo; installed as "foo"
strata plugin add https://example.com/x/bar.git --ref v1.2
strata plugin add someone/plugins --path baz      # one plugin from a repository with several
strata plugin list                                # installed plugins and their commits
strata plugin update                              # newest commit of each plugin's branch
strata plugin remove foo

Each plugin is copied, without its git history, to ~/.config/strata/plugins/<name>/. ~/.config/strata/plugins.toml records its source and the commit installed. Keep that file with your dotfiles and run strata plugin install on another machine to get the same plugins at the same commits. --ref follows a branch, or pins a tag or commit; without it a plugin follows the repository's default branch. Restart strata to load new plugins. You need git for all of this.

A plugin runs with your permissions, like any program you install, so add only ones you trust.

Official plugins

PluginWhat it adds
gitBranch and change count in the top bar, a Git panel (g s) and :git <args>
bookmarksB to bookmark a directory, ' to jump, :bookmark-remove
archiveLists .7z and .rar archives in the preview (extracting and compressing are built in)
zoxidez to jump by query, Z to pick, and visited directories are recorded
protectRefuses to delete, move, rename or overwrite items tagged keep (option tag), and shows a lock column (option column = false hides it)

Enable them with plugins.enabled in the config. All but protect are on by default.

Options

If a plugin returns a table with a setup function, strata calls it with the plugin's options:

local M = {}
function M.setup(opts)          -- [plugins.options.hello] greeting = "hi"
  strata.statusline(function() return opts.greeting end)
end
return M

Context

Callbacks receive a ctx table:

FieldDescription
cwdDirectory of the focused panel
hoveredPath under the cursor, or nil
hovered_is_dirWhether hovered is a directory
selectedList of marked paths
panelFocused panel number (1-based)
viewfiles, dashboard, docker, nas or usage
themeActive theme
schemelocal, sftp, docker, archive, s3, webdav, ftp or rclone
iconsWhether Nerd Font icons are enabled
tagsTags of the hovered item
filterThe panel's filter text
listingWhat a flat listing shows (find *.log, flatten…), or nil
tabTab number (1-based)

API

Registration

FunctionDescription
strata.map(keys, fn(ctx), desc?)Bind a key sequence such as "g p" or "ctrl+e"
strata.command(name, fn(ctx, args), desc?)Add a :name command
strata.on(event, fn(ctx, data))React to an event
strata.statusline(fn(ctx) -> string?)Add a segment to the top bar
strata.panel{ name, title?, render = fn(ctx, w, h) -> lines }Draw a panel next to the file panels
strata.previewer{ ext = {...}, fn = fn(path, w, h) -> lines? }Preview these extensions; return nil to pass
strata.column{ name, width?, style?, fn = fn(entry) -> text?, style? }Add a column to the file list
strata.sort{ name, title?, fn = fn(entry) -> key }Add a sort order to the sort menu and :sort

Actions

FunctionDescription
strata.cd(path)Change directory
strata.action(name)Run a built-in action
strata.run(line)Run a command-palette line, e.g. "theme nord"
strata.notify(msg, level?)Show a message: "info", "warn" or "error"
strata.select(title, items, fn(item?))Show a fuzzy picker
strata.input(prompt, default?, fn(text?))Ask for text
strata.toggle_panel(name)Show or hide a plugin panel
strata.exec(cmd)Run an interactive command with the terminal handed over
strata.refresh()Reload the listings
strata.mark(paths, clear?)Mark these paths in the focused panel; clear drops other marks first
strata.show(title, paths)Show these paths as a flat list in the focused panel
strata.tag(paths, tag) / strata.untag(paths, tag?)Add or remove a tag (all tags without one); paths may be one path

Events

Handlers get the context and a data table describing what happened:

Eventdata fields
startup, quit, cd, pastenone
hoverpath: the item the cursor moved to
openpath: a file being opened
createpath, dir (true for a directory)
renamefrom, to; once per item, also for pattern and bulk renames
deletepaths, permanent (false when going to the trash)
tagpaths, tag ("" when every tag was removed), added
findtitle (find …, flatten, tag red…), count, truncated
job_donelabel, state (done, failed or cancelled), error
mountdevice, path: a removable drive was mounted
unmountdevice: a removable drive was ejected
viewview: files, dashboard, docker, nas or usage
tabtab: the tab switched to (1-based)
themename: the theme picked
layout_save, layout_loadname: the layout saved or opened (:layout, --layout, default_layout)
strata.on("rename", function(ctx, e)
  strata.notify(e.from .. " → " .. e.to)
end)

Refusing operations

before_* events fire before an operation starts. A handler cancels it by returning false (optionally followed by a reason) or { cancel = true, reason = "..." }, and the reason is shown.

Eventdata fields
before_deletepaths, permanent
before_renamepaths, to (new paths in the same order); also for pattern and bulk renames
before_copy, before_movepaths, dest
before_overwritepaths (items that would be replaced), sources, dest

Each also carries tags: a table from path to tags for the items in paths and every tagged item inside them.

strata.on("before_delete", function(ctx, e)
  for path, tags in pairs(e.tags) do
    for _, t in ipairs(tags) do
      if t == "keep" then return false, path .. " is tagged keep" end
    end
  end
end)

A handler that fails or runs longer than half a second is reported and cancels nothing. Undo and redo do not ask.

Columns and sort orders

Column and sort functions get an entry: path, name, is_dir, size, modified (epoch seconds or nil), ext and tags.

A column function returns the text and optionally a colour (muted, accent, error, warning, success, info, a tag colour, a colour name or #rrggbb). Cells are worked out only for rows on screen and kept until the listing changes. A sort function returns a key: numbers before text, nil last, ties by name; folders-first and reverse still apply (not in the tree view).

strata.column({ name = "lines", width = 6, fn = function(entry)
  if entry.is_dir or entry.size > 1e6 then return nil end
  local n = 0
  for _ in io.lines(entry.path) do n = n + 1 end
  return tostring(n), "muted"
end })
 
strata.sort({ name = "tagged", title = "Tagged first", fn = function(entry)
  return #entry.tags > 0 and 0 or 1
end })

Helpers

FunctionDescription
strata.shell(cmd, cwd?) -> stdout, code, stderrRun a command and capture its output
strata.which(program) -> boolWhether a program is on PATH
strata.mkdir(path) -> boolCreate a directory and its parents
strata.config_dir(), strata.data_dir()Where to read config and keep state
strata.version, strata.platformstrata's version and the OS

Lua's io, os and string libraries are available too.

Callbacks run on the UI thread, so keep them quick. statusline and panel callbacks run every couple of seconds — cache anything expensive. before_* handlers, columns and sort orders are stopped when they take too long. Errors appear as notifications and never crash strata.

The official plugins are good examples to start from.