xplr/en/print.html
2023-07-14 19:39:20 +00:00

5620 lines
305 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js dark">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>xplr book</title>
<meta name="robots" content="noindex" />
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="A hackable, minimal, fast TUI file explorer">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- EthicalAds -->
<script async src="https://media.ethicalads.io/media/client/ethicalads.min.js"></script>
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "coal" : "dark";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('dark')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li class="chapter-item expanded "><a href="quickstart.html"><strong aria-hidden="true">2.</strong> Quickstart</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="install.html"><strong aria-hidden="true">2.1.</strong> Install</a></li><li class="chapter-item expanded "><a href="post-install.html"><strong aria-hidden="true">2.2.</strong> Post Install</a></li></ol></li><li class="chapter-item expanded "><a href="configuration.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="general-config.html"><strong aria-hidden="true">3.1.</strong> General</a></li><li class="chapter-item expanded "><a href="node_types.html"><strong aria-hidden="true">3.2.</strong> Node Types</a></li><li class="chapter-item expanded "><a href="layouts.html"><strong aria-hidden="true">3.3.</strong> Layouts</a></li><li class="chapter-item expanded "><a href="modes.html"><strong aria-hidden="true">3.4.</strong> Modes</a></li></ol></li><li class="chapter-item expanded "><a href="concept.html"><strong aria-hidden="true">4.</strong> Concept</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="sum-type.html"><strong aria-hidden="true">4.1.</strong> Sum Type</a></li><li class="chapter-item expanded "><a href="key-bindings.html"><strong aria-hidden="true">4.2.</strong> Key Bindings</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="configure-key-bindings.html"><strong aria-hidden="true">4.2.1.</strong> Configure Key Bindings</a></li><li class="chapter-item expanded "><a href="default-key-bindings.html"><strong aria-hidden="true">4.2.2.</strong> Default Key Bindings</a></li><li class="chapter-item expanded "><a href="debug-key-bindings.html"><strong aria-hidden="true">4.2.3.</strong> Debug Key Bindings</a></li></ol></li><li class="chapter-item expanded "><a href="node-type.html"><strong aria-hidden="true">4.3.</strong> Node Type</a></li><li class="chapter-item expanded "><a href="layout.html"><strong aria-hidden="true">4.4.</strong> Layout</a></li><li class="chapter-item expanded "><a href="mode.html"><strong aria-hidden="true">4.5.</strong> Mode</a></li><li class="chapter-item expanded "><a href="message.html"><strong aria-hidden="true">4.6.</strong> Message</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="messages.html"><strong aria-hidden="true">4.6.1.</strong> Full List of Messages</a></li><li class="chapter-item expanded "><a href="input-operation.html"><strong aria-hidden="true">4.6.2.</strong> Input Operation</a></li></ol></li><li class="chapter-item expanded "><a href="borders.html"><strong aria-hidden="true">4.7.</strong> Borders</a></li><li class="chapter-item expanded "><a href="style.html"><strong aria-hidden="true">4.8.</strong> Style</a></li><li class="chapter-item expanded "><a href="searching.html"><strong aria-hidden="true">4.9.</strong> Searching</a></li><li class="chapter-item expanded "><a href="sorting.html"><strong aria-hidden="true">4.10.</strong> Sorting</a></li><li class="chapter-item expanded "><a href="filtering.html"><strong aria-hidden="true">4.11.</strong> Filtering</a></li><li class="chapter-item expanded "><a href="column-renderer.html"><strong aria-hidden="true">4.12.</strong> Column Renderer</a></li><li class="chapter-item expanded "><a href="lua-function-calls.html"><strong aria-hidden="true">4.13.</strong> Lua Function Calls</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="xplr.util.html"><strong aria-hidden="true">4.13.1.</strong> xplr.util</a></li></ol></li><li class="chapter-item expanded "><a href="environment-variables-and-pipes.html"><strong aria-hidden="true">4.14.</strong> Environment Variables and Pipes</a></li></ol></li><li class="chapter-item expanded "><a href="awesome-hacks.html"><strong aria-hidden="true">5.</strong> Awesome Hacks</a></li><li class="chapter-item expanded "><a href="plugin.html"><strong aria-hidden="true">6.</strong> Plugin</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="installing-plugins.html"><strong aria-hidden="true">6.1.</strong> Installing Plugins</a></li><li class="chapter-item expanded "><a href="writing-plugins.html"><strong aria-hidden="true">6.2.</strong> Writing Plugins</a></li><li class="chapter-item expanded "><a href="awesome-plugins.html"><strong aria-hidden="true">6.3.</strong> Awesome Plugins</a></li></ol></li><li class="chapter-item expanded "><a href="integration.html"><strong aria-hidden="true">7.</strong> Integration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="awesome-integrations.html"><strong aria-hidden="true">7.1.</strong> Awesome Integrations</a></li></ol></li><li class="chapter-item expanded "><a href="alternatives.html"><strong aria-hidden="true">8.</strong> Alternatives</a></li><li class="chapter-item expanded "><a href="upgrade-guide.html"><strong aria-hidden="true">9.</strong> Upgrade Guide</a></li><li class="chapter-item expanded "><a href="community.html"><strong aria-hidden="true">10.</strong> Community</a></li><li class="chapter-item expanded "><a href="contribute.html"><strong aria-hidden="true">11.</strong> Contribute</a></li></ol>
<!-- EthicalAds -->
<div
id="docs-sidebar-bottom"
class="dark flat"
data-ea-publisher="xplrdev"
data-ea-type="image"
></div>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">xplr book</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/sayanarijit/xplr" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="introduction"><a class="header" href="#introduction">Introduction</a></h1>
<p>xplr is a terminal UI based file explorer that aims to increase our terminal
productivity by being a flexible, interactive orchestrator for the ever growing
awesome command-line utilities that work with the file-system.</p>
<p>To achieve its goal, xplr strives to be a fast, minimal and more importantly,
hackable file explorer.</p>
<p>xplr is not meant to be a replacement for the standard shell commands or the
GUI file managers. Rather, it aims to <a href="awesome-plugins.html#integration">integrate them all</a> and expose an
intuitive, scriptable, <a href="configure-key-bindings.html">keyboard controlled</a>,
<a href="layouts.html">real-time visual interface</a>, also being an ideal candidate for <a href="awesome-integrations.html">further
integration</a>, enabling you to achieve insane terminal productivity.</p>
<h2 id="concept"><a class="header" href="#concept">Concept</a></h2>
<h3 id="hackable"><a class="header" href="#hackable">Hackable</a></h3>
<p>xplr is built with configurability in mind. So it allows you to perform a vast
set of operations and make it look and behave just the way you want.</p>
<p>A few things you can do with the xplr configuration</p>
<ul>
<li><a href="awesome-hacks.html">Hacks</a></li>
<li><a href="awesome-plugins.html">Plugins</a></li>
<li><a href="awesome-integrations.html">Integrations</a></li>
</ul>
<h3 id="fast"><a class="header" href="#fast">Fast</a></h3>
<p>Although speed is not the primary concern, xplr is already fast enough so that
you can take it out for a walk into your <code>node_modules</code> or <code>/nix/store</code> any
time you want, and it will only get faster. Still, if you feel like it's
somehow making you slow, just report it. Most probably we're just waiting for
someone to complain.</p>
<p><strong>Tip:</strong> A quick and easy way to optimize the UI rendering is reducing the
number of columns in the table.</p>
<h3 id="minimal"><a class="header" href="#minimal">Minimal</a></h3>
<p>xplr is being referred to as a <em>File Explorer</em>, not a <em>File Manager</em>. This
is because at the core, xplr is only an explorer, and <a href="https://github.com/sayanarijit/xplr/blob/main/src/init.lua">outsources</a> the file
management operations to external commands. This helps xplr stay minimal, and
focus only on doing what it does best.</p>
<p>So, just like speed, minimalism isn't as as aggressively pursued as
hackability. xplr simply prefers to stay minimal and looks for the opportunity
to lose some kb if it makes sense.</p>
<h2 id="features"><a class="header" href="#features">Features</a></h2>
<p>Some of the coolest features xplr provide beside the basic stuff:</p>
<ul>
<li><a href="https://github.com/sayanarijit/xplr/discussions/183">Embedded LuaJIT</a> for portability and extensibility.</li>
<li><a href="messages.html">A simple modal system based on message passing</a> to control xplr session
using:
<ul>
<li><a href="configure-key-bindings.html">Keyboard inputs</a></li>
<li><a href="mode.html#input-pipe">Shell Commands</a></li>
<li><a href="lua-function-calls.html">Lua Functions</a></li>
<li><a href="configuration.html#hooks">Hooks</a></li>
</ul>
</li>
<li>Easy, typesafe message passing with <code>-m MSG</code> or <code>-M MSG</code> subcommands.</li>
<li><a href="https://github.com/sayanarijit/xplr/pull/397">Readline-like input buffer</a> with customizable behavior to read user
inputs.</li>
<li><a href="modes.html#xplrconfigmodesbuiltinrecover">Switchable recover mode</a> that saves you from doing unwanted things when
in a hurry.</li>
<li><a href="layouts.html">Customizable layouts</a> with built-in panels. For e.g.
<ul>
<li><strong>Selection list</strong> to show you the selected paths in real-time.</li>
<li><strong>Help menu</strong> to show you the available keys bindings in each mode.</li>
<li><strong>Input &amp; logs</strong> to read input and display logs.</li>
<li><strong>Filter and sort pipeline</strong> to show you the applied filters and sorters.</li>
</ul>
</li>
<li><a href="node_types.html">Custom file properties</a> with custom colors can be displayed in the table.</li>
<li><a href="messages.html#startfifo">FIFO manager</a> to manage a FIFO file that can be used to
<a href="https://github.com/sayanarijit/xplr/pull/229">integrate with previewers</a>.</li>
<li><a href="messages.html#virtual-root">Virtual root</a> with <code>--vroot</code> and <code>:v</code> key bindings.</li>
<li><strong>Different quit options:</strong>
<ul>
<li>Quit with success without any output (<code>q</code>).</li>
<li>Quit with success and the result printed on stdout (<code>enter</code>).</li>
<li>Quit with success and the present working directory printed on stdout
(<code>:</code> <code>q</code> <code>p</code>).</li>
<li>Quit with success and the path under focus printed on stdout
(<code>:</code> <code>q</code> <code>f</code>).</li>
<li>Quit with success and the selection printed on stdout
(<code>:</code> <code>q</code> <code>s</code>).</li>
<li>Quit with failure (<code>ctrl-c</code>).</li>
</ul>
</li>
</ul>
<p><strong>Q.</strong> What features should be added here? <a href="community.html">let us know</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="quickstart"><a class="header" href="#quickstart">Quickstart</a></h1>
<p>Nice to you have here! Let's quickly start with the
following steps:</p>
<ul>
<li><a href="install.html">Install</a></li>
<li><a href="post-install.html">Post Install</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="try-in-docker"><a class="header" href="#try-in-docker">Try in Docker</a></h1>
<p>If you prefer to try it before installing, here's the snippet for your
convenience.</p>
<pre><code class="language-bash">docker run -w / -it --rm ubuntu sh -uec '
apt-get update -y
apt-get install -y wget tar vim less
wget https://github.com/sayanarijit/xplr/releases/latest/download/xplr-linux.tar.gz
tar -xzvf xplr-linux.tar.gz
./xplr
'
</code></pre>
<h1 id="install"><a class="header" href="#install">Install</a></h1>
<p>You can install xplr using one of the following ways. Each has their own
advantages and limitations.</p>
<p>For example, the <a href="install.html#direct-download">Direct Download</a>, <a href="install.html#from-cratesio">From crates.io</a>, and
<a href="install.html#build-from-source">Build From Source</a> methods allow the users to install the latest possible
version of xplr, but they have one common drawback - the user will need to keep
an eye on the releases, and manually upgrade xplr when a new version is
available.</p>
<p>One way to keep an eye on the releases is to <a href="https://github.com/sayanarijit/xplr/watchers">watch the repository</a>.</p>
<h2 id="community-maintained-repositories"><a class="header" href="#community-maintained-repositories">Community Maintained Repositories</a></h2>
<p>xplr can be installed from one of the following community maintained
repositories:</p>
<p><a href="https://repology.org/project/xplr/versions"><img src="https://repology.org/badge/vertical-allrepos/xplr.svg" alt="packaging status" /></a></p>
<h3 id="cross-platform"><a class="header" href="#cross-platform">Cross-platform</a></h3>
<h4 id="nixpkgs"><a class="header" href="#nixpkgs"><a href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/file-managers/xplr/default.nix">Nixpkgs</a></a></h4>
<pre><code>nix-env -f https://github.com/NixOS/nixpkgs/tarball/master -iA xplr
</code></pre>
<h3 id="arch-linux"><a class="header" href="#arch-linux">Arch Linux</a></h3>
<p>(same for Manjaro Linux)</p>
<h4 id="official-community-repo"><a class="header" href="#official-community-repo"><a href="https://archlinux.org/packages/community/x86_64/xplr">Official Community Repo</a></a></h4>
<pre><code>sudo pacman -S xplr
</code></pre>
<h4 id="aur"><a class="header" href="#aur"><a href="https://aur.archlinux.org/packages/?O=0&amp;SeB=n&amp;K=xplr&amp;outdated=&amp;SB=n&amp;SO=a&amp;PP=50&amp;do_Search=Go">AUR</a></a></h4>
<p>Git version:</p>
<pre><code>paru -S xplr-git
</code></pre>
<h3 id="alpine-linux"><a class="header" href="#alpine-linux">Alpine Linux</a></h3>
<h4 id="edge-testing-repo"><a class="header" href="#edge-testing-repo"><a href="https://pkgs.alpinelinux.org/packages?name=xplr">Edge Testing Repo</a></a></h4>
<pre><code># Add the following line in /etc/apk/repositories:
# https://dl-cdn.alpinelinux.org/alpine/edge/testing
apk add xplr bash less
</code></pre>
<h3 id="void-linux"><a class="header" href="#void-linux">Void Linux</a></h3>
<h4 id="void-templates-by-shubham"><a class="header" href="#void-templates-by-shubham"><a href="https://github.com/shubham-cpp/void-pkg-templates">void-templates by shubham</a></a></h4>
<h3 id="gentoo"><a class="header" href="#gentoo">Gentoo</a></h3>
<h4 id="overlay-guru"><a class="header" href="#overlay-guru"><a href="https://gpo.zugaina.org/Overlays/guru/app-misc/xplr">Overlay GURU</a></a></h4>
<h3 id="macos"><a class="header" href="#macos">macOS</a></h3>
<p>Make sure you have the latest version of <a href="https://formulae.brew.sh/formula/coreutils">GNU core utilities</a> installed.</p>
<h4 id="macports"><a class="header" href="#macports"><a href="https://ports.macports.org/port/xplr">MacPorts</a></a></h4>
<pre><code>sudo port selfupdate
sudo port install xplr
</code></pre>
<h4 id="homebrew"><a class="header" href="#homebrew"><a href="https://formulae.brew.sh/formula/xplr">Homebrew</a></a></h4>
<p>Stable branch:</p>
<pre><code>brew install xplr
</code></pre>
<p>HEAD branch:</p>
<pre><code>brew install --head xplr
</code></pre>
<h3 id="freebsd"><a class="header" href="#freebsd">FreeBSD</a></h3>
<h4 id="ports"><a class="header" href="#ports"><a href="https://cgit.freebsd.org/ports/plain/misc/xplr/">ports</a></a></h4>
<pre><code>pkg install xplr
</code></pre>
<p>Or</p>
<pre><code>cd /usr/ports/misc/xplr
make install clean
</code></pre>
<h3 id="netbsd"><a class="header" href="#netbsd">NetBSD</a></h3>
<h4 id="pkgsrc"><a class="header" href="#pkgsrc"><a href="https://pkgsrc.se/sysutils/xplr">pkgsrc</a></a></h4>
<pre><code>pkgin install xplr
</code></pre>
<p>Or</p>
<pre><code>cd /usr/pkgsrc/sysutils/xplr
make install
</code></pre>
<h2 id="direct-download"><a class="header" href="#direct-download">Direct Download</a></h2>
<p>One can directly download the standalone binary from the
<a href="https://github.com/sayanarijit/xplr/releases">releases</a>.</p>
<p>Currently, the following options are available for direct download:</p>
<ul>
<li><a href="https://github.com/sayanarijit/xplr/releases/latest/download/xplr-linux.tar.gz">GNU/Linux</a></li>
<li><a href="https://github.com/sayanarijit/xplr/releases/latest/download/xplr-linux-musl.tar.gz">Linux musl</a></li>
<li><a href="https://github.com/sayanarijit/xplr/releases/latest/download/xplr-macos.tar.gz">macOS</a></li>
</ul>
<p>Command-line instructions:</p>
<pre><code class="language-bash">platform=&quot;linux&quot; # or &quot;macos&quot; / &quot;linux-musl&quot;
# Download
wget https://github.com/sayanarijit/xplr/releases/latest/download/xplr-$platform.tar.gz
# Extract
tar xzvf xplr-$platform.tar.gz
# Place in $PATH
sudo mv xplr /usr/local/bin/
</code></pre>
<h2 id="from-cratesio"><a class="header" href="#from-cratesio">From <a href="https://crates.io/crates/xplr">crates.io</a></a></h2>
<p>Prerequisites:</p>
<ul>
<li><a href="https://www.rust-lang.org/tools/install">Rust toolchain</a>,</li>
<li><a href="https://gcc.gnu.org/">gcc</a></li>
<li><a href="https://www.gnu.org/software/make/">make</a></li>
</ul>
<p>Command-line instructions:</p>
<pre><code class="language-bash">cargo install --locked --force xplr
</code></pre>
<h2 id="build-from-source"><a class="header" href="#build-from-source">Build From Source</a></h2>
<p>Prerequisites:</p>
<ul>
<li><a href="https://git-scm.com/">git</a></li>
<li><a href="https://www.rust-lang.org/tools/install">Rust toolchain</a></li>
<li><a href="https://gcc.gnu.org/">gcc</a></li>
<li><a href="https://www.gnu.org/software/make/">make</a></li>
</ul>
<p>Command-line instructions:</p>
<pre><code class="language-bash"># Clone the repository
git clone https://github.com/sayanarijit/xplr.git
cd xplr
# Build
cargo build --locked --release --bin xplr
# Place in $PATH
sudo cp target/release/xplr /usr/local/bin/
</code></pre>
<h2 id="android"><a class="header" href="#android">Android</a></h2>
<h3 id="termux"><a class="header" href="#termux"><a href="https://termux.com/">Termux</a></a></h3>
<p><a href="https://gifyu.com/image/tF2D"><img src="https://s3.gifyu.com/images/xplr-termuxfd3c398d3cf4bcbc.md.jpg" alt="xplr-termuxfd3c398d3cf4bcbc.md.jpg" /></a></p>
<blockquote>
<p>Please note that xplr isn't heavily tested on Termux, hence things might
need a little tweaking and fixing for a smooth usage experience.</p>
</blockquote>
<ul>
<li>
<p>Install build dependencies</p>
<pre><code class="language-bash">pkg install rustc cargo make
</code></pre>
</li>
<li>
<p>Install <code>xplr</code></p>
<pre><code class="language-bash">cargo install --locked --force xplr
</code></pre>
</li>
<li>
<p>Setup storage</p>
<pre><code class="language-bash">termux-setup-storage
</code></pre>
</li>
<li>
<p>Setup config and runtime dir</p>
<pre><code class="language-bash">export XDG_CONFIG_HOME=&quot;$PWD/storage/.config&quot;
export XDG_RUNTIME_DIR=&quot;$PWD/storage/run&quot;
mkdir -p &quot;$XDG_CONFIG_HOME&quot; &quot;$XDG_RUNTIME_DIR&quot;
</code></pre>
</li>
<li>
<p>Run</p>
<pre><code class="language-bash">~/.cargo/bin/xplr
</code></pre>
</li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="post-install"><a class="header" href="#post-install">Post Install</a></h1>
<p>Once <a href="install.html">installed</a>, use the following steps to setup and run xplr.</p>
<h2 id="create-the-customizable-config-file"><a class="header" href="#create-the-customizable-config-file">Create the customizable config file</a></h2>
<pre><code class="language-bash">mkdir -p ~/.config/xplr
version=&quot;$(xplr --version | awk '{print $2}')&quot;
echo &quot;version = '${version:?}'&quot; &gt; ~/.config/xplr/init.lua
</code></pre>
<p>Then
<strong><a href="https://github.com/sayanarijit/xplr/blob/main/src/init.lua">copy from here</a></strong>
and remove / comment out what you don't want to customize.</p>
<h2 id="run"><a class="header" href="#run">Run</a></h2>
<pre><code>xplr
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="configuration"><a class="header" href="#configuration">Configuration</a></h1>
<p>xplr can be configured using <a href="https://www.lua.org">Lua</a> via a special file named <code>init.lua</code>,
which can be placed in <code>~/.config/xplr/</code> (local to user) or <code>/etc/xplr/</code>
(global) depending on the use case.</p>
<p>When xplr loads, it first executes the <a href="https://github.com/sayanarijit/xplr/blob/main/src/init.lua">built-in init.lua</a> to set the
default values, which is then overwritten by another config file, if found
using the following lookup order:</p>
<ol>
<li><code>--config /path/to/init.lua</code></li>
<li><code>~/.config/xplr/init.lua</code></li>
<li><code>/etc/xplr/init.lua</code></li>
</ol>
<p>The first one found will be loaded by xplr and the lookup will stop.</p>
<p>The loaded config can be further extended using the <code>-C</code> or <code>--extra-config</code>
command-line option.</p>
<h2 id="config"><a class="header" href="#config">Config</a></h2>
<p>The xplr configuration, exposed via <code>xplr.config</code> Lua API contains the
following sections.</p>
<p>See:</p>
<ul>
<li><a href="https://xplr.dev/en/general-config">xplr.config.general</a></li>
<li><a href="https://xplr.dev/en/node_types">xplr.config.node_types</a></li>
<li><a href="https://xplr.dev/en/layouts">xplr.config.layouts</a></li>
<li><a href="https://xplr.dev/en/modes">xplr.config.modes</a></li>
</ul>
<h2 id="function"><a class="header" href="#function">Function</a></h2>
<p>While <code>xplr.config</code> defines all the static parts of the configuration,
<code>xplr.fn</code> defines all the dynamic parts using functions.</p>
<p>See: <a href="https://xplr.dev/en/lua-function-calls">Lua Function Calls</a></p>
<p>As always, <code>xplr.fn.builtin</code> is where the built-in functions are defined
that can be overwritten.</p>
<h4 id="xplrfnbuiltintry_complete_path"><a class="header" href="#xplrfnbuiltintry_complete_path">xplr.fn.builtin.try_complete_path</a></h4>
<p>Tries to auto complete the path in the input buffer</p>
<h4 id="xplrfnbuiltinfmt_general_table_row_cols_0"><a class="header" href="#xplrfnbuiltinfmt_general_table_row_cols_0">xplr.fn.builtin.fmt_general_table_row_cols_0</a></h4>
<p>Renders the first column in the table</p>
<h4 id="xplrfnbuiltinfmt_general_table_row_cols_1"><a class="header" href="#xplrfnbuiltinfmt_general_table_row_cols_1">xplr.fn.builtin.fmt_general_table_row_cols_1</a></h4>
<p>Renders the second column in the table</p>
<h4 id="xplrfnbuiltinfmt_general_table_row_cols_2"><a class="header" href="#xplrfnbuiltinfmt_general_table_row_cols_2">xplr.fn.builtin.fmt_general_table_row_cols_2</a></h4>
<p>Renders the third column in the table</p>
<h4 id="xplrfnbuiltinfmt_general_table_row_cols_3"><a class="header" href="#xplrfnbuiltinfmt_general_table_row_cols_3">xplr.fn.builtin.fmt_general_table_row_cols_3</a></h4>
<p>Renders the fourth column in the table</p>
<h4 id="xplrfnbuiltinfmt_general_table_row_cols_4"><a class="header" href="#xplrfnbuiltinfmt_general_table_row_cols_4">xplr.fn.builtin.fmt_general_table_row_cols_4</a></h4>
<p>Renders the fifth column in the table</p>
<h4 id="xplrfncustom"><a class="header" href="#xplrfncustom">xplr.fn.custom</a></h4>
<p>This is where the custom functions can be added.</p>
<p>There is currently no restriction on what kind of functions can be defined
in <code>xplr.fn.custom</code>.</p>
<p>You can also use nested tables such as
<code>xplr.fn.custom.my_plugin.my_function</code> to define custom functions.</p>
<h2 id="hooks"><a class="header" href="#hooks">Hooks</a></h2>
<p>This section of the configuration cannot be overwritten by another config
file or plugin, since this is an optional lua return statement specific to
each config file. It can be used to define things that should be explicit
for reasons like performance concerns, such as hooks.</p>
<p>Plugins should expose the hooks, and require users to subscribe to them
explicitly.</p>
<p>Example:</p>
<pre><code class="language-lua">return {
-- Add messages to send when the xplr loads.
-- This is similar to the `--on-load` command-line option.
--
-- Type: list of [Message](https://xplr.dev/en/message#message)s
on_load = {
{ LogSuccess = &quot;Configuration successfully loaded!&quot; },
{ CallLuaSilently = &quot;custom.some_plugin_with_hooks.on_load&quot; },
},
-- Add messages to send when the directory changes.
--
-- Type: list of [Message](https://xplr.dev/en/message#message)s
on_directory_change = {
{ LogSuccess = &quot;Changed directory&quot; },
{ CallLuaSilently = &quot;custom.some_plugin_with_hooks.on_directory_change&quot; },
},
-- Add messages to send when the focus changes.
--
-- Type: list of [Message](https://xplr.dev/en/message#message)s
on_focus_change = {
{ LogSuccess = &quot;Changed focus&quot; },
{ CallLuaSilently = &quot;custom.some_plugin_with_hooks.on_focus_change&quot; },
}
-- Add messages to send when the mode is switched.
--
-- Type: list of [Message](https://xplr.dev/en/message#message)s
on_mode_switch = {
{ LogSuccess = &quot;Switched mode&quot; },
{ CallLuaSilently = &quot;custom.some_plugin_with_hooks.on_mode_switch&quot; },
}
-- Add messages to send when the layout is switched
--
-- Type: list of [Message](https://xplr.dev/en/message#message)s
on_layout_switch = {
{ LogSuccess = &quot;Switched layout&quot; },
{ CallLuaSilently = &quot;custom.some_plugin_with_hooks.on_layout_switch&quot; },
}
}
</code></pre>
<hr />
<blockquote>
<p>Note:</p>
<p>It's not recommended to copy the entire configuration, unless you want to
freeze it and miss out on useful updates to the defaults.</p>
<p>Instead, you can use this as a reference to overwrite only the parts you
want to update.</p>
<p>If you still want to copy the entire configuration, make sure to put your
customization before the return statement.</p>
</blockquote>
<div style="break-before: page; page-break-before: always;"></div><h3 id="general-configuration"><a class="header" href="#general-configuration">General Configuration</a></h3>
<p>The general configuration properties are grouped together in
<code>xplr.config.general</code>.</p>
<h4 id="xplrconfiggeneraldisable_debug_error_mode"><a class="header" href="#xplrconfiggeneraldisable_debug_error_mode">xplr.config.general.disable_debug_error_mode</a></h4>
<p>Set it to <code>true</code> if you want to ignore the startup errors. You can still see
the errors in the logs.</p>
<p>Type: boolean</p>
<h4 id="xplrconfiggeneralenable_mouse"><a class="header" href="#xplrconfiggeneralenable_mouse">xplr.config.general.enable_mouse</a></h4>
<p>Set it to <code>true</code> if you want to enable mouse scrolling.</p>
<p>Type: boolean</p>
<h4 id="xplrconfiggeneralshow_hidden"><a class="header" href="#xplrconfiggeneralshow_hidden">xplr.config.general.show_hidden</a></h4>
<p>Set it to <code>true</code> to show hidden files by default.</p>
<p>Type: boolean</p>
<h4 id="xplrconfiggeneralread_only"><a class="header" href="#xplrconfiggeneralread_only">xplr.config.general.read_only</a></h4>
<p>Set it to <code>true</code> to use only a subset of selected operations that forbids
executing commands or performing write operations on the file-system.</p>
<p>Type: boolean</p>
<h4 id="xplrconfiggeneralenable_recover_mode"><a class="header" href="#xplrconfiggeneralenable_recover_mode">xplr.config.general.enable_recover_mode</a></h4>
<p>Set it to <code>true</code> if you want to enable a safety feature that will save you
from yourself when you type recklessly.</p>
<p>Type: boolean</p>
<h4 id="xplrconfiggeneralhide_remaps_in_help_menu"><a class="header" href="#xplrconfiggeneralhide_remaps_in_help_menu">xplr.config.general.hide_remaps_in_help_menu</a></h4>
<p>Set it to <code>true</code> if you want to hide all remaps in the help menu.</p>
<p>Type: boolean</p>
<h4 id="xplrconfiggeneralenforce_bounded_index_navigation"><a class="header" href="#xplrconfiggeneralenforce_bounded_index_navigation">xplr.config.general.enforce_bounded_index_navigation</a></h4>
<p>Set it to <code>true</code> if you want the cursor to stay in the same position when
the focus is on the first path and you navigate to the previous path
(by pressing <code>up</code>/<code>k</code>), or when the focus is on the last path and you
navigate to the next path (by pressing <code>down</code>/<code>j</code>).
The default behavior is to rotate from the last/first path.</p>
<p>Type: boolean</p>
<h4 id="xplrconfiggeneralpromptformat"><a class="header" href="#xplrconfiggeneralpromptformat">xplr.config.general.prompt.format</a></h4>
<p>This is the shape of the prompt for the input buffer.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralpromptstyle"><a class="header" href="#xplrconfiggeneralpromptstyle">xplr.config.general.prompt.style</a></h4>
<p>This is the style of the prompt for the input buffer.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggenerallogsinfoformat"><a class="header" href="#xplrconfiggenerallogsinfoformat">xplr.config.general.logs.info.format</a></h4>
<p>The string to indicate an information in logs.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggenerallogsinfostyle"><a class="header" href="#xplrconfiggenerallogsinfostyle">xplr.config.general.logs.info.style</a></h4>
<p>The style for the information logs.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggenerallogssuccessformat"><a class="header" href="#xplrconfiggenerallogssuccessformat">xplr.config.general.logs.success.format</a></h4>
<p>The string to indicate an success in logs.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggenerallogssuccessstyle"><a class="header" href="#xplrconfiggenerallogssuccessstyle">xplr.config.general.logs.success.style</a></h4>
<p>The style for the success logs.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggenerallogswarningformat"><a class="header" href="#xplrconfiggenerallogswarningformat">xplr.config.general.logs.warning.format</a></h4>
<p>The string to indicate an warnings in logs.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggenerallogswarningstyle"><a class="header" href="#xplrconfiggenerallogswarningstyle">xplr.config.general.logs.warning.style</a></h4>
<p>The style for the warnings logs.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggenerallogserrorformat"><a class="header" href="#xplrconfiggenerallogserrorformat">xplr.config.general.logs.error.format</a></h4>
<p>The string to indicate an error in logs.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggenerallogserrorstyle"><a class="header" href="#xplrconfiggenerallogserrorstyle">xplr.config.general.logs.error.style</a></h4>
<p>The style for the error logs.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneraltableheadercols"><a class="header" href="#xplrconfiggeneraltableheadercols">xplr.config.general.table.header.cols</a></h4>
<p>Columns to display in the table header.</p>
<p>Type: nullable list of tables with the following fields:</p>
<ul>
<li>format: nullable string</li>
<li>style: <a href="https://xplr.dev/en/style">Style</a></li>
</ul>
<h4 id="xplrconfiggeneraltableheaderstyle"><a class="header" href="#xplrconfiggeneraltableheaderstyle">xplr.config.general.table.header.style</a></h4>
<p>Style of the table header.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneraltableheaderheight"><a class="header" href="#xplrconfiggeneraltableheaderheight">xplr.config.general.table.header.height</a></h4>
<p>Height of the table header.</p>
<p>Type: nullable integer</p>
<h4 id="xplrconfiggeneraltablerowcols"><a class="header" href="#xplrconfiggeneraltablerowcols">xplr.config.general.table.row.cols</a></h4>
<p>Columns to display in each row in the table.</p>
<p>Type: nullable list of tables with the following fields:</p>
<ul>
<li>format: nullable string</li>
<li>style: <a href="https://xplr.dev/en/style">Style</a></li>
</ul>
<h4 id="xplrconfiggeneraltablerowstyle"><a class="header" href="#xplrconfiggeneraltablerowstyle">xplr.config.general.table.row.style</a></h4>
<p>Default style of the table.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneraltablerowheight"><a class="header" href="#xplrconfiggeneraltablerowheight">xplr.config.general.table.row.height</a></h4>
<p>Height of the table rows.</p>
<p>Type: nullable integer</p>
<h4 id="xplrconfiggeneraltablestyle"><a class="header" href="#xplrconfiggeneraltablestyle">xplr.config.general.table.style</a></h4>
<p>Default style of the table.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneraltabletree"><a class="header" href="#xplrconfiggeneraltabletree">xplr.config.general.table.tree</a></h4>
<p>Tree to display in the table.</p>
<p>Type: nullable list of tables with the following fields:</p>
<ul>
<li>format: nullable string</li>
<li>style: <a href="https://xplr.dev/en/style">Style</a></li>
</ul>
<h4 id="xplrconfiggeneraltablecol_spacing"><a class="header" href="#xplrconfiggeneraltablecol_spacing">xplr.config.general.table.col_spacing</a></h4>
<p>Spacing between the columns in the table.</p>
<p>Type: nullable integer</p>
<h4 id="xplrconfiggeneraltablecol_widths"><a class="header" href="#xplrconfiggeneraltablecol_widths">xplr.config.general.table.col_widths</a></h4>
<p>Constraint for the column widths.</p>
<p>Type: nullable list of <a href="https://xplr.dev/en/layouts#constraint">Constraint</a></p>
<h4 id="xplrconfiggeneralselectionitemformat"><a class="header" href="#xplrconfiggeneralselectionitemformat">xplr.config.general.selection.item.format</a></h4>
<p>Renderer for each item in the selection list.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralselectionitemstyle"><a class="header" href="#xplrconfiggeneralselectionitemstyle">xplr.config.general.selection.item.style</a></h4>
<p>Style for each item in the selection list.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralsearchalgorithm"><a class="header" href="#xplrconfiggeneralsearchalgorithm">xplr.config.general.search.algorithm</a></h4>
<p>The default search algorithm</p>
<p>Type: <a href="https://xplr.dev/en/searching#algorithm">Search Algorithm</a></p>
<h4 id="xplrconfiggeneralsearchunordered"><a class="header" href="#xplrconfiggeneralsearchunordered">xplr.config.general.search.unordered</a></h4>
<p>The default search ordering</p>
<p>Type: boolean</p>
<h4 id="xplrconfiggeneraldefault_uiprefix"><a class="header" href="#xplrconfiggeneraldefault_uiprefix">xplr.config.general.default_ui.prefix</a></h4>
<p>The content that is placed before the item name for each row by default.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneraldefault_uisuffix"><a class="header" href="#xplrconfiggeneraldefault_uisuffix">xplr.config.general.default_ui.suffix</a></h4>
<p>The content which is appended to each item name for each row by default.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneraldefault_uistyle"><a class="header" href="#xplrconfiggeneraldefault_uistyle">xplr.config.general.default_ui.style</a></h4>
<p>The default style of each item for each row.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralfocus_uiprefix"><a class="header" href="#xplrconfiggeneralfocus_uiprefix">xplr.config.general.focus_ui.prefix</a></h4>
<p>The string placed before the item name for a focused row.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralfocus_uisuffix"><a class="header" href="#xplrconfiggeneralfocus_uisuffix">xplr.config.general.focus_ui.suffix</a></h4>
<p>The string placed after the item name for a focused row.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralfocus_uistyle"><a class="header" href="#xplrconfiggeneralfocus_uistyle">xplr.config.general.focus_ui.style</a></h4>
<p>Style for focused item.
Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralselection_uiprefix"><a class="header" href="#xplrconfiggeneralselection_uiprefix">xplr.config.general.selection_ui.prefix</a></h4>
<p>The string placed before the item name for a selected row.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralselection_uisuffix"><a class="header" href="#xplrconfiggeneralselection_uisuffix">xplr.config.general.selection_ui.suffix</a></h4>
<p>The string placed after the item name for a selected row.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralselection_uistyle"><a class="header" href="#xplrconfiggeneralselection_uistyle">xplr.config.general.selection_ui.style</a></h4>
<p>Style for selected rows.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralfocus_selection_uiprefix"><a class="header" href="#xplrconfiggeneralfocus_selection_uiprefix">xplr.config.general.focus_selection_ui.prefix</a></h4>
<p>The string placed before item name for a selected row that gets the focus.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralfocus_selection_uisuffix"><a class="header" href="#xplrconfiggeneralfocus_selection_uisuffix">xplr.config.general.focus_selection_ui.suffix</a></h4>
<p>The string placed after the item name for a selected row that gets the focus.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralfocus_selection_uistyle"><a class="header" href="#xplrconfiggeneralfocus_selection_uistyle">xplr.config.general.focus_selection_ui.style</a></h4>
<p>Style for a selected row that gets the focus.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralsort_and_filter_uiseparatorformat"><a class="header" href="#xplrconfiggeneralsort_and_filter_uiseparatorformat">xplr.config.general.sort_and_filter_ui.separator.format</a></h4>
<p>The shape of the separator for the Sort &amp; filter panel.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralsort_and_filter_uiseparatorstyle"><a class="header" href="#xplrconfiggeneralsort_and_filter_uiseparatorstyle">xplr.config.general.sort_and_filter_ui.separator.style</a></h4>
<p>The style of the separator for the Sort &amp; filter panel.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralsort_and_filter_uidefault_identifierformat"><a class="header" href="#xplrconfiggeneralsort_and_filter_uidefault_identifierformat">xplr.config.general.sort_and_filter_ui.default_identifier.format</a></h4>
<p>The content of the default identifier in Sort &amp; filter panel.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralsort_and_filter_uidefault_identifierstyle"><a class="header" href="#xplrconfiggeneralsort_and_filter_uidefault_identifierstyle">xplr.config.general.sort_and_filter_ui.default_identifier.style</a></h4>
<p>Style for the default identifier in Sort &amp; filter panel.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralsort_and_filter_uisort_direction_identifiersforwardformat"><a class="header" href="#xplrconfiggeneralsort_and_filter_uisort_direction_identifiersforwardformat">xplr.config.general.sort_and_filter_ui.sort_direction_identifiers.forward.format</a></h4>
<p>The shape of the forward direction indicator for sort identifiers in Sort &amp; filter panel.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralsort_and_filter_uisort_direction_identifiersforwardstyle"><a class="header" href="#xplrconfiggeneralsort_and_filter_uisort_direction_identifiersforwardstyle">xplr.config.general.sort_and_filter_ui.sort_direction_identifiers.forward.style</a></h4>
<p>Style of forward direction indicator in Sort &amp; filter panel.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralsort_and_filter_uisort_direction_identifiersreverseformat"><a class="header" href="#xplrconfiggeneralsort_and_filter_uisort_direction_identifiersreverseformat">xplr.config.general.sort_and_filter_ui.sort_direction_identifiers.reverse.format</a></h4>
<p>The shape of the reverse direction indicator for sort identifiers in Sort &amp; filter panel.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralsort_and_filter_uisort_direction_identifiersreversestyle"><a class="header" href="#xplrconfiggeneralsort_and_filter_uisort_direction_identifiersreversestyle">xplr.config.general.sort_and_filter_ui.sort_direction_identifiers.reverse.style</a></h4>
<p>Style of reverse direction indicator in Sort &amp; filter panel.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralsort_and_filter_uisorter_identifiers"><a class="header" href="#xplrconfiggeneralsort_and_filter_uisorter_identifiers">xplr.config.general.sort_and_filter_ui.sorter_identifiers</a></h4>
<p>The identifiers used to denote applied sorters in the Sort &amp; filter panel.</p>
<p>Type: nullable mapping of the following key-value pairs:</p>
<ul>
<li>key: <a href="https://xplr.dev/en/sorting#sorter">Sorter</a></li>
<li>value:
<ul>
<li>format: nullable string</li>
<li>style: <a href="https://xplr.dev/en/style">Style</a></li>
</ul>
</li>
</ul>
<h4 id="xplrconfiggeneralsort_and_filter_uifilter_identifiers"><a class="header" href="#xplrconfiggeneralsort_and_filter_uifilter_identifiers">xplr.config.general.sort_and_filter_ui.filter_identifiers</a></h4>
<p>The identifiers used to denote applied filters in the Sort &amp; filter panel.</p>
<p>Type: nullable mapping of the following key-value pairs:</p>
<ul>
<li>key: <a href="https://xplr.dev/en/filtering#filter">Filter</a></li>
<li>value:
<ul>
<li>format: nullable string</li>
<li>style: <a href="https://xplr.dev/en/style">Style</a></li>
</ul>
</li>
</ul>
<h4 id="xplrconfiggeneralsort_and_filter_uisearch_identifiers"><a class="header" href="#xplrconfiggeneralsort_and_filter_uisearch_identifiers">xplr.config.general.sort_and_filter_ui.search_identifiers</a></h4>
<p>The identifiers used to denote applied search input.</p>
<p>Type: { format = nullable string, style = <a href="https://xplr.dev/en/style">Style</a> }</p>
<h4 id="xplrconfiggeneralsort_and_filter_uisearch_direction_identifiersorderedformat"><a class="header" href="#xplrconfiggeneralsort_and_filter_uisearch_direction_identifiersorderedformat">xplr.config.general.sort_and_filter_ui.search_direction_identifiers.ordered.format</a></h4>
<p>The shape of ordered indicator for search ordering identifiers in Sort &amp; filter panel.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralsort_and_filter_uisearch_direction_identifiersunorderedformat"><a class="header" href="#xplrconfiggeneralsort_and_filter_uisearch_direction_identifiersunorderedformat">xplr.config.general.sort_and_filter_ui.search_direction_identifiers.unordered.format</a></h4>
<p>The shape of unordered indicator for search ordering identifiers in Sort &amp; filter panel.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralpanel_uidefaulttitleformat"><a class="header" href="#xplrconfiggeneralpanel_uidefaulttitleformat">xplr.config.general.panel_ui.default.title.format</a></h4>
<p>The content for panel title by default.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralpanel_uidefaulttitlestyle"><a class="header" href="#xplrconfiggeneralpanel_uidefaulttitlestyle">xplr.config.general.panel_ui.default.title.style</a></h4>
<p>The style for panel title by default.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uidefaultstyle"><a class="header" href="#xplrconfiggeneralpanel_uidefaultstyle">xplr.config.general.panel_ui.default.style</a></h4>
<p>Style of the panels by default.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uidefaultborders"><a class="header" href="#xplrconfiggeneralpanel_uidefaultborders">xplr.config.general.panel_ui.default.borders</a></h4>
<p>Defines where to show borders for the panels by default.</p>
<p>Type: nullable list of <a href="https://xplr.dev/en/borders#border">Border</a></p>
<h4 id="xplrconfiggeneralpanel_uidefaultborder_type"><a class="header" href="#xplrconfiggeneralpanel_uidefaultborder_type">xplr.config.general.panel_ui.default.border_type</a></h4>
<p>Type of the borders by default.</p>
<p>Type: nullable <a href="https://xplr.dev/en/borders#border-type">Border Type</a></p>
<h4 id="xplrconfiggeneralpanel_uidefaultborder_style"><a class="header" href="#xplrconfiggeneralpanel_uidefaultborder_style">xplr.config.general.panel_ui.default.border_style</a></h4>
<p>Style of the panel borders by default.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uitabletitleformat"><a class="header" href="#xplrconfiggeneralpanel_uitabletitleformat">xplr.config.general.panel_ui.table.title.format</a></h4>
<p>The content for the table panel title.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralpanel_uitabletitlestyle"><a class="header" href="#xplrconfiggeneralpanel_uitabletitlestyle">xplr.config.general.panel_ui.table.title.style</a></h4>
<p>Style of the table panel title.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uitablestyle"><a class="header" href="#xplrconfiggeneralpanel_uitablestyle">xplr.config.general.panel_ui.table.style</a></h4>
<p>Style of the table panel.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uitableborders"><a class="header" href="#xplrconfiggeneralpanel_uitableborders">xplr.config.general.panel_ui.table.borders</a></h4>
<p>Defines where to show borders for the table panel.</p>
<p>Type: nullable list of <a href="https://xplr.dev/en/borders#border">Border</a></p>
<h4 id="xplrconfiggeneralpanel_uitableborder_type"><a class="header" href="#xplrconfiggeneralpanel_uitableborder_type">xplr.config.general.panel_ui.table.border_type</a></h4>
<p>Type of the borders for table panel.</p>
<p>Type: nullable <a href="https://xplr.dev/en/borders#border-type">Border Type</a></p>
<h4 id="xplrconfiggeneralpanel_uitableborder_style"><a class="header" href="#xplrconfiggeneralpanel_uitableborder_style">xplr.config.general.panel_ui.table.border_style</a></h4>
<p>Style of the table panel borders.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uihelp_menutitleformat"><a class="header" href="#xplrconfiggeneralpanel_uihelp_menutitleformat">xplr.config.general.panel_ui.help_menu.title.format</a></h4>
<p>The content for the help menu panel title.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralpanel_uihelp_menutitlestyle"><a class="header" href="#xplrconfiggeneralpanel_uihelp_menutitlestyle">xplr.config.general.panel_ui.help_menu.title.style</a></h4>
<p>Style of the help menu panel title.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uihelp_menustyle"><a class="header" href="#xplrconfiggeneralpanel_uihelp_menustyle">xplr.config.general.panel_ui.help_menu.style</a></h4>
<p>Style of the help menu panel.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uihelp_menuborders"><a class="header" href="#xplrconfiggeneralpanel_uihelp_menuborders">xplr.config.general.panel_ui.help_menu.borders</a></h4>
<p>Defines where to show borders for the help menu panel.</p>
<p>Type: nullable list of <a href="https://xplr.dev/en/borders#border">Border</a></p>
<h4 id="xplrconfiggeneralpanel_uihelp_menuborder_type"><a class="header" href="#xplrconfiggeneralpanel_uihelp_menuborder_type">xplr.config.general.panel_ui.help_menu.border_type</a></h4>
<p>Type of the borders for help menu panel.</p>
<p>Type: nullable <a href="https://xplr.dev/en/borders#border-type">Border Type</a></p>
<h4 id="xplrconfiggeneralpanel_uihelp_menuborder_style"><a class="header" href="#xplrconfiggeneralpanel_uihelp_menuborder_style">xplr.config.general.panel_ui.help_menu.border_style</a></h4>
<p>Style of the help menu panel borders.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uiinput_and_logstitleformat"><a class="header" href="#xplrconfiggeneralpanel_uiinput_and_logstitleformat">xplr.config.general.panel_ui.input_and_logs.title.format</a></h4>
<p>The content for the input &amp; logs panel title.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralpanel_uiinput_and_logstitlestyle"><a class="header" href="#xplrconfiggeneralpanel_uiinput_and_logstitlestyle">xplr.config.general.panel_ui.input_and_logs.title.style</a></h4>
<p>Style of the input &amp; logs panel title.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uiinput_and_logsborders"><a class="header" href="#xplrconfiggeneralpanel_uiinput_and_logsborders">xplr.config.general.panel_ui.input_and_logs.borders</a></h4>
<h4 id="xplrconfiggeneralpanel_uiinput_and_logsstyle"><a class="header" href="#xplrconfiggeneralpanel_uiinput_and_logsstyle">xplr.config.general.panel_ui.input_and_logs.style</a></h4>
<p>Style of the input &amp; logs panel.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a>
Defines where to show borders for the input &amp; logs panel.</p>
<p>Type: nullable list of <a href="https://xplr.dev/en/borders#border">Border</a></p>
<h4 id="xplrconfiggeneralpanel_uiinput_and_logsborder_type"><a class="header" href="#xplrconfiggeneralpanel_uiinput_and_logsborder_type">xplr.config.general.panel_ui.input_and_logs.border_type</a></h4>
<p>Type of the borders for input &amp; logs panel.</p>
<p>Type: nullable <a href="https://xplr.dev/en/borders#border-type">Border Type</a></p>
<h4 id="xplrconfiggeneralpanel_uiinput_and_logsborder_style"><a class="header" href="#xplrconfiggeneralpanel_uiinput_and_logsborder_style">xplr.config.general.panel_ui.input_and_logs.border_style</a></h4>
<p>Style of the input &amp; logs panel borders.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uiselectiontitleformat"><a class="header" href="#xplrconfiggeneralpanel_uiselectiontitleformat">xplr.config.general.panel_ui.selection.title.format</a></h4>
<p>The content for the selection panel title.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralpanel_uiselectiontitlestyle"><a class="header" href="#xplrconfiggeneralpanel_uiselectiontitlestyle">xplr.config.general.panel_ui.selection.title.style</a></h4>
<p>Style of the selection panel title.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uiselectionborders"><a class="header" href="#xplrconfiggeneralpanel_uiselectionborders">xplr.config.general.panel_ui.selection.borders</a></h4>
<h4 id="xplrconfiggeneralpanel_uiselectionstyle"><a class="header" href="#xplrconfiggeneralpanel_uiselectionstyle">xplr.config.general.panel_ui.selection.style</a></h4>
<p>Style of the selection panel.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a>
Defines where to show borders for the selection panel.</p>
<p>Type: nullable list of <a href="https://xplr.dev/en/borders#border">Border</a></p>
<h4 id="xplrconfiggeneralpanel_uiselectionborder_type"><a class="header" href="#xplrconfiggeneralpanel_uiselectionborder_type">xplr.config.general.panel_ui.selection.border_type</a></h4>
<p>Type of the borders for selection panel.</p>
<p>Type: nullable <a href="https://xplr.dev/en/borders#border-type">Border Type</a></p>
<h4 id="xplrconfiggeneralpanel_uiselectionborder_style"><a class="header" href="#xplrconfiggeneralpanel_uiselectionborder_style">xplr.config.general.panel_ui.selection.border_style</a></h4>
<p>Style of the selection panel borders.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uisort_and_filtertitleformat"><a class="header" href="#xplrconfiggeneralpanel_uisort_and_filtertitleformat">xplr.config.general.panel_ui.sort_and_filter.title.format</a></h4>
<p>The content for the sort &amp; filter panel title.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralpanel_uisort_and_filtertitlestyle"><a class="header" href="#xplrconfiggeneralpanel_uisort_and_filtertitlestyle">xplr.config.general.panel_ui.sort_and_filter.title.style</a></h4>
<p>Style of the sort &amp; filter panel title.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uisort_and_filterstyle"><a class="header" href="#xplrconfiggeneralpanel_uisort_and_filterstyle">xplr.config.general.panel_ui.sort_and_filter.style</a></h4>
<p>Style of the sort &amp; filter panel.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralpanel_uisort_and_filterborders"><a class="header" href="#xplrconfiggeneralpanel_uisort_and_filterborders">xplr.config.general.panel_ui.sort_and_filter.borders</a></h4>
<p>Defines where to show borders for the sort &amp; filter panel.</p>
<p>Type: nullable list of <a href="https://xplr.dev/en/borders#border">Border</a></p>
<h4 id="xplrconfiggeneralpanel_uisort_and_filterborder_type"><a class="header" href="#xplrconfiggeneralpanel_uisort_and_filterborder_type">xplr.config.general.panel_ui.sort_and_filter.border_type</a></h4>
<p>Type of the borders for sort &amp; filter panel.</p>
<p>Type: nullable <a href="https://xplr.dev/en/borders#border-type">Border Type</a></p>
<h4 id="xplrconfiggeneralpanel_uisort_and_filterborder_style"><a class="header" href="#xplrconfiggeneralpanel_uisort_and_filterborder_style">xplr.config.general.panel_ui.sort_and_filter.border_style</a></h4>
<p>Style of the sort &amp; filter panel borders.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfiggeneralinitial_sorting"><a class="header" href="#xplrconfiggeneralinitial_sorting">xplr.config.general.initial_sorting</a></h4>
<p>Initial group if sorters applied to the nodes list in the table.</p>
<p>Type: nullable list of <a href="https://xplr.dev/en/sorting#node-sorter-applicable">Node Sorter</a></p>
<h4 id="xplrconfiggeneralinitial_mode"><a class="header" href="#xplrconfiggeneralinitial_mode">xplr.config.general.initial_mode</a></h4>
<p>The name of one of the modes to use when xplr loads.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralinitial_layout"><a class="header" href="#xplrconfiggeneralinitial_layout">xplr.config.general.initial_layout</a></h4>
<p>The name of one of the layouts to use when xplr loads.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralstart_fifo"><a class="header" href="#xplrconfiggeneralstart_fifo">xplr.config.general.start_fifo</a></h4>
<p>Set it to a file path to start fifo when xplr loads.
Generally it is used to integrate with external tools like previewers.</p>
<p>Type: nullable string</p>
<h4 id="xplrconfiggeneralglobal_key_bindings"><a class="header" href="#xplrconfiggeneralglobal_key_bindings">xplr.config.general.global_key_bindings</a></h4>
<p>Use it to define a set of key bindings that are available by default in
every <a href="https://xplr.dev/en/mode">mode</a>. They can be overwritten.</p>
<p>Type: <a href="https://xplr.dev/en/configure-key-bindings#key-bindings">Key Bindings</a></p>
<div style="break-before: page; page-break-before: always;"></div><h3 id="node-types"><a class="header" href="#node-types">Node Types</a></h3>
<p>This section defines how to deal with different kinds of nodes (files,
directories, symlinks etc.) based on their properties.</p>
<p>One node can fall into multiple categories. For example, a node can have the
<em>extension</em> <code>md</code>, and also be a <em>file</em>. In that case, the properties from
the more specific category i.e. <em>extension</em> will be used.</p>
<p>This can be configured using the <code>xplr.config.node_types</code> Lua API.</p>
<h4 id="xplrconfignode_typesdirectorystyle"><a class="header" href="#xplrconfignode_typesdirectorystyle">xplr.config.node_types.directory.style</a></h4>
<p>The style for the directory nodes</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfignode_typesdirectorymetaicon"><a class="header" href="#xplrconfignode_typesdirectorymetaicon">xplr.config.node_types.directory.meta.icon</a></h4>
<p>Metadata for the directory nodes.
You can set as many metadata as you want.</p>
<p>Type: nullable string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.config.node_types.directory.meta.foo = &quot;foo&quot;
xplr.config.node_types.directory.meta.bar = &quot;bar&quot;
</code></pre>
<h4 id="xplrconfignode_typesfilestyle"><a class="header" href="#xplrconfignode_typesfilestyle">xplr.config.node_types.file.style</a></h4>
<p>The style for the file nodes.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfignode_typesfilemetaicon"><a class="header" href="#xplrconfignode_typesfilemetaicon">xplr.config.node_types.file.meta.icon</a></h4>
<p>Metadata for the file nodes.
You can set as many metadata as you want.</p>
<p>Type: nullable string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.config.node_types.file.meta.foo = &quot;foo&quot;
xplr.config.node_types.file.meta.bar = &quot;bar&quot;
</code></pre>
<h4 id="xplrconfignode_typessymlinkstyle"><a class="header" href="#xplrconfignode_typessymlinkstyle">xplr.config.node_types.symlink.style</a></h4>
<p>The style for the symlink nodes.</p>
<p>Type: <a href="https://xplr.dev/en/style">Style</a></p>
<h4 id="xplrconfignode_typessymlinkmetaicon"><a class="header" href="#xplrconfignode_typessymlinkmetaicon">xplr.config.node_types.symlink.meta.icon</a></h4>
<p>Metadata for the symlink nodes.
You can set as many metadata as you want.</p>
<p>Type: nullable string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.config.node_types.symlink.meta.foo = &quot;foo&quot;
xplr.config.node_types.symlink.meta.bar = &quot;bar&quot;
</code></pre>
<h4 id="xplrconfignode_typesmime_essence"><a class="header" href="#xplrconfignode_typesmime_essence">xplr.config.node_types.mime_essence</a></h4>
<p>Metadata and style based on mime types.
It is possible to use the wildcard <code>*</code> to match all mime sub types. It will
be overwritten by the more specific sub types that are defined.</p>
<p>Type: mapping of the following key-value pairs:</p>
<ul>
<li>key: string</li>
<li>value:
<ul>
<li>key: string</li>
<li>value: <a href="https://xplr.dev/en/node-type">Node Type</a></li>
</ul>
</li>
</ul>
<p>Example:</p>
<pre><code class="language-lua">xplr.config.node_types.mime_essence = {
application = {
-- application/*
[&quot;*&quot;] = { meta = { icon = &quot;a&quot; } },
-- application/pdf
pdf = { meta = { icon = &quot;&quot; }, style = { fg = &quot;Blue&quot; } },
-- application/zip
zip = { meta = { icon = &quot;&quot;} },
},
}
</code></pre>
<h4 id="xplrconfignode_typesextension"><a class="header" href="#xplrconfignode_typesextension">xplr.config.node_types.extension</a></h4>
<p>Metadata and style based on extension.</p>
<p>Type: mapping of the following key-value pairs:</p>
<ul>
<li>key: string</li>
<li>value: <a href="https://xplr.dev/en/node-type">Node Type</a></li>
</ul>
<p>Example:</p>
<pre><code class="language-lua">xplr.config.node_types.extension.md = { meta = { icon = &quot;&quot; }, style = { fg = &quot;Blue&quot; } }
xplr.config.node_types.extension.rs = { meta = { icon = &quot;🦀&quot; } }
</code></pre>
<h4 id="xplrconfignode_typesspecial"><a class="header" href="#xplrconfignode_typesspecial">xplr.config.node_types.special</a></h4>
<p>Metadata and style based on special file names.</p>
<p>Type: mapping of the following key-value pairs:</p>
<ul>
<li>key: string</li>
<li>value: <a href="https://xplr.dev/en/node-type">Node Type</a></li>
</ul>
<p>Example:</p>
<pre><code class="language-lua">xplr.config.node_types.special[&quot;Cargo.toml&quot;] = { meta = { icon = &quot;&quot; } }
xplr.config.node_types.special[&quot;Downloads&quot;] = { meta = { icon = &quot;&quot; }, style = { fg = &quot;Blue&quot; } }
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h3 id="layouts"><a class="header" href="#layouts">Layouts</a></h3>
<p>xplr layouts define the structure of the UI, i.e. how many panel we see,
placement and size of the panels, how they look etc.</p>
<p>This is configuration exposed via the <code>xplr.config.layouts</code> API.</p>
<p><code>xplr.config.layouts.builtin</code> contain some built-in panels which can be
overridden, but you can't add or remove panels in it.</p>
<p>You can add new panels in <code>xplr.config.layouts.custom</code>.</p>
<h5 id="example-defining-custom-layout"><a class="header" href="#example-defining-custom-layout">Example: Defining Custom Layout</a></h5>
<p><img src="https://s6.gifyu.com/images/layout.png" alt="demo" /></p>
<pre><code class="language-lua">xplr.config.layouts.builtin.default = {
Horizontal = {
config = {
margin = 1,
horizontal_margin = 2,
vertical_margin = 3,
constraints = {
{ Percentage = 50 },
{ Percentage = 50 },
}
},
splits = {
&quot;Table&quot;,
&quot;HelpMenu&quot;,
}
}
}
</code></pre>
<h4 id="xplrconfiglayoutsbuiltindefault"><a class="header" href="#xplrconfiglayoutsbuiltindefault">xplr.config.layouts.builtin.default</a></h4>
<p>The default layout</p>
<p>Type: <a href="https://xplr.dev/en/layout">Layout</a></p>
<h4 id="xplrconfiglayoutsbuiltinno_help"><a class="header" href="#xplrconfiglayoutsbuiltinno_help">xplr.config.layouts.builtin.no_help</a></h4>
<p>The layout without help menu</p>
<p>Type: <a href="https://xplr.dev/en/layout">Layout</a></p>
<h4 id="xplrconfiglayoutsbuiltinno_selection"><a class="header" href="#xplrconfiglayoutsbuiltinno_selection">xplr.config.layouts.builtin.no_selection</a></h4>
<p>The layout without selection panel</p>
<p>Type: <a href="https://xplr.dev/en/layout">Layout</a></p>
<h4 id="xplrconfiglayoutsbuiltinno_help_no_selection"><a class="header" href="#xplrconfiglayoutsbuiltinno_help_no_selection">xplr.config.layouts.builtin.no_help_no_selection</a></h4>
<p>The layout without help menu and selection panel</p>
<p>Type: <a href="https://xplr.dev/en/layout">Layout</a></p>
<h4 id="xplrconfiglayoutscustom"><a class="header" href="#xplrconfiglayoutscustom">xplr.config.layouts.custom</a></h4>
<p>This is where you can define custom layouts</p>
<p>Type: mapping of the following key-value pairs:</p>
<ul>
<li>key: string</li>
<li>value: <a href="https://xplr.dev/en/layout">Layout</a></li>
</ul>
<p>Example:</p>
<pre><code class="language-lua">xplr.config.layouts.custom.example = &quot;Nothing&quot; -- Show a blank screen
xplr.config.general.initial_layout = &quot;example&quot; -- Load the example layout
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h3 id="modes"><a class="header" href="#modes">Modes</a></h3>
<p>xplr is a modal file explorer. That means the users switch between different
modes, each containing a different set of key bindings to avoid clashes.
Users can switch between these modes at run-time.</p>
<p>The modes can be configured using the <code>xplr.config.modes</code> Lua API.</p>
<p><code>xplr.config.modes.builtin</code> contain some built-in modes which can be
overridden, but you can't add or remove modes in it.</p>
<h4 id="xplrconfigmodesbuiltindefault"><a class="header" href="#xplrconfigmodesbuiltindefault">xplr.config.modes.builtin.default</a></h4>
<p>The builtin default mode.
Visit the <a href="https://xplr.dev/en/default-key-bindings">Default Key Bindings</a>
to see what each mode does.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltindebug_error"><a class="header" href="#xplrconfigmodesbuiltindebug_error">xplr.config.modes.builtin.debug_error</a></h4>
<p>The builtin debug error mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinrecover"><a class="header" href="#xplrconfigmodesbuiltinrecover">xplr.config.modes.builtin.recover</a></h4>
<p>The builtin recover mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltingo_to_path"><a class="header" href="#xplrconfigmodesbuiltingo_to_path">xplr.config.modes.builtin.go_to_path</a></h4>
<p>The builtin go to path mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinselection_ops"><a class="header" href="#xplrconfigmodesbuiltinselection_ops">xplr.config.modes.builtin.selection_ops</a></h4>
<p>The builtin selection ops mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltincreate"><a class="header" href="#xplrconfigmodesbuiltincreate">xplr.config.modes.builtin.create</a></h4>
<p>The builtin create mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltincreate_directory"><a class="header" href="#xplrconfigmodesbuiltincreate_directory">xplr.config.modes.builtin.create_directory</a></h4>
<p>The builtin create directory mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltincreate_file"><a class="header" href="#xplrconfigmodesbuiltincreate_file">xplr.config.modes.builtin.create_file</a></h4>
<p>The builtin create file mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinnumber"><a class="header" href="#xplrconfigmodesbuiltinnumber">xplr.config.modes.builtin.number</a></h4>
<p>The builtin number mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltingo_to"><a class="header" href="#xplrconfigmodesbuiltingo_to">xplr.config.modes.builtin.go_to</a></h4>
<p>The builtin go to mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinrename"><a class="header" href="#xplrconfigmodesbuiltinrename">xplr.config.modes.builtin.rename</a></h4>
<p>The builtin rename mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinduplicate_as"><a class="header" href="#xplrconfigmodesbuiltinduplicate_as">xplr.config.modes.builtin.duplicate_as</a></h4>
<p>The builtin duplicate as mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltindelete"><a class="header" href="#xplrconfigmodesbuiltindelete">xplr.config.modes.builtin.delete</a></h4>
<p>The builtin delete mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinaction"><a class="header" href="#xplrconfigmodesbuiltinaction">xplr.config.modes.builtin.action</a></h4>
<p>The builtin action mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinquit"><a class="header" href="#xplrconfigmodesbuiltinquit">xplr.config.modes.builtin.quit</a></h4>
<p>The builtin quit mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinsearch"><a class="header" href="#xplrconfigmodesbuiltinsearch">xplr.config.modes.builtin.search</a></h4>
<p>The builtin search mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinfilter"><a class="header" href="#xplrconfigmodesbuiltinfilter">xplr.config.modes.builtin.filter</a></h4>
<p>The builtin filter mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinrelative_path_does_match_regex"><a class="header" href="#xplrconfigmodesbuiltinrelative_path_does_match_regex">xplr.config.modes.builtin.relative_path_does_match_regex</a></h4>
<p>The builtin relative_path_does_match_regex mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinrelative_path_does_not_match_regex"><a class="header" href="#xplrconfigmodesbuiltinrelative_path_does_not_match_regex">xplr.config.modes.builtin.relative_path_does_not_match_regex</a></h4>
<p>The builtin relative_path_does_not_match_regex mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinsort"><a class="header" href="#xplrconfigmodesbuiltinsort">xplr.config.modes.builtin.sort</a></h4>
<p>The builtin sort mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinswitch_layout"><a class="header" href="#xplrconfigmodesbuiltinswitch_layout">xplr.config.modes.builtin.switch_layout</a></h4>
<p>The builtin switch layout mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinvroot"><a class="header" href="#xplrconfigmodesbuiltinvroot">xplr.config.modes.builtin.vroot</a></h4>
<p>The builtin vroot mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodesbuiltinedit_permissions"><a class="header" href="#xplrconfigmodesbuiltinedit_permissions">xplr.config.modes.builtin.edit_permissions</a></h4>
<p>The builtin edit permissions mode.</p>
<p>Type: <a href="https://xplr.dev/en/mode">Mode</a></p>
<h4 id="xplrconfigmodescustom"><a class="header" href="#xplrconfigmodescustom">xplr.config.modes.custom</a></h4>
<p>This is where you define custom modes.</p>
<p>Type: mapping of the following key-value pairs:</p>
<ul>
<li>key: string</li>
<li>value: <a href="https://xplr.dev/en/mode">Mode</a></li>
</ul>
<p>Example:</p>
<pre><code class="language-lua">xplr.config.modes.custom.example = {
name = &quot;example&quot;,
key_bindings = {
on_key = {
enter = {
help = &quot;default mode&quot;,
messages = {
&quot;PopMode&quot;,
{ SwitchModeBuiltin = &quot;default&quot; },
},
},
},
},
}
xplr.config.general.initial_mode = &quot;example&quot;
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="concept-1"><a class="header" href="#concept-1">Concept</a></h1>
<p>These are the concepts that make xplr probably the most hackable terminal file
explorer.</p>
<ul>
<li><a href="key-bindings.html">Key Bindings</a></li>
<li><a href="node-type.html">Node Type</a></li>
<li><a href="layout.html">Layout</a></li>
<li><a href="mode.html">Mode</a></li>
<li><a href="message.html">Message</a></li>
<li><a href="borders.html">Borders</a></li>
<li><a href="style.html">Style</a></li>
<li><a href="sorting.html">Sorting</a></li>
<li><a href="filtering.html">Filtering</a></li>
<li><a href="column-renderer.html">Column Renderer</a></li>
<li><a href="lua-function-calls.html">Lua Function Calls</a></li>
<li><a href="environment-variables-and-pipes.html">Environment Variables and Pipes</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="sum-type"><a class="header" href="#sum-type">Sum Type</a></h1>
<blockquote>
<p>This section isn't specific to xplr. However, since xplr configuration makes
heavy use of this particular data type, even though it isn't available in
most of the mainstream programming languages (yet), making it a wild or
unfamiliar concept for many, it's worth doing a quick introduction here.</p>
<p>If you're already familiar with <a href="https://en.wikipedia.org/wiki/Tagged_union">Sum Type / Tagged Union</a> (e.g. Rust's
enum), you can skip ahead.</p>
</blockquote>
<p>While reading this doc, you'll come across some data types like <a href="layout.html">Layout</a>,
<a href="style.html#color">Color</a>, <a href="message.html">Message</a> etc. that says something like &quot;x is a sum type that
can be any of the following&quot;, and then you'll see a list of strings and/or lua
tables just below.</p>
<p>Yes, they are actually sum types, i.e. they can be any of the given set of
tagged variants listed there.</p>
<p>Notice the word &quot;be&quot;. Unlike classes or structs (aka product types), they don't
&quot;have&quot; values, they &quot;are&quot; (i.e. &quot;be&quot;) the value, or rather, one of the possible
set of values.</p>
<p>Also notice the word &quot;tagged&quot;. Unlike the single variant <code>null</code>, or the dual
variant <code>boolean</code> types, the variants of sum types are tagged (i.e. named), and
may further have, or be, value or values of any data type.</p>
<p>A simple example of a sum type is an enum. Many programming languages have
them, but only a few modern programming languages allow nesting other types
into a sum type.</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum Result {
Ok,
Err,
}
<span class="boring">}
</span></code></pre></pre>
<p>Here, <code>Result</code> can be one of two the possible values: &quot;Ok&quot; and &quot;Err&quot; (just like
<code>boolean</code>, but tagged):</p>
<p>We'd document it here as:</p>
<blockquote>
<p>Result is a sum type that can be one of the following:</p>
<ul>
<li>&quot;Ok&quot;</li>
<li>&quot;Err&quot;</li>
</ul>
</blockquote>
<p>But some languages (like Rust, Haskell, Elm etc.) go even further, allowing us
to associate each branch of the enum with further nested types like:</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum Result {
Ok(bool),
Err(String),
}
<span class="boring">}
</span></code></pre></pre>
<p>We'd document it here as:</p>
<blockquote>
<p>Result is a sum type that can be one of the following:</p>
<ul>
<li>{ Ok = bool }</li>
<li>{ Err = &quot;string&quot; }</li>
</ul>
</blockquote>
<p>Here, <code>Result</code> still has only two possibilities, but unlike bool, each
possibility here is tagged, and has further set of possible value(s).</p>
<p>And there you go. This is exactly what sum types are - glorified enums that can
have nested types in each branch.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="key-bindings"><a class="header" href="#key-bindings">Key Bindings</a></h1>
<p>Key bindings define how each keyboard input will be handled while in a specific
<a href="modes.html#mode">mode</a>.</p>
<p>See the <a href="default-key-bindings.html">Default key bindings</a> for example.</p>
<p>To configure or work with key bindings, visit <a href="configure-key-bindings.html">Configure Key Bindings</a>.</p>
<p>In case you need help debugging key bindings or to understand the system DYI
way, refer to the <a href="debug-key-bindings.html">Debug Key Bindings</a> guide.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="configure-key-bindings"><a class="header" href="#configure-key-bindings">Configure Key Bindings</a></h1>
<p>In xplr, each keyboard input passes through a bunch of handlers (e.g. <code>on_key</code>,
<code>on_number</code>, <code>default</code> etc.) in a given order. If any of the handlers is
configured to with an <a href="configure-key-bindings.html#action">action</a>, it will intercept the key and produce
<a href="message.html#message">messages</a> for xplr to handle.</p>
<p>Try <a href="debug-key-bindings.html">debug key bindings</a> to understand how key bindings actually work.</p>
<h2 id="key-bindings-1"><a class="header" href="#key-bindings-1">Key Bindings</a></h2>
<p>Key bindings contains the following information:</p>
<ul>
<li><a href="configure-key-bindings.html#on_key">on_key</a></li>
<li><a href="configure-key-bindings.html#on_alphabet">on_alphabet</a></li>
<li><a href="configure-key-bindings.html#on_number">on_number</a></li>
<li><a href="configure-key-bindings.html#on_alphanumeric">on_alphanumeric</a></li>
<li><a href="configure-key-bindings.html#on_special_character">on_special_character</a></li>
<li><a href="configure-key-bindings.html#on_character">on_character</a></li>
<li><a href="configure-key-bindings.html#on_navigation">on_navigation</a></li>
<li><a href="configure-key-bindings.html#on_function">on_function</a></li>
<li><a href="configure-key-bindings.html#default">default</a></li>
</ul>
<h3 id="on_key"><a class="header" href="#on_key">on_key</a></h3>
<p>Type: mapping of <a href="configure-key-bindings.html#key">Key</a> to nullable <a href="configure-key-bindings.html#action">Action</a></p>
<p>Defines what to do when an exact key is pressed.</p>
<h3 id="on_alphabet"><a class="header" href="#on_alphabet">on_alphabet</a></h3>
<p>Type: nullable <a href="configure-key-bindings.html#action">Action</a></p>
<p>An action to perform if the keyboard input is an alphabet and is not mapped via
the <a href="configure-key-bindings.html#on_key">on_key</a> field.</p>
<h3 id="on_number"><a class="header" href="#on_number">on_number</a></h3>
<p>Type: nullable <a href="configure-key-bindings.html#action">Action</a></p>
<p>An action to perform if the keyboard input is a number and is not mapped via
the <a href="configure-key-bindings.html#on_key">on_key</a> field.</p>
<h3 id="on_alphanumeric"><a class="header" href="#on_alphanumeric">on_alphanumeric</a></h3>
<p>Type: nullable <a href="configure-key-bindings.html#action">Action</a></p>
<p>An action to perform if the keyboard input is alphanumeric and is not mapped
via the <a href="configure-key-bindings.html#on_key">on_key</a>, <a href="configure-key-bindings.html#on_alphabet">on_alphabet</a> or <a href="configure-key-bindings.html#on_number">on_number</a> field.</p>
<h3 id="on_special_character"><a class="header" href="#on_special_character">on_special_character</a></h3>
<p>Type: nullable <a href="configure-key-bindings.html#action">Action</a></p>
<p>An action to perform if the keyboard input is a special character and is not
mapped via the <a href="configure-key-bindings.html#on_key">on_key</a> field.</p>
<h3 id="on_character"><a class="header" href="#on_character">on_character</a></h3>
<p>Type: nullable <a href="configure-key-bindings.html#action">Action</a></p>
<p>An action to perform if the keyboard input is a character and is not mapped
via the <a href="configure-key-bindings.html#on_key">on_key</a>, <a href="configure-key-bindings.html#on_alphabet">on_alphabet</a>, <a href="configure-key-bindings.html#on_number">on_number</a>, <a href="configure-key-bindings.html#on_alphanumeric">on_alphanumeric</a>
or <a href="configure-key-bindings.html#on_special_character">on_special_character</a> field.</p>
<h3 id="on_navigation"><a class="header" href="#on_navigation">on_navigation</a></h3>
<p>Type: nullable <a href="configure-key-bindings.html#action">Action</a></p>
<p>An action to perform if the keyboard input is a navigation key and is not
mapped via the <a href="configure-key-bindings.html#on_key">on_key</a> field.</p>
<h3 id="on_function"><a class="header" href="#on_function">on_function</a></h3>
<p>Type: nullable <a href="configure-key-bindings.html#action">Action</a></p>
<p>An action to perform if the keyboard input is a function key and is not mapped
via the <a href="configure-key-bindings.html#on_key">on_key</a> field.</p>
<h3 id="default"><a class="header" href="#default">default</a></h3>
<p>Type: nullable <a href="configure-key-bindings.html#action">Action</a></p>
<p>Default action to perform in case if a keyboard input not mapped via any of the
<code>on_*</code> fields mentioned above.</p>
<h2 id="key"><a class="header" href="#key">Key</a></h2>
<p>A key is a <a href="sum-type.html">sum type</a> can be one of the following:</p>
<ul>
<li>0, 1, ... 9</li>
<li>a, b, ... z</li>
<li>A, B, ... Z</li>
<li>f1, f2, ... f12</li>
<li>backspace</li>
<li>left</li>
<li>right</li>
<li>up</li>
<li>down</li>
<li>home</li>
<li>end</li>
<li>page-up</li>
<li>page-down</li>
<li>back-tab</li>
<li>delete</li>
<li>insert</li>
<li>enter</li>
<li>tab</li>
<li>esc</li>
<li>ctrl-a, ctrl-b, ... ctrl-z</li>
<li>ctrl-backspace, ctrl-left, ... ctrl-esc</li>
<li>alt-a, alt-b, ... alt-z</li>
</ul>
<p>And finally, the special characters - including space (<code>&quot; &quot;</code>) with their <code>ctrl</code>
bindings.</p>
<h2 id="action"><a class="header" href="#action">Action</a></h2>
<p>An action contains the following information:</p>
<ul>
<li><a href="configure-key-bindings.html#help">help</a></li>
<li><a href="configure-key-bindings.html#messages">messages</a></li>
</ul>
<h3 id="help"><a class="header" href="#help">help</a></h3>
<p>Type: nullable string</p>
<p>Description of what it does. If unspecified, it will be excluded from the help
menu.</p>
<h3 id="messages"><a class="header" href="#messages">messages</a></h3>
<p>Type: A list of <a href="message.html#message">Message</a> to send.</p>
<p>The list of messages to send when a key is pressed.</p>
<h2 id="tutorial-adding-a-new-mode"><a class="header" href="#tutorial-adding-a-new-mode">Tutorial: Adding a New Mode</a></h2>
<p>Assuming xplr is <a href="install.html">installed</a> and <a href="post-install.html">setup</a>, let's
add our own mode to integrate xplr with <a href="https://github.com/junegunn/fzf">fzf</a>.</p>
<p>We'll call it <code>fzxplr</code> mode.</p>
<p>First, let's add a custom mode called <code>fzxplr</code>, and map the key <code>F</code> to an
action that will call <code>fzf</code> to search and focus on a file or enter into a
directory.</p>
<pre><code class="language-lua">xplr.config.modes.custom.fzxplr = {
name = &quot;fzxplr&quot;,
key_bindings = {
on_key = {
F = {
help = &quot;search&quot;,
messages = {
{
BashExec = [===[
PTH=$(cat &quot;${XPLR_PIPE_DIRECTORY_NODES_OUT:?}&quot; | awk -F/ '{print $NF}' | fzf)
if [ -d &quot;$PTH&quot; ]; then
&quot;$XPLR&quot; -m 'ChangeDirectory: %q' &quot;$PTH&quot;
else
&quot;$XPLR&quot; -m 'FocusPath: %q' &quot;$PTH&quot;
fi
]===]
},
&quot;PopMode&quot;,
},
},
},
default = {
messages = {
&quot;PopMode&quot;,
},
},
},
}
</code></pre>
<p>As you can see, the key <code>F</code> in mode <code>fzxplr</code> (the name can be anything)
executes a script in <code>bash</code>.</p>
<p><code>BashExec</code>, <code>PopMode</code>, <code>SwitchModeBuiltin</code>, <code>ChangeDirectory</code> and <code>FocusPath</code>
are <a href="message.html#message">messages</a>, <code>$XPLR</code>, <code>$XPLR_PIPE_DIRECTORY_NODES_OUT</code> are
<a href="environment-variables-and-pipes.html#environment-variables">environment variables</a> exported by <code>xplr</code> before executing the command.
They contain the path to the <a href="environment-variables-and-pipes.html#input-pipe">input</a> and <a href="environment-variables-and-pipes.html#output-pipes">output</a> pipes that allows
external tools to interact with <code>xplr</code>.</p>
<p>Now that we have our new mode ready, let's add an entry point to this mode via
the <code>default</code> mode.</p>
<pre><code class="language-lua">xplr.config.modes.builtin.default.key_bindings.on_key[&quot;F&quot;] = {
help = &quot;fzf mode&quot;,
messages = {
{ SwitchModeCustom = &quot;fzxplr&quot; },
},
}
</code></pre>
<p>Now let's try out the new <code>xplr</code>-<code>fzf</code> integration.</p>
<p><a href="https://gifyu.com/image/tW86"><img src="https://s3.gifyu.com/images/xplr-fzf.gif" alt="xplr-fzf.gif" /></a></p>
<hr />
<p>Visit <a href="awesome-plugins.html">Awesome Plugins</a> for more <a href="awesome-plugins.html#integration">integration</a> options.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="default-key-bindings"><a class="header" href="#default-key-bindings">Default Key Bindings</a></h1>
<p>The default key binding is inspired by <a href="https://www.vim.org/">vim</a> and slightly
overlaps with <a href="https://github.com/jarun/nnn/">nnn</a>, but it's supposed to be customized as per user
requirements.</p>
<p>When you press <code>?</code> in <a href="default-key-bindings.html#default">default mode</a>, you can see the complete list
of <a href="modes.html">modes</a> and the key mappings for each mode.</p>
<h3 id="default-1"><a class="header" href="#default-1">default</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>.</td><td></td><td>show hidden</td></tr>
<tr><td>/</td><td>ctrl-f</td><td>search</td></tr>
<tr><td>:</td><td></td><td>action</td></tr>
<tr><td>?</td><td></td><td>global help menu</td></tr>
<tr><td>G</td><td></td><td>go to bottom</td></tr>
<tr><td>V</td><td>ctrl-a</td><td>select/unselect all</td></tr>
<tr><td>ctrl-d</td><td></td><td>duplicate as</td></tr>
<tr><td>ctrl-i</td><td></td><td>next visited path</td></tr>
<tr><td>ctrl-n</td><td></td><td>next selection</td></tr>
<tr><td>ctrl-o</td><td></td><td>last visited path</td></tr>
<tr><td>ctrl-p</td><td></td><td>prev selection</td></tr>
<tr><td>ctrl-r</td><td></td><td>refresh screen</td></tr>
<tr><td>ctrl-u</td><td></td><td>clear selection</td></tr>
<tr><td>ctrl-w</td><td></td><td>switch layout</td></tr>
<tr><td>d</td><td></td><td>delete</td></tr>
<tr><td>down</td><td>j</td><td>down</td></tr>
<tr><td>enter</td><td></td><td>quit with result</td></tr>
<tr><td>f</td><td></td><td>filter</td></tr>
<tr><td>g</td><td></td><td>go to</td></tr>
<tr><td>h</td><td>left</td><td>back</td></tr>
<tr><td>k</td><td>up</td><td>up</td></tr>
<tr><td>l</td><td>right</td><td>enter</td></tr>
<tr><td>page-down</td><td></td><td>scroll down</td></tr>
<tr><td>page-up</td><td></td><td>scroll up</td></tr>
<tr><td>q</td><td></td><td>quit</td></tr>
<tr><td>r</td><td></td><td>rename</td></tr>
<tr><td>s</td><td></td><td>sort</td></tr>
<tr><td>space</td><td>v</td><td>toggle selection</td></tr>
<tr><td>{</td><td></td><td>scroll up half</td></tr>
<tr><td>}</td><td></td><td>scroll down half</td></tr>
<tr><td>~</td><td></td><td>go home</td></tr>
<tr><td>[0-9]</td><td></td><td>input</td></tr>
</tbody></table>
<h3 id="vroot"><a class="header" href="#vroot">vroot</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>.</td><td></td><td>vroot $PWD</td></tr>
<tr><td>/</td><td></td><td>vroot /</td></tr>
<tr><td>ctrl-r</td><td></td><td>reset vroot</td></tr>
<tr><td>ctrl-u</td><td></td><td>unset vroot</td></tr>
<tr><td>v</td><td></td><td>toggle vroot</td></tr>
<tr><td>~</td><td></td><td>vroot $HOME</td></tr>
</tbody></table>
<h3 id="relative_path_does_match_regex"><a class="header" href="#relative_path_does_match_regex">relative_path_does_match_regex</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>enter</td><td></td><td>submit</td></tr>
</tbody></table>
<h3 id="go_to_path"><a class="header" href="#go_to_path">go_to_path</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>enter</td><td></td><td>submit</td></tr>
<tr><td>tab</td><td></td><td>try complete</td></tr>
</tbody></table>
<h3 id="duplicate_as"><a class="header" href="#duplicate_as">duplicate_as</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>enter</td><td></td><td>submit</td></tr>
<tr><td>tab</td><td></td><td>try complete</td></tr>
</tbody></table>
<h3 id="debug_error"><a class="header" href="#debug_error">debug_error</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>enter</td><td></td><td>open logs in editor</td></tr>
<tr><td>q</td><td></td><td>quit</td></tr>
</tbody></table>
<h3 id="selection_ops"><a class="header" href="#selection_ops">selection_ops</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>c</td><td></td><td>copy here</td></tr>
<tr><td>e</td><td></td><td>edit selection</td></tr>
<tr><td>h</td><td></td><td>hardlink here</td></tr>
<tr><td>l</td><td></td><td>list selection</td></tr>
<tr><td>m</td><td></td><td>move here</td></tr>
<tr><td>s</td><td></td><td>softlink here</td></tr>
<tr><td>u</td><td></td><td>clear selection</td></tr>
</tbody></table>
<h3 id="sort"><a class="header" href="#sort">sort</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>!</td><td></td><td>reverse sorters</td></tr>
<tr><td>C</td><td></td><td>by created reverse</td></tr>
<tr><td>E</td><td></td><td>by canonical extension reverse</td></tr>
<tr><td>L</td><td></td><td>by last modified reverse</td></tr>
<tr><td>M</td><td></td><td>by canonical mime essence reverse</td></tr>
<tr><td>N</td><td></td><td>by node type reverse</td></tr>
<tr><td>R</td><td></td><td>by relative path reverse</td></tr>
<tr><td>S</td><td></td><td>by size reverse</td></tr>
<tr><td>backspace</td><td></td><td>remove last sorter</td></tr>
<tr><td>c</td><td></td><td>by created</td></tr>
<tr><td>ctrl-r</td><td></td><td>reset sorters</td></tr>
<tr><td>ctrl-u</td><td></td><td>clear sorters</td></tr>
<tr><td>e</td><td></td><td>by canonical extension</td></tr>
<tr><td>enter</td><td></td><td>submit</td></tr>
<tr><td>l</td><td></td><td>by last modified</td></tr>
<tr><td>m</td><td></td><td>by canonical mime essence</td></tr>
<tr><td>n</td><td></td><td>by node type</td></tr>
<tr><td>r</td><td></td><td>by relative path</td></tr>
<tr><td>s</td><td></td><td>by size</td></tr>
</tbody></table>
<h3 id="go_to"><a class="header" href="#go_to">go_to</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>f</td><td></td><td>follow symlink</td></tr>
<tr><td>g</td><td></td><td>top</td></tr>
<tr><td>i</td><td></td><td>initial $PWD</td></tr>
<tr><td>p</td><td></td><td>path</td></tr>
<tr><td>x</td><td></td><td>open in gui</td></tr>
</tbody></table>
<h3 id="edit_permissions"><a class="header" href="#edit_permissions">edit_permissions</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>G</td><td></td><td>-group</td></tr>
<tr><td>M</td><td></td><td>min</td></tr>
<tr><td>O</td><td></td><td>-other</td></tr>
<tr><td>U</td><td></td><td>-user</td></tr>
<tr><td>ctrl-r</td><td></td><td>reset</td></tr>
<tr><td>enter</td><td></td><td>submit</td></tr>
<tr><td>g</td><td></td><td>+group</td></tr>
<tr><td>m</td><td></td><td>max</td></tr>
<tr><td>o</td><td></td><td>+other</td></tr>
<tr><td>u</td><td></td><td>+user</td></tr>
</tbody></table>
<h3 id="switch_layout"><a class="header" href="#switch_layout">switch_layout</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>1</td><td></td><td>default</td></tr>
<tr><td>2</td><td></td><td>no help menu</td></tr>
<tr><td>3</td><td></td><td>no selection panel</td></tr>
<tr><td>4</td><td></td><td>no help or selection</td></tr>
</tbody></table>
<h3 id="create"><a class="header" href="#create">create</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>d</td><td></td><td>create directory</td></tr>
<tr><td>f</td><td></td><td>create file</td></tr>
</tbody></table>
<h3 id="create_directory"><a class="header" href="#create_directory">create_directory</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>enter</td><td></td><td>submit</td></tr>
<tr><td>tab</td><td></td><td>try complete</td></tr>
</tbody></table>
<h3 id="create_file"><a class="header" href="#create_file">create_file</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>enter</td><td></td><td>submit</td></tr>
<tr><td>tab</td><td></td><td>try complete</td></tr>
</tbody></table>
<h3 id="search"><a class="header" href="#search">search</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>ctrl-a</td><td></td><td>toggle search algorithm</td></tr>
<tr><td>ctrl-f</td><td></td><td>fuzzy search</td></tr>
<tr><td>ctrl-n</td><td>down</td><td>down</td></tr>
<tr><td>ctrl-p</td><td>up</td><td>up</td></tr>
<tr><td>ctrl-r</td><td></td><td>regex search</td></tr>
<tr><td>ctrl-s</td><td></td><td>sort (no search order)</td></tr>
<tr><td>ctrl-z</td><td></td><td>toggle ordering</td></tr>
<tr><td>enter</td><td></td><td>submit</td></tr>
<tr><td>esc</td><td></td><td>cancel</td></tr>
<tr><td>left</td><td></td><td>back</td></tr>
<tr><td>right</td><td></td><td>enter</td></tr>
<tr><td>tab</td><td></td><td>toggle selection</td></tr>
</tbody></table>
<h3 id="number"><a class="header" href="#number">number</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>down</td><td>j</td><td>to down</td></tr>
<tr><td>enter</td><td></td><td>to index</td></tr>
<tr><td>k</td><td>up</td><td>to up</td></tr>
<tr><td>[0-9]</td><td></td><td>input</td></tr>
</tbody></table>
<h3 id="action-1"><a class="header" href="#action-1">action</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>!</td><td></td><td>shell</td></tr>
<tr><td>c</td><td></td><td>create</td></tr>
<tr><td>e</td><td></td><td>open in editor</td></tr>
<tr><td>l</td><td></td><td>logs</td></tr>
<tr><td>m</td><td></td><td>toggle mouse</td></tr>
<tr><td>p</td><td></td><td>edit permissions</td></tr>
<tr><td>q</td><td></td><td>quit options</td></tr>
<tr><td>s</td><td></td><td>selection operations</td></tr>
<tr><td>v</td><td></td><td>vroot</td></tr>
<tr><td>[0-9]</td><td></td><td>go to index</td></tr>
</tbody></table>
<h3 id="filter"><a class="header" href="#filter">filter</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>R</td><td></td><td>relative path does not match regex</td></tr>
<tr><td>backspace</td><td></td><td>remove last filter</td></tr>
<tr><td>ctrl-r</td><td></td><td>reset filters</td></tr>
<tr><td>ctrl-u</td><td></td><td>clear filters</td></tr>
<tr><td>r</td><td></td><td>relative path does match regex</td></tr>
</tbody></table>
<h3 id="rename"><a class="header" href="#rename">rename</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>enter</td><td></td><td>submit</td></tr>
<tr><td>tab</td><td></td><td>try complete</td></tr>
</tbody></table>
<h3 id="relative_path_does_not_match_regex"><a class="header" href="#relative_path_does_not_match_regex">relative_path_does_not_match_regex</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>enter</td><td></td><td>submit</td></tr>
</tbody></table>
<h3 id="quit"><a class="header" href="#quit">quit</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>enter</td><td></td><td>just quit</td></tr>
<tr><td>f</td><td></td><td>quit printing focus</td></tr>
<tr><td>p</td><td></td><td>quit printing pwd</td></tr>
<tr><td>r</td><td></td><td>quit printing result</td></tr>
<tr><td>s</td><td></td><td>quit printing selection</td></tr>
</tbody></table>
<h3 id="recover"><a class="header" href="#recover">recover</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
</tbody></table>
<h3 id="delete"><a class="header" href="#delete">delete</a></h3>
<table><thead><tr><th>key</th><th>remaps</th><th>action</th></tr></thead><tbody>
<tr><td>D</td><td></td><td>force delete</td></tr>
<tr><td>d</td><td></td><td>delete</td></tr>
</tbody></table>
<div style="break-before: page; page-break-before: always;"></div><h1 id="debug-key-bindings"><a class="header" href="#debug-key-bindings">Debug Key Bindings</a></h1>
<p>If you need help debugging or understanding key bindings DYI way, you can
create a <code>test.lua</code> file with the following script, launch xplr with
<code>xplr --extra-config test.lua</code>, press <code>#</code> and play around.</p>
<pre><code class="language-lua">-- The global key bindings inherited by all the modes.
xplr.config.general.global_key_bindings = {
on_key = {
esc = {
help = &quot;escape&quot;,
messages = {
{ LogInfo = &quot;global on_key(esc) called&quot; },
&quot;PopMode&quot;,
},
},
[&quot;ctrl-c&quot;] = {
help = &quot;terminate&quot;,
messages = {
&quot;Terminate&quot;,
},
},
},
}
-- Press `#` to enter the `debug key bindings` mode.
xplr.config.modes.builtin.default.key_bindings.on_key[&quot;#&quot;] = {
help = &quot;test&quot;,
messages = {
&quot;PopMode&quot;,
{ SwitchModeCustom = &quot;debug_key_bindings&quot; },
},
}
-- The `debug key bindings` mode.
xplr.config.modes.custom.debug_key_bindings = {
name = &quot;debug key bindings&quot;,
key_bindings = {
on_key = {
[&quot;1&quot;] = {
messages = {
{ LogInfo = &quot;on_key(1) called&quot; },
},
},
a = {
messages = {
{ LogInfo = &quot;on_key(a) called&quot; },
},
},
[&quot;`&quot;] = {
messages = {
{ LogInfo = &quot;on_key(`) called&quot; },
},
},
tab = {
messages = {
{ LogInfo = &quot;on_key(tab) called&quot; },
},
},
f1 = {
messages = {
{ LogInfo = &quot;on_key(f1) called&quot; },
},
},
},
on_alphabet = {
messages = {
{ LogInfo = &quot;on_alphabet called&quot; },
},
},
on_number = {
messages = {
{ LogInfo = &quot;on_number called&quot; },
},
},
-- on_alphanumeric = {
-- messages = {
-- { LogInfo = &quot;on_alphanumeric called&quot; },
-- },
-- },
on_special_character = {
messages = {
{ LogInfo = &quot;on_special_character called&quot; },
},
},
-- on_character = {
-- messages = {
-- { LogInfo = &quot;on_character called&quot; },
-- },
-- },
on_navigation = {
messages = {
{ LogInfo = &quot;on_navigation called&quot; },
},
},
on_function = {
messages = {
{ LogInfo = &quot;on_function called&quot; },
},
},
default = {
messages = {
{ LogInfo = &quot;default called&quot; },
},
},
},
}
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="node-type"><a class="header" href="#node-type">Node Type</a></h1>
<p>A node-type contains the following fields:</p>
<ul>
<li><a href="node-type.html#meta">meta</a></li>
<li><a href="style.html">style</a></li>
</ul>
<h3 id="meta"><a class="header" href="#meta">meta</a></h3>
<p>Type: mapping of string and string</p>
<p>A meta field can contain custom metadata about a node. By default, the &quot;icon&quot;
metadata is set for the <a href="node_types.html#directory">directory</a>, <a href="node_types.html#file">file</a>, and
<a href="node_types.html#symlink">symlink</a> nodes.</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.config.node_types.file = {
meta = {
icon = &quot;f&quot;,
foo = &quot;bar&quot;,
}
}
</code></pre>
<h2 id="also-see"><a class="header" href="#also-see">Also See:</a></h2>
<ul>
<li><a href="node_types.html">xplr.config.node_types</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="layout"><a class="header" href="#layout">Layout</a></h1>
<h4 id="example-defining-custom-layout-1"><a class="header" href="#example-defining-custom-layout-1">Example: Defining Custom Layout</a></h4>
<p><a href="https://gifyu.com/image/1X38"><img src="https://s6.gifyu.com/images/layout.png" alt="layout.png" /></a></p>
<pre><code class="language-lua">xplr.config.layouts.builtin.default = {
Horizontal = {
config = {
margin = 1,
horizontal_margin = 2,
vertical_margin = 3,
constraints = {
{ Percentage = 50 },
{ Percentage = 50 },
}
},
splits = {
&quot;Table&quot;,
&quot;HelpMenu&quot;,
}
}
}
</code></pre>
<p>A layout is a <a href="sum-type.html">sum type</a> can be one of the following:</p>
<ul>
<li><a href="layout.html#nothing">Nothing</a></li>
<li><a href="layout.html#table">Table</a></li>
<li><a href="layout.html#inputandlogs">InputAndLogs</a></li>
<li><a href="layout.html#selection">Selection</a></li>
<li><a href="layout.html#helpmenu">HelpMenu</a></li>
<li><a href="layout.html#sortandfilter">SortAndFilter</a></li>
<li><a href="layout.html#static">Static</a></li>
<li><a href="layout.html#dynamic">Dynamic</a></li>
<li><a href="layout.html#horizontal">Horizontal</a></li>
<li><a href="layout.html#vertical">Vertical</a></li>
<li>CustomContent (deprecated, use <code>Static</code> or <code>Dynamic</code>)</li>
</ul>
<h3 id="nothing"><a class="header" href="#nothing">Nothing</a></h3>
<p>This layout contains a blank panel.</p>
<p>Type: &quot;Nothing&quot;</p>
<h3 id="table"><a class="header" href="#table">Table</a></h3>
<p>This layout contains the table displaying the files and directories in the current
directory.</p>
<h3 id="inputandlogs"><a class="header" href="#inputandlogs">InputAndLogs</a></h3>
<p>This layout contains the panel displaying the input prompt and logs.</p>
<p>Type: &quot;InputAndLogs&quot;</p>
<h3 id="selection"><a class="header" href="#selection">Selection</a></h3>
<p>This layout contains the panel displaying the selected paths.</p>
<p>Type: &quot;Selection&quot;</p>
<h3 id="helpmenu"><a class="header" href="#helpmenu">HelpMenu</a></h3>
<p>This layout contains the panel displaying the help menu for the current mode in
real-time.</p>
<p>Type: &quot;HelpMenu&quot;</p>
<h3 id="sortandfilter"><a class="header" href="#sortandfilter">SortAndFilter</a></h3>
<p>This layout contains the panel displaying the pipeline of sorters and filters applied on
the list of paths being displayed.</p>
<p>Type: &quot;SortAndFilter&quot;</p>
<h3 id="static"><a class="header" href="#static">Static</a></h3>
<p>This is a custom layout to render static content.</p>
<p>Type: { Static = <a href="layout.html#custom-panel">Custom Panel</a> }</p>
<h3 id="dynamic"><a class="header" href="#dynamic">Dynamic</a></h3>
<p>This is a custom layout to render dynamic content using a function defined in
<a href="configuration.html#function">xplr.fn</a> that takes <a href="layout.html#content-renderer-argument">Content Renderer Argument</a> and returns <a href="layout.html#custom-panel">Custom Panel</a>.</p>
<p>Type: { Dynamic = <a href="layout.html#content-renderer">Content Renderer</a> }</p>
<h3 id="horizontal"><a class="header" href="#horizontal">Horizontal</a></h3>
<p>This is a special layout that splits the panel into two horizontal parts.</p>
<p>It contains the following information:</p>
<ul>
<li><a href="layout.html#layout-config">config</a></li>
<li><a href="layout.html#splits">splits</a></li>
</ul>
<p>Type: { Horizontal = { config = <a href="layout.html#layout-config">config</a>, splits = <a href="layout.html#splits">splits</a> }</p>
<h3 id="vertical"><a class="header" href="#vertical">Vertical</a></h3>
<p>This is a special layout that splits the panel into two vertical parts.</p>
<p>It contains the following information:</p>
<ul>
<li><a href="layout.html#layout-config">config</a></li>
<li><a href="layout.html#splits">splits</a></li>
</ul>
<p>Type: { Vertical = { config = <a href="layout.html#layout-config">config</a>, splits = <a href="layout.html#splits">splits</a> }</p>
<h2 id="layout-config"><a class="header" href="#layout-config">Layout Config</a></h2>
<p>A layout config contains the following information:</p>
<ul>
<li><a href="layout.html#margin">margin</a></li>
<li><a href="layout.html#horizontal_margin">horizontal_margin</a></li>
<li><a href="layout.html#vertical_margin">vertical_margin</a></li>
<li><a href="layout.html#constraints">constraints</a></li>
</ul>
<h3 id="margin"><a class="header" href="#margin">margin</a></h3>
<p>Type: nullable integer</p>
<p>The width of the margin in all direction.</p>
<h3 id="horizontal_margin"><a class="header" href="#horizontal_margin">horizontal_Margin</a></h3>
<p>Type: nullable integer</p>
<p>The width of the horizontal margins. Overwrites the <a href="layout.html#margin">margin</a> value.</p>
<h3 id="vertical_margin"><a class="header" href="#vertical_margin">vertical_Margin</a></h3>
<p>Type: nullable integer</p>
<p>The width of the vertical margins. Overwrites the <a href="layout.html#margin">margin</a> value.</p>
<h3 id="constraints"><a class="header" href="#constraints">constraints</a></h3>
<p>Type: nullable list of <a href="layout.html#constraint">Constraint</a></p>
<p>The constraints applied on the layout.</p>
<h2 id="constraint"><a class="header" href="#constraint">Constraint</a></h2>
<p>A constraint is a <a href="sum-type.html">sum type</a> can be one of the following:</p>
<ul>
<li>{ Percentage = int }</li>
<li>{ Ratio = { int, int } }</li>
<li>{ Length = { int }</li>
<li>{ LengthLessThanScreenHeight = int }</li>
<li>{ LengthLessThanScreenWidth = int }</li>
<li>{ LengthLessThanLayoutHeight = int }</li>
<li>{ LengthLessThanLayoutWidth = int }</li>
<li>{ Max = int }</li>
<li>{ MaxLessThanScreenHeight = int }</li>
<li>{ MaxLessThanScreenWidth = int }</li>
<li>{ MaxLessThanLayoutHeight = int }</li>
<li>{ MaxLessThanLayoutWidth = int }</li>
<li>{ Min = int }</li>
<li>{ MinLessThanScreenHeight = int }</li>
<li>{ MinLessThanScreenWidth = int }</li>
<li>{ MinLessThanLayoutHeight = int }</li>
<li>{ MinLessThanLayoutWidth = int }</li>
</ul>
<h2 id="splits"><a class="header" href="#splits">splits</a></h2>
<p>Type: list of <a href="layout.html#layout">Layout</a></p>
<p>The list of child layouts to fit into the parent layout.</p>
<h2 id="custom-panel"><a class="header" href="#custom-panel">Custom Panel</a></h2>
<p>Custom panel is a <a href="sum-type.html">sum type</a> can be one of the following:</p>
<ul>
<li><a href="layout.html#customparagraph">CustomParagraph</a></li>
<li><a href="layout.html#customlist">CustomList</a></li>
<li><a href="layout.html#customtable">CustomTable</a></li>
<li><a href="layout.html#customlayout">CustomLayout</a></li>
</ul>
<h3 id="customparagraph"><a class="header" href="#customparagraph">CustomParagraph</a></h3>
<p>A paragraph to render. It contains the following fields:</p>
<ul>
<li><strong>ui</strong> (nullable <a href="layout.html#panel-ui-config">Panel UI Config</a>): Optional UI config for the panel.</li>
<li><strong>body</strong> (string): The string to render.</li>
</ul>
<h4 id="example-render-a-custom-static-paragraph"><a class="header" href="#example-render-a-custom-static-paragraph">Example: Render a custom static paragraph</a></h4>
<pre><code class="language-lua">xplr.config.layouts.builtin.default = {
Static = {
CustomParagraph = {
ui = { title = { format = &quot; custom title &quot; } },
body = &quot;custom body&quot;,
},
},
}
</code></pre>
<h4 id="example-render-a-custom-dynamic-paragraph"><a class="header" href="#example-render-a-custom-dynamic-paragraph">Example: Render a custom dynamic paragraph</a></h4>
<pre><code class="language-lua">xplr.config.layouts.builtin.default = { Dynamic = &quot;custom.render_layout&quot; }
xplr.fn.custom.render_layout = function(ctx)
return {
CustomParagraph = {
ui = { title = { format = ctx.app.pwd } },
body = xplr.util.to_yaml(ctx.app.focused_node),
},
}
end
</code></pre>
<h3 id="customlist"><a class="header" href="#customlist">CustomList</a></h3>
<p>A list to render. It contains the following fields:</p>
<ul>
<li><strong>ui</strong> (nullable <a href="layout.html#panel-ui-config">Panel UI Config</a>): Optional UI config for the panel.</li>
<li><strong>body</strong> (list of string): The list of strings to display.</li>
</ul>
<h4 id="example-render-a-custom-static-list"><a class="header" href="#example-render-a-custom-static-list">Example: Render a custom static list</a></h4>
<pre><code class="language-lua">xplr.config.layouts.builtin.default = {
Static = {
CustomList = {
ui = { title = { format = &quot; custom title &quot; } },
body = { &quot;1&quot;, &quot;2&quot;, &quot;3&quot; },
},
},
}
</code></pre>
<h4 id="example-render-a-custom-dynamic-list"><a class="header" href="#example-render-a-custom-dynamic-list">Example: Render a custom dynamic list</a></h4>
<pre><code class="language-lua">xplr.config.layouts.builtin.default = { Dynamic = &quot;custom.render_layout&quot; }
xplr.fn.custom.render_layout = function(ctx)
return {
CustomList = {
ui = { title = { format = ctx.app.pwd } },
body = {
(ctx.app.focused_node or {}).relative_path or &quot;&quot;,
ctx.app.version,
tostring(ctx.app.pid),
},
},
}
end
</code></pre>
<h2 id="customtable"><a class="header" href="#customtable">CustomTable</a></h2>
<p>A custom table to render. It contains the following fields:</p>
<ul>
<li><strong>ui</strong> (nullable <a href="layout.html#panel-ui-config">Panel UI Config</a>): Optional UI config for the panel.</li>
<li><strong>widths</strong> (list of <a href="layout.html#constraint">Constraint</a>): Width of the columns.</li>
<li><strong>col_spacing</strong> (nullable int): Spacing between columns. Defaults to 1.</li>
<li><strong>body</strong> (list of list of string): The rows and columns to render.</li>
</ul>
<h4 id="example-render-a-custom-static-table"><a class="header" href="#example-render-a-custom-static-table">Example: Render a custom static table</a></h4>
<pre><code class="language-lua">xplr.config.layouts.builtin.default = {
Static = {
CustomTable = {
ui = { title = { format = &quot; custom title &quot; } },
widths = {
{ Percentage = 50 },
{ Percentage = 50 },
},
body = {
{ &quot;a&quot;, &quot;b&quot; },
{ &quot;c&quot;, &quot;d&quot; },
},
},
},
}
</code></pre>
<h4 id="example-render-a-custom-dynamic-table"><a class="header" href="#example-render-a-custom-dynamic-table">Example: Render a custom dynamic table</a></h4>
<pre><code class="language-lua">xplr.config.layouts.builtin.default = {Dynamic = &quot;custom.render_layout&quot; }
xplr.fn.custom.render_layout = function(ctx)
return {
CustomTable = {
ui = { title = { format = ctx.app.pwd } },
widths = {
{ Percentage = 50 },
{ Percentage = 50 },
},
body = {
{ &quot;&quot;, &quot;&quot; },
{ &quot;Layout height&quot;, tostring(ctx.layout_size.height) },
{ &quot;Layout width&quot;, tostring(ctx.layout_size.width) },
{ &quot;&quot;, &quot;&quot; },
{ &quot;Screen height&quot;, tostring(ctx.screen_size.height) },
{ &quot;Screen width&quot;, tostring(ctx.screen_size.width) },
},
},
}
end
</code></pre>
<h3 id="customlayout"><a class="header" href="#customlayout">CustomLayout</a></h3>
<p>A whole custom layout to render. It doesn't make sense to use it as a
<a href="layout.html#static">Static</a> layout, but can be very useful to render as a <a href="layout.html#dynamic">Dynamic</a> layout
for use cases where the structure of the layout needs to change without having
to switch modes.</p>
<blockquote>
<p>WARNING: Rendering the same dynamic custom layout recursively will result in
a ugly crash.</p>
</blockquote>
<h4 id="example-render-a-custom-dynamic-layout"><a class="header" href="#example-render-a-custom-dynamic-layout">Example: Render a custom dynamic layout</a></h4>
<pre><code class="language-lua">xplr.config.layouts.builtin.default = { Dynamic = &quot;custom.render_layout&quot; }
xplr.fn.custom.render_layout = function(ctx)
local inner = {
config = {
constraints = {
{ Percentage = 50 },
{ Percentage = 50 },
},
},
splits = {
{ Static = { CustomParagraph = { body = &quot;Try your luck...&quot; } } },
{ Static = { CustomParagraph = { body = &quot;Press ctrl-r&quot; } } },
},
}
local layout_type = &quot;Vertical&quot;
if math.random(1, 2) == 1 then
layout_type = &quot;Horizontal&quot;
end
return { CustomLayout = { [layout_type] = inner } }
end
</code></pre>
<h2 id="panel-ui-config"><a class="header" href="#panel-ui-config">Panel UI Config</a></h2>
<p>It contains the following optional fields:</p>
<ul>
<li><strong>title</strong> ({ format = &quot;string&quot;, style = <a href="style.html#style">Style</a> }): the title of the panel.</li>
<li><strong>style</strong> (<a href="style.html#style">Style</a>): The style of the panel body.</li>
<li><strong>borders</strong> (nullable list of <a href="borders.html#border">Border</a>): The shape of the borders.</li>
<li><strong>border_type</strong> (<a href="borders.html#border-type">Border Type</a>): The type of the borders.</li>
<li><strong>border_style</strong> (<a href="style.html#style">Style</a>): The style of the borders.</li>
</ul>
<h2 id="content-renderer"><a class="header" href="#content-renderer">Content Renderer</a></h2>
<p>It is a Lua function that receives <a href="layout.html#content-renderer-argument">a special argument</a> as input and
returns some output that can be rendered in the UI. It is used to render
content body for the custom dynamic layouts.</p>
<h2 id="content-renderer-argument"><a class="header" href="#content-renderer-argument">Content Renderer Argument</a></h2>
<p>It contains the following information:</p>
<ul>
<li><a href="layout.html#size">layout_size</a></li>
<li><a href="layout.html#size">screen_size</a></li>
<li><a href="layout.html#app">app</a></li>
</ul>
<h3 id="size"><a class="header" href="#size">Size</a></h3>
<p>It contains the following information:</p>
<ul>
<li>x</li>
<li>y</li>
<li>height</li>
<li>width</li>
</ul>
<p>Every field is of integer type.</p>
<h3 id="app"><a class="header" href="#app">app</a></h3>
<p>This is a lightweight version of the <a href="lua-function-calls.html#lua-context">Lua Context</a>. In this context, the
heavyweight fields like <a href="lua-function-calls.html#directory_buffer">directory_buffer</a> are omitted for performance
reasons.</p>
<p>Hence, only the following fields are available.</p>
<ul>
<li><a href="lua-function-calls.html#version">version</a></li>
<li><a href="lua-function-calls.html#pwd">pwd</a></li>
<li><a href="lua-function-calls.html#initial_pwd">initial_pwd</a></li>
<li><a href="lua-function-calls.html#vroot">vroot</a></li>
<li><a href="lua-function-calls.html#focused_node">focused_node</a></li>
<li><a href="lua-function-calls.html#selection">selection</a></li>
<li><a href="lua-function-calls.html#mode">mode</a></li>
<li><a href="lua-function-calls.html#layout">layout</a></li>
<li><a href="lua-function-calls.html#input_buffer">input_buffer</a></li>
<li><a href="lua-function-calls.html#pid">pid</a></li>
<li><a href="lua-function-calls.html#session_path">session_path</a></li>
<li><a href="lua-function-calls.html#explorer_config">explorer_config</a></li>
</ul>
<h2 id="also-see-1"><a class="header" href="#also-see-1">Also See:</a></h2>
<ul>
<li><a href="layouts.html">xplr.config.layouts</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="mode"><a class="header" href="#mode">Mode</a></h1>
<p>A mode contains the following information:</p>
<ul>
<li><a href="mode.html#name">name</a></li>
<li><a href="mode.html#help">help</a></li>
<li><a href="mode.html#extra_help">extra_help</a></li>
<li><a href="mode.html#key_bindings">key_bindings</a></li>
<li><a href="mode.html#layout">layout</a></li>
<li><a href="mode.html#prompt">prompt</a></li>
</ul>
<h3 id="name"><a class="header" href="#name">name</a></h3>
<p>Type: string</p>
<p>This is the name of the mode visible in the help menu.</p>
<h3 id="help-1"><a class="header" href="#help-1">help</a></h3>
<p>Type: nullable string</p>
<p>If specified, the help menu will display this instead of the auto generated
mappings.</p>
<h3 id="extra_help"><a class="header" href="#extra_help">extra_help</a></h3>
<p>Type: nullable string</p>
<p>If specified, the help menu will display this along-side the auto generated
help menu.</p>
<h3 id="key_bindings"><a class="header" href="#key_bindings">key_bindings</a></h3>
<p>Type: <a href="configure-key-bindings.html#key-bindings">Key Bindings</a></p>
<p>The key bindings available in that mode.</p>
<h3 id="layout-1"><a class="header" href="#layout-1">layout</a></h3>
<p>Type: nullable <a href="layout.html#layout">Layout</a></p>
<p>If specified, this layout will be used to render the UI.</p>
<h3 id="prompt"><a class="header" href="#prompt">prompt</a></h3>
<p>Type: nullable string</p>
<p>If set, this prompt will be displayed in the input buffer when in this mode.</p>
<h2 id="also-see-2"><a class="header" href="#also-see-2">Also See:</a></h2>
<ul>
<li><a href="modes.html">xplr.config.modes</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="message"><a class="header" href="#message">Message</a></h1>
<p>You can think of xplr as a server. Just like web servers listen to HTTP
requests, xplr listens to messages.</p>
<p>A message is a <a href="sum-type.html">sum type</a> that can have <a href="messages.html">these possible values</a>.</p>
<p>You can send these messages to an xplr session in the following ways:</p>
<ul>
<li>Via command-line (currently during start-up only, using <code>--on-load</code>)</li>
<li>Via <a href="key-bindings.html">key bindings</a></li>
<li>Via <a href="lua-function-calls.html">Lua function calls</a></li>
<li>Via shell command using the <a href="environment-variables-and-pipes.html#input-pipe">input pipe</a></li>
<li>Via socket (coming soon)</li>
</ul>
<h3 id="format"><a class="header" href="#format">Format</a></h3>
<p>To send messages using the <a href="key-bindings.html">key bindings</a> or <a href="lua-function-calls.html">Lua function calls</a>,
messages are represented in <a href="https://www.lua.org/">Lua</a> syntax.</p>
<p>For example:</p>
<ul>
<li><code>&quot;Quit&quot;</code></li>
<li><code>{ FocusPath = &quot;/path/to/file&quot; }</code></li>
<li><code>{ Call = { command = &quot;bash&quot;, args = { &quot;-c&quot;, &quot;read -p test&quot; } } }</code></li>
</ul>
<p>However, to send messages using the <a href="environment-variables-and-pipes.html#input-pipe">input pipe</a>, they need to be
represented using <a href="http://yaml.org/">YAML</a> (or <a href="https://www.json.org">JSON</a>) syntax.</p>
<p>For example:</p>
<ul>
<li><code>Quit</code></li>
<li><code>FocusPath: &quot;/path/to/file&quot;</code></li>
<li><code>Call: { command: bash, args: [&quot;-c&quot;, &quot;read -p test&quot;] }</code></li>
</ul>
<p>Use <code>&quot;$XPLR&quot; -m TEMPLATE [VALUE]...</code> command-line option to safely format
<code>TEMPLATE</code> into a valid message. If uses <a href="https://github.com/sayanarijit/jf">jf</a> to parse and render the
template. And <code>$XPLR</code> (rather than <code>xplr</code>) makes sure that the correct version
of the binary is being used.</p>
<p>For example:</p>
<ul>
<li><code>&quot;$XPLR&quot; -m Quit</code></li>
<li><code>&quot;$XPLR&quot; -m 'FocusPath: %q' &quot;/path/to/file&quot;</code></li>
<li><code>&quot;$XPLR&quot; -m 'Call: { command: %q, args: [%*q] }' bash -c &quot;read -p test&quot;</code></li>
</ul>
<h2 id="also-see-3"><a class="header" href="#also-see-3">Also See:</a></h2>
<ul>
<li><a href="messages.html">Full List of Messages</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="full-list-of-messages"><a class="header" href="#full-list-of-messages">Full List of Messages</a></h1>
<p>xplr <a href="message.html">messages</a> categorized based on their purpose.</p>
<h2 id="categories"><a class="header" href="#categories">Categories</a></h2>
<ul>
<li><a href="messages.html#exploring">Exploring</a></li>
<li><a href="messages.html#screen">Screen</a></li>
<li><a href="messages.html#navigation">Navigation</a></li>
<li><a href="messages.html#virtual-root">Virtual Root</a></li>
<li><a href="messages.html#reading-input">Reading Input</a></li>
<li><a href="messages.html#switching-mode">Switching Mode</a></li>
<li><a href="messages.html#switching-layout">Switching Layout</a></li>
<li><a href="messages.html#executing-commands">Executing Commands</a></li>
<li><a href="messages.html#calling-lua-functions">Calling Lua Functions</a></li>
<li><a href="messages.html#select-operations">Select Operations</a></li>
<li><a href="messages.html#filter-operations">Filter Operations</a></li>
<li><a href="messages.html#sort-operations">Sort Operations</a></li>
<li><a href="messages.html#search-operations">Search Operations</a></li>
<li><a href="messages.html#mouse-operations">Mouse Operations</a></li>
<li><a href="messages.html#fifo-operations">Fifo Operations</a></li>
<li><a href="messages.html#logging">Logging</a></li>
<li><a href="messages.html#debugging">Debugging</a></li>
<li><a href="messages.html#quit-options">Quit Options</a></li>
</ul>
<h3 id="exploring"><a class="header" href="#exploring">Exploring</a></h3>
<h4 id="explorepwd"><a class="header" href="#explorepwd">ExplorePwd</a></h4>
<p>Explore the present working directory and register the filtered nodes.
This operation is expensive. So, try to avoid using it too often.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ExplorePwd&quot;</code></li>
<li>YAML: <code>ExplorePwd</code></li>
</ul>
<h4 id="explorepwdasync"><a class="header" href="#explorepwdasync">ExplorePwdAsync</a></h4>
<p>Explore the present working directory and register the filtered nodes
asynchronously. This operation happens asynchronously. That means, the
xplr directory buffers won't be updated immediately. Hence, it needs to
be used with care and probably with special checks in place. To explore
$PWD synchronously, use <code>ExplorePwd</code> instead.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ExplorePwdAsync&quot;</code></li>
<li>YAML: <code>ExplorePwdAsync</code></li>
</ul>
<h4 id="exploreparentsasync"><a class="header" href="#exploreparentsasync">ExploreParentsAsync</a></h4>
<p>Explore the present working directory along with its parents and
register the filtered nodes. This operation happens asynchronously.
That means, the xplr directory buffers won't be updated immediately.
Hence, it needs to be used with care and probably with special checks
in place. To explore just the <code>$PWD</code> synchronously, use <code>ExplorePwd</code>
instead.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ExploreParentsAsync&quot;</code></li>
<li>YAML: <code>ExploreParentsAsync</code></li>
</ul>
<h3 id="screen"><a class="header" href="#screen">Screen</a></h3>
<h4 id="clearscreen"><a class="header" href="#clearscreen">ClearScreen</a></h4>
<p>Clear the screen.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ClearScreen&quot;</code></li>
<li>YAML: <code>ClearScreen</code></li>
</ul>
<h4 id="refresh"><a class="header" href="#refresh">Refresh</a></h4>
<p>Refresh the screen.
But it will not re-explore the directory if the working directory is
the same. If there is some change in the working directory and you want
to re-explore it, use the <code>Explore</code> message instead.
Also, it will not clear the screen. Use <code>ClearScreen</code> for that.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;Refresh&quot;</code></li>
<li>YAML: <code>Refresh</code></li>
</ul>
<h3 id="navigation"><a class="header" href="#navigation">Navigation</a></h3>
<h4 id="focusnext"><a class="header" href="#focusnext">FocusNext</a></h4>
<p>Focus next node.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusNext&quot;</code></li>
<li>YAML: <code>FocusNext</code></li>
</ul>
<h4 id="focusnextselection"><a class="header" href="#focusnextselection">FocusNextSelection</a></h4>
<p>Focus on the next selected node.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusNextSelection&quot;</code></li>
<li>YAML: <code>FocusNextSelection</code></li>
</ul>
<h4 id="focusnextbyrelativeindex"><a class="header" href="#focusnextbyrelativeindex">FocusNextByRelativeIndex</a></h4>
<p>Focus on the <code>n</code>th node relative to the current focus where <code>n</code> is a
given value.</p>
<p>Type: { FocusNextByRelativeIndex = int }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ FocusNextByRelativeIndex = 2 }</code></li>
<li>YAML: <code>FocusNextByRelativeIndex: 2</code></li>
</ul>
<h4 id="focusnextbyrelativeindexfrominput"><a class="header" href="#focusnextbyrelativeindexfrominput">FocusNextByRelativeIndexFromInput</a></h4>
<p>Focus on the <code>n</code>th node relative to the current focus where <code>n</code> is read
from the input buffer.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusNextByRelativeIndexFromInput&quot;</code></li>
<li>YAML: <code>FocusNextByRelativeIndexFromInput</code></li>
</ul>
<h4 id="focusprevious"><a class="header" href="#focusprevious">FocusPrevious</a></h4>
<p>Focus on the previous item.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusPrevious&quot;</code></li>
<li>YAML: <code>FocusPrevious</code></li>
</ul>
<h4 id="focuspreviousselection"><a class="header" href="#focuspreviousselection">FocusPreviousSelection</a></h4>
<p>Focus on the previous selection item.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusPreviousSelection&quot;</code></li>
<li>YAML: <code>FocusPreviousSelection</code></li>
</ul>
<h4 id="focuspreviousbyrelativeindex"><a class="header" href="#focuspreviousbyrelativeindex">FocusPreviousByRelativeIndex</a></h4>
<p>Focus on the <code>-n</code>th node relative to the current focus where <code>n</code> is a
given value.</p>
<p>Type: { FocusPreviousByRelativeIndex = int }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ FocusPreviousByRelativeIndex = 2 }</code></li>
<li>YAML: <code>FocusPreviousByRelativeIndex: 2</code></li>
</ul>
<h4 id="focuspreviousbyrelativeindexfrominput"><a class="header" href="#focuspreviousbyrelativeindexfrominput">FocusPreviousByRelativeIndexFromInput</a></h4>
<p>Focus on the <code>-n</code>th node relative to the current focus where <code>n</code> is
read from the input buffer.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusPreviousByRelativeIndexFromInput&quot;</code></li>
<li>YAML: <code>FocusPreviousByRelativeIndexFromInput</code></li>
</ul>
<h4 id="focusfirst"><a class="header" href="#focusfirst">FocusFirst</a></h4>
<p>Focus on the first node.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusFirst&quot;</code></li>
<li>YAML: <code>FocusFirst</code></li>
</ul>
<h4 id="focuslast"><a class="header" href="#focuslast">FocusLast</a></h4>
<p>Focus on the last node.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusLast&quot;</code></li>
<li>YAML: <code>FocusLast</code></li>
</ul>
<h4 id="focuspath"><a class="header" href="#focuspath">FocusPath</a></h4>
<p>Focus on the given path.</p>
<p>Type: { FocusPath = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ FocusPath = &quot;/path/to/file&quot; }</code></li>
<li>YAML: <code>FocusPath: /path/to/file</code></li>
</ul>
<h4 id="focuspathfrominput"><a class="header" href="#focuspathfrominput">FocusPathFromInput</a></h4>
<p>Focus on the path read from input buffer.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusPathFromInput&quot;</code></li>
<li>YAML: <code>FocusPathFromInput</code></li>
</ul>
<h4 id="focusbyindex"><a class="header" href="#focusbyindex">FocusByIndex</a></h4>
<p>Focus on the absolute <code>n</code>th node where <code>n</code> is a given value.</p>
<p>Type: { FocusByIndex = int }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ FocusByIndex = 2 }</code></li>
<li>YAML: <code>FocusByIndex: 2</code></li>
</ul>
<h4 id="focusbyindexfrominput"><a class="header" href="#focusbyindexfrominput">FocusByIndexFromInput</a></h4>
<p>Focus on the absolute <code>n</code>th node where <code>n</code> is read from the input buffer.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FocusByIndexFromInput&quot;</code></li>
<li>YAML: <code>FocusByIndexFromInput</code></li>
</ul>
<h4 id="focusbyfilename"><a class="header" href="#focusbyfilename">FocusByFileName</a></h4>
<p>Focus on the file by name from the present working directory.</p>
<p>Type: { FocusByFileName = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ FocusByFileName = &quot;filename.ext&quot; }</code></li>
<li>YAML: <code>FocusByFileName: filename.ext</code></li>
</ul>
<h4 id="scrollup"><a class="header" href="#scrollup">ScrollUp</a></h4>
<p>Scroll up by terminal height.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ScrollUp&quot;</code></li>
<li>YAML: <code>ScrollUp</code></li>
</ul>
<h4 id="scrolldown"><a class="header" href="#scrolldown">ScrollDown</a></h4>
<p>Scroll down by terminal height.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ScrollDown&quot;</code></li>
<li>YAML: <code>ScrollDown</code></li>
</ul>
<h4 id="scrolluphalf"><a class="header" href="#scrolluphalf">ScrollUpHalf</a></h4>
<p>Scroll up by half of terminal height.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ScrollUpHalf&quot;</code></li>
<li>YAML: <code>ScrollUpHalf</code></li>
</ul>
<h4 id="scrolldownhalf"><a class="header" href="#scrolldownhalf">ScrollDownHalf</a></h4>
<p>Scroll down by half of terminal height.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ScrollDownHalf&quot;</code></li>
<li>YAML: <code>ScrollDownHalf</code></li>
</ul>
<h4 id="changedirectory"><a class="header" href="#changedirectory">ChangeDirectory</a></h4>
<p>Change the present working directory ($PWD)</p>
<p>Type: { ChangeDirectory = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ ChangeDirectory = &quot;/path/to/directory&quot; }</code></li>
<li>YAML: <code>ChangeDirectory: /path/to/directory</code></li>
</ul>
<h4 id="enter"><a class="header" href="#enter">Enter</a></h4>
<p>Enter into the currently focused path if it's a directory.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;Enter&quot;</code></li>
<li>YAML: <code>Enter</code></li>
</ul>
<h4 id="back"><a class="header" href="#back">Back</a></h4>
<p>Go back to the parent directory.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;Back&quot;</code></li>
<li>YAML: <code>Back</code></li>
</ul>
<h4 id="lastvisitedpath"><a class="header" href="#lastvisitedpath">LastVisitedPath</a></h4>
<p>Go to the last path visited.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;LastVisitedPath&quot;</code></li>
<li>YAML: <code>LastVisitedPath</code></li>
</ul>
<h4 id="nextvisitedpath"><a class="header" href="#nextvisitedpath">NextVisitedPath</a></h4>
<p>Go to the next path visited.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;NextVisitedPath&quot;</code></li>
<li>YAML: <code>NextVisitedPath</code></li>
</ul>
<h4 id="followsymlink"><a class="header" href="#followsymlink">FollowSymlink</a></h4>
<p>Follow the symlink under focus to its actual location.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;FollowSymlink&quot;</code></li>
<li>YAML: <code>FollowSymlink</code></li>
</ul>
<h3 id="virtual-root"><a class="header" href="#virtual-root">Virtual Root</a></h3>
<h4 id="setvroot"><a class="header" href="#setvroot">SetVroot</a></h4>
<p>Sets the virtual root for isolating xplr navigation, similar to
<code>--vroot</code>, but temporary (can be reset back to initial value).
If the $PWD is outside the vroot, xplr will automatically enter vroot.</p>
<p>Type: { SetVroot = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SetVroot = &quot;/tmp&quot; }</code></li>
<li>YAML: <code>SetVroot: /tmp</code></li>
</ul>
<h4 id="unsetvroot"><a class="header" href="#unsetvroot">UnsetVroot</a></h4>
<p>Unset the virtual root temporarily (can be reset back to the initial
value).</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;UnsetVroot&quot;</code></li>
<li>YAML: <code>UnsetVroot</code></li>
</ul>
<h4 id="togglevroot"><a class="header" href="#togglevroot">ToggleVroot</a></h4>
<p>Toggle virtual root between unset, initial value and $PWD.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ToggleVroot&quot;</code></li>
<li>YAML: <code>ToggleVroot</code></li>
</ul>
<h4 id="resetvroot"><a class="header" href="#resetvroot">ResetVroot</a></h4>
<p>Reset the virtual root back to the initial value.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ResetVroot&quot;</code></li>
<li>YAML: <code>ResetVroot</code></li>
</ul>
<h3 id="reading-input"><a class="header" href="#reading-input">Reading Input</a></h3>
<h4 id="setinputprompt"><a class="header" href="#setinputprompt">SetInputPrompt</a></h4>
<p>Set the input prompt temporarily, until the input buffer is reset.</p>
<p>Type: { SetInputPrompt = string }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SetInputPrompt = &quot;&quot; }</code></li>
<li>YAML: <code>SetInputPrompt: →</code></li>
</ul>
<h4 id="updateinputbuffer"><a class="header" href="#updateinputbuffer">UpdateInputBuffer</a></h4>
<p>Update the input buffer using cursor based operations.</p>
<p>Type: { UpdateInputBuffer = <a href="https://xplr.dev/en/input-operation">Input Operation</a> }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ UpdateInputBuffer = &quot;GoToPreviousWord&quot; }</code></li>
<li>YAML: <code>UpdateInputBuffer: GoToPreviousWord</code></li>
</ul>
<h4 id="updateinputbufferfromkey"><a class="header" href="#updateinputbufferfromkey">UpdateInputBufferFromKey</a></h4>
<p>Update the input buffer from the key read from keyboard input.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;UpdateInputBufferFromKey&quot;</code></li>
<li>YAML: <code>UpdateInputBufferFromKey</code></li>
</ul>
<h4 id="bufferinput"><a class="header" href="#bufferinput">BufferInput</a></h4>
<p>Append/buffer the given string into the input buffer.</p>
<p>Type: { BufferInput = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ BufferInput = &quot;foo&quot; }</code></li>
<li>YAML: <code>BufferInput: foo</code></li>
</ul>
<h4 id="bufferinputfromkey"><a class="header" href="#bufferinputfromkey">BufferInputFromKey</a></h4>
<p>Append/buffer the character read from a keyboard input into the
input buffer.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;BufferInputFromKey&quot;</code></li>
<li>YAML: <code>BufferInputFromKey</code></li>
</ul>
<h4 id="setinputbuffer"><a class="header" href="#setinputbuffer">SetInputBuffer</a></h4>
<p>Set/rewrite the input buffer with the given string.
When the input buffer is not-null (even if empty string)
it will show in the UI.</p>
<p>Type: { SetInputBuffer = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SetInputBuffer = &quot;foo&quot; }</code></li>
<li>YAML: <code>SetInputBuffer: foo</code></li>
</ul>
<h4 id="removeinputbufferlastcharacter"><a class="header" href="#removeinputbufferlastcharacter">RemoveInputBufferLastCharacter</a></h4>
<p>Remove input buffer's last character.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;RemoveInputBufferLastCharacter&quot;</code></li>
<li>YAML: <code>RemoveInputBufferLastCharacter</code></li>
</ul>
<h4 id="removeinputbufferlastword"><a class="header" href="#removeinputbufferlastword">RemoveInputBufferLastWord</a></h4>
<p>Remove input buffer's last word.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;RemoveInputBufferLastWord&quot;</code></li>
<li>YAML: <code>RemoveInputBufferLastWord</code></li>
</ul>
<h4 id="resetinputbuffer"><a class="header" href="#resetinputbuffer">ResetInputBuffer</a></h4>
<p>Reset the input buffer back to null. It will not show in the UI.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ResetInputBuffer&quot;</code></li>
<li>YAML: <code>ResetInputBuffer</code></li>
</ul>
<h3 id="switching-mode"><a class="header" href="#switching-mode">Switching Mode</a></h3>
<h4 id="switchmode"><a class="header" href="#switchmode">SwitchMode</a></h4>
<p>Switch input <a href="https://xplr.dev/en/modes">mode</a>.</p>
<p>Type : { SwitchMode = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SwitchMode = &quot;default&quot; }</code></li>
<li>YAML: SwitchMode: default</li>
</ul>
<blockquote>
<p><strong>NOTE:</strong> To be specific about which mode to switch to, use
<code>SwitchModeBuiltin</code> or <code>SwitchModeCustom</code> instead.</p>
</blockquote>
<h4 id="switchmodekeepinginputbuffer"><a class="header" href="#switchmodekeepinginputbuffer">SwitchModeKeepingInputBuffer</a></h4>
<p>Switch input <a href="https://xplr.dev/en/modes">mode</a>.
It keeps the input buffer.</p>
<p>Type: { SwitchModeKeepingInputBuffer = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SwitchModeKeepingInputBuffer = &quot;default&quot; }</code></li>
<li>YAML: <code>SwitchModeKeepingInputBuffer: default</code></li>
</ul>
<blockquote>
<p><strong>NOTE:</strong> To be specific about which mode to switch to, use
<code>SwitchModeBuiltinKeepingInputBuffer</code> or
<code>SwitchModeCustomKeepingInputBuffer</code> instead.</p>
</blockquote>
<h4 id="switchmodebuiltin"><a class="header" href="#switchmodebuiltin">SwitchModeBuiltin</a></h4>
<p>Switch to a <a href="https://xplr.dev/en/modes#builtin">builtin mode</a>.
It clears the input buffer.</p>
<p>Type: { SwitchModeBuiltin = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SwitchModeBuiltin = &quot;default&quot; }</code></li>
<li>YAML: <code>SwitchModeBuiltin: default</code></li>
</ul>
<h4 id="switchmodebuiltinkeepinginputbuffer"><a class="header" href="#switchmodebuiltinkeepinginputbuffer">SwitchModeBuiltinKeepingInputBuffer</a></h4>
<p>Switch to a <a href="https://xplr.dev/en/modes#builtin">builtin mode</a>.
It keeps the input buffer.</p>
<p>Type: { SwitchModeBuiltinKeepingInputBuffer = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SwitchModeBuiltinKeepingInputBuffer = &quot;default&quot; }</code></li>
<li>YAML: <code>SwitchModeBuiltinKeepingInputBuffer: default</code></li>
</ul>
<h4 id="switchmodecustom"><a class="header" href="#switchmodecustom">SwitchModeCustom</a></h4>
<p>Switch to a <a href="https://xplr.dev/en/modes#custom">custom mode</a>.
It clears the input buffer.</p>
<p>Type: { SwitchModeCustom = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SwitchModeCustom = &quot;my_custom_mode&quot; }</code></li>
<li>YAML: <code>SwitchModeCustom: my_custom_mode</code></li>
</ul>
<h4 id="switchmodecustomkeepinginputbuffer"><a class="header" href="#switchmodecustomkeepinginputbuffer">SwitchModeCustomKeepingInputBuffer</a></h4>
<p>Switch to a <a href="https://xplr.dev/en/modes#custom">custom mode</a>.
It keeps the input buffer.</p>
<p>Type: { SwitchModeCustomKeepingInputBuffer = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SwitchModeCustomKeepingInputBuffer = &quot;my_custom_mode&quot; }</code></li>
<li>YAML: <code>SwitchModeCustomKeepingInputBuffer: my_custom_mode</code></li>
</ul>
<h4 id="popmode"><a class="header" href="#popmode">PopMode</a></h4>
<p>Pop the last mode from the history and switch to it.
It clears the input buffer.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;PopMode&quot;</code></li>
<li>YAML: <code>PopMode</code></li>
</ul>
<h4 id="popmodekeepinginputbuffer"><a class="header" href="#popmodekeepinginputbuffer">PopModeKeepingInputBuffer</a></h4>
<p>Pop the last mode from the history and switch to it.
It keeps the input buffer.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>PopModeKeepingInputBuffer</code></li>
<li>YAML: <code>PopModeKeepingInputBuffer</code></li>
</ul>
<h3 id="switching-layout"><a class="header" href="#switching-layout">Switching Layout</a></h3>
<h4 id="switchlayout"><a class="header" href="#switchlayout">SwitchLayout</a></h4>
<p>Switch <a href="https://xplr.dev/en/layouts">layout</a>.</p>
<p>Type: { SwitchLayout = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SwitchLayout = &quot;default&quot; }</code></li>
<li>YAML: <code>SwitchLayout: default</code></li>
</ul>
<blockquote>
<p><strong>NOTE:</strong> To be specific about which layout to switch to, use <code>SwitchLayoutBuiltin</code> or
<code>SwitchLayoutCustom</code> instead.</p>
</blockquote>
<h4 id="switchlayoutbuiltin"><a class="header" href="#switchlayoutbuiltin">SwitchLayoutBuiltin</a></h4>
<p>Switch to a <a href="https://xplr.dev/en/layouts#builtin">builtin layout</a>.</p>
<p>Type: { SwitchLayoutBuiltin = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SwitchLayoutBuiltin = &quot;default&quot; }</code></li>
<li>YAML: <code>SwitchLayoutBuiltin: default</code></li>
</ul>
<h4 id="switchlayoutcustom"><a class="header" href="#switchlayoutcustom">SwitchLayoutCustom</a></h4>
<p>Switch to a <a href="https://xplr.dev/en/layouts#custom">custom layout</a>.</p>
<p>Type: { SwitchLayoutCustom = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SwitchLayoutCustom = &quot;my_custom_layout&quot; }</code></li>
<li>YAML: <code>SwitchLayoutCustom: my_custom_layout</code></li>
</ul>
<h3 id="executing-commands"><a class="header" href="#executing-commands">Executing Commands</a></h3>
<h4 id="call"><a class="header" href="#call">Call</a></h4>
<p>Like <code>Call0</code>, but it uses <code>\n</code> as the delimiter in input/output pipes,
hence it cannot handle files with <code>\n</code> in the name.
You may want to use <code>Call0</code> instead.</p>
<h4 id="call0"><a class="header" href="#call0">Call0</a></h4>
<p>Call a shell command with the given arguments.
Note that the arguments will be shell-escaped.
So to read the variables, the <code>-c</code> option of the shell
can be used.
You may need to pass <code>ExplorePwd</code> depending on the expectation.</p>
<p>Type: { Call0 = { command = &quot;string&quot;, args = { &quot;list&quot;, &quot;of&quot;, &quot;string&quot; } }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ Call0 = { command = &quot;bash&quot;, args = { &quot;-c&quot;, &quot;read -p test&quot; } } }</code></li>
<li>YAML: <code>Call0: { command: bash, args: [&quot;-c&quot;, &quot;read -p test&quot;] }</code></li>
</ul>
<h4 id="callsilently"><a class="header" href="#callsilently">CallSilently</a></h4>
<p>Like <code>CallSilently0</code>, but it uses <code>\n</code> as the delimiter in input/output
pipes, hence it cannot handle files with <code>\n</code> in the name.
You may want to use <code>CallSilently0</code> instead.</p>
<h4 id="callsilently0"><a class="header" href="#callsilently0">CallSilently0</a></h4>
<p>Like <code>Call0</code> but without the flicker. The stdin, stdout
stderr will be piped to null. So it's non-interactive.</p>
<p>Type: { CallSilently0 = { command = &quot;string&quot;, args = {&quot;list&quot;, &quot;of&quot;, &quot;string&quot;} } }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ CallSilently0 = { command = &quot;tput&quot;, args = { &quot;bell&quot; } } }</code></li>
<li>YAML: <code>CallSilently0: { command: tput, args: [&quot;bell&quot;] }</code></li>
</ul>
<h4 id="bashexec"><a class="header" href="#bashexec">BashExec</a></h4>
<p>Like <code>BashExec0</code>, but it uses <code>\n</code> as the delimiter in input/output
pipes, hence it cannot handle files with <code>\n</code> in the name.
You may want to use <code>BashExec0</code> instead.</p>
<h4 id="bashexec0"><a class="header" href="#bashexec0">BashExec0</a></h4>
<p>An alias to <code>Call: {command: bash, args: [&quot;-c&quot;, &quot;{string}&quot;], silent: false}</code>
where <code>{string}</code> is the given value.</p>
<p>Type: { BashExec0 = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ BashExec0 = &quot;read -p test&quot; }</code></li>
<li>YAML: <code>BashExec0: &quot;read -p test&quot;</code></li>
</ul>
<h4 id="bashexecsilently"><a class="header" href="#bashexecsilently">BashExecSilently</a></h4>
<p>Like <code>BashExecSilently0</code>, but it uses <code>\n</code> as the delimiter in
input/output pipes, hence it cannot handle files with <code>\n</code> in the name.
You may want to use <code>BashExecSilently0</code> instead.</p>
<h4 id="bashexecsilently0"><a class="header" href="#bashexecsilently0">BashExecSilently0</a></h4>
<p>Like <code>BashExec0</code> but without the flicker. The stdin, stdout
stderr will be piped to null. So it's non-interactive.</p>
<p>Type: { BashExecSilently0 = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ BashExecSilently0 = &quot;tput bell&quot; }</code></li>
<li>YAML: <code>BashExecSilently0: &quot;tput bell&quot;</code></li>
</ul>
<h3 id="calling-lua-functions"><a class="header" href="#calling-lua-functions">Calling Lua Functions</a></h3>
<h4 id="calllua"><a class="header" href="#calllua">CallLua</a></h4>
<p>Call a Lua function.</p>
<p>A <a href="https://xplr.dev/en/lua-function-calls#lua-context">Lua Context</a>
object will be passed to the function as argument.
The function can optionally return a list of messages for xplr to
handle after the executing the function.</p>
<p>Type: { CallLua = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ CallLua = &quot;custom.some_custom_funtion&quot; }</code></li>
<li>YAML: <code>CallLua: custom.some_custom_funtion</code></li>
</ul>
<h4 id="callluasilently"><a class="header" href="#callluasilently">CallLuaSilently</a></h4>
<p>Like <code>CallLua</code> but without the flicker. The stdin, stdout
stderr will be piped to null. So it's non-interactive.</p>
<p>Type: { CallLuaSilently = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ CallLuaSilently = &quot;custom.some_custom_function&quot; }</code></li>
<li>YAML: <code>CallLuaSilently: custom.some_custom_function</code></li>
</ul>
<h4 id="luaeval"><a class="header" href="#luaeval">LuaEval</a></h4>
<p>Execute Lua code without needing to define a function.</p>
<p>If the <code>string</code> is a callable, xplr will try to call it with with the
<a href="https://xplr.dev/en/lua-function-calls#lua-context">Lua Context</a>
argument.</p>
<p>Type: { LuaEval = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ LuaEval = [[return { { LogInfo = io.read() } }]] }</code></li>
<li>Lua: <code>{ LuaEval = [[function(app) return { { LogInfo = app.pwd } } end]] }</code></li>
<li>YAML: <code>LuaEval: &quot;return { { LogInfo = io.read() } }&quot;</code></li>
<li>YAML: <code>LuaEval: &quot;function(app) return { { LogInfo = app.pwd } } end&quot;</code></li>
</ul>
<h4 id="luaevalsilently"><a class="header" href="#luaevalsilently">LuaEvalSilently</a></h4>
<p>Like <code>LuaEval</code> but without the flicker. The stdin, stdout
stderr will be piped to null. So it's non-interactive.</p>
<p>Type: { LuaEvalSilently = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ LuaEvalSilently = [[return { { LogInfo = &quot;foo&quot; } }]] }</code></li>
<li>YAML: <code>LuaEvalSilently: &quot;return { { LogInfo = 'foo' } }&quot;</code></li>
</ul>
<h3 id="select-operations"><a class="header" href="#select-operations">Select Operations</a></h3>
<h4 id="select"><a class="header" href="#select">Select</a></h4>
<p>Select the focused node.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;Select&quot;</code></li>
<li>YAML: <code>Select</code></li>
</ul>
<h4 id="selectall"><a class="header" href="#selectall">SelectAll</a></h4>
<p>Select all the visible nodes.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;SelectAll&quot;</code></li>
<li>YAML: <code>SelectAll</code></li>
</ul>
<h4 id="selectpath"><a class="header" href="#selectpath">SelectPath</a></h4>
<p>Select the given path.</p>
<p>Type: { SelectPath = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SelectPath = &quot;/path/to/file&quot; }</code></li>
<li>YAML: <code>SelectPath: /path/to/file</code></li>
</ul>
<h4 id="unselect"><a class="header" href="#unselect">UnSelect</a></h4>
<p>Unselect the focused node.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;UnSelect&quot;</code></li>
<li>YAML: <code>UnSelect</code></li>
</ul>
<h4 id="unselectall"><a class="header" href="#unselectall">UnSelectAll</a></h4>
<p>Unselect all the visible nodes.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;UnSelectAll&quot;</code></li>
<li>YAML: <code>UnSelectAll</code></li>
</ul>
<h4 id="unselectpath"><a class="header" href="#unselectpath">UnSelectPath</a></h4>
<p>UnSelect the given path.</p>
<p>Type: { UnSelectPath = &quot;string)&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ UnSelectPath = &quot;/path/to/file&quot; }</code></li>
<li>YAML: <code>UnSelectPath: /path/to/file</code></li>
</ul>
<h4 id="toggleselection"><a class="header" href="#toggleselection">ToggleSelection</a></h4>
<p>Toggle selection on the focused node.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ToggleSelection&quot;</code></li>
<li>YAML <code>ToggleSelection</code></li>
</ul>
<h4 id="toggleselectall"><a class="header" href="#toggleselectall">ToggleSelectAll</a></h4>
<p>Toggle between select all and unselect all.
Example:</p>
<ul>
<li>Lua: <code>&quot;ToggleSelectAll&quot;</code></li>
<li>YAML: <code>ToggleSelectAll</code></li>
</ul>
<h4 id="toggleselectionbypath"><a class="header" href="#toggleselectionbypath">ToggleSelectionByPath</a></h4>
<p>Toggle selection by file path.</p>
<p>Type: { ToggleSelectionByPath = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ ToggleSelectionByPath = &quot;/path/to/file&quot; }</code></li>
<li>YAML: <code>ToggleSelectionByPath: /path/to/file</code></li>
</ul>
<h4 id="clearselection"><a class="header" href="#clearselection">ClearSelection</a></h4>
<p>Clear the selection.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ClearSelection&quot;</code></li>
<li>YAML: <code>ClearSelection</code></li>
</ul>
<h3 id="filter-operations"><a class="header" href="#filter-operations">Filter Operations</a></h3>
<h4 id="addnodefilter"><a class="header" href="#addnodefilter">AddNodeFilter</a></h4>
<p>Add a <a href="https://xplr.dev/en/filtering#filter">filter</a> to exclude nodes
while exploring directories.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
Filters get automatically cleared when changing directories.</p>
<p>Type: { AddNodeFilter = { filter = <a href="https://xplr.dev/en/filtering#filter">Filter</a>, input = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ AddNodeFilter = { filter = &quot;RelativePathDoesStartWith&quot;, input = &quot;foo&quot; } }</code></li>
<li>YAML: <code>AddNodeFilter: { filter: RelativePathDoesStartWith, input: foo }</code></li>
</ul>
<h4 id="removenodefilter"><a class="header" href="#removenodefilter">RemoveNodeFilter</a></h4>
<p>Remove an existing <a href="https://xplr.dev/en/filtering#filter">filter</a>.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Type: { RemoveNodeFilter = { filter = <a href="https://xplr.dev/en/filtering">Filter</a>, input = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ RemoveNodeFilter: { filter: &quot;RelativePathDoesStartWith&quot;, input: &quot;foo&quot; } }</code></li>
<li>YAML: <code>RemoveNodeFilter: { filter: RelativePathDoesStartWith, input: foo }</code></li>
</ul>
<h4 id="togglenodefilter"><a class="header" href="#togglenodefilter">ToggleNodeFilter</a></h4>
<p>Remove a <a href="https://xplr.dev/en/filtering#filter">filter</a> if it exists,
else, add a it.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Type: { ToggleNodeFilter = { filter = <a href="https://xplr.dev/en/filtering">Filter</a>, input = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ ToggleNodeFilter = { filter = &quot;RelativePathDoesStartWith&quot;, input = &quot;foo&quot; } }</code></li>
<li>YAML: <code>ToggleNodeFilter: { filter: RelativePathDoesStartWith, input: foo }</code></li>
</ul>
<h4 id="addnodefilterfrominput"><a class="header" href="#addnodefilterfrominput">AddNodeFilterFromInput</a></h4>
<p>Add a node <a href="https://xplr.dev/en/filtering#filter">filter</a> reading the
input from the buffer.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Type: { AddNodeFilterFromInput = <a href="https://xplr.dev/en/filtering">Filter</a> }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ AddNodeFilterFromInput = &quot;RelativePathDoesStartWith&quot; }</code></li>
<li>YAML: <code>AddNodeFilterFromInput: RelativePathDoesStartWith</code></li>
</ul>
<h4 id="removenodefilterfrominput"><a class="header" href="#removenodefilterfrominput">RemoveNodeFilterFromInput</a></h4>
<p>Remove a node <a href="https://xplr.dev/en/filtering#filter">filter</a> reading
the input from the buffer.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Type: { RemoveNodeFilterFromInput = <a href="https://xplr.dev/en/filtering">Filter</a> }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ RemoveNodeFilterFromInput = &quot;RelativePathDoesStartWith&quot; }</code></li>
<li>YAML: <code>RemoveNodeFilterFromInput: RelativePathDoesStartWith</code></li>
</ul>
<h4 id="removelastnodefilter"><a class="header" href="#removelastnodefilter">RemoveLastNodeFilter</a></h4>
<p>Remove the last node <a href="https://xplr.dev/en/filtering">filter</a>.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;RemoveLastNodeFilter&quot;</code></li>
<li>YAML: <code>RemoveLastNodeFilter</code></li>
</ul>
<h4 id="resetnodefilters"><a class="header" href="#resetnodefilters">ResetNodeFilters</a></h4>
<p>Reset the node <a href="https://xplr.dev/en/filtering">filters</a> back to the
default configuration.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ResetNodeFilters&quot;</code></li>
<li>YAML: <code>ResetNodeFilters</code></li>
</ul>
<h4 id="clearnodefilters"><a class="header" href="#clearnodefilters">ClearNodeFilters</a></h4>
<p>Clear all the node <a href="https://xplr.dev/en/filtering">filters</a>.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ClearNodeFilters&quot;</code></li>
<li>YAML: <code>ClearNodeFilters</code></li>
</ul>
<h3 id="sort-operations"><a class="header" href="#sort-operations">Sort Operations</a></h3>
<h4 id="addnodesorter"><a class="header" href="#addnodesorter">AddNodeSorter</a></h4>
<p>Add a <a href="https://xplr.dev/en/sorting#sorter">sorter</a> to sort nodes while
exploring directories.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Type: { AddNodeSorter = { sorter = <a href="https://xplr.dev/en/sorting#sorter">Sorter</a>, reverse = bool } }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ AddNodeSorter = { sorter = &quot;ByRelativePath&quot;, reverse = false } }</code></li>
<li>YAML: <code>AddNodeSorter: { sorter: ByRelativePath, reverse: false }</code></li>
</ul>
<h4 id="removenodesorter"><a class="header" href="#removenodesorter">RemoveNodeSorter</a></h4>
<p>Remove an existing <a href="https://xplr.dev/en/sorting#sorter">sorter</a>.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Type: { RemoveNodeSorter = <a href="https://xplr.dev/en/sorting#sorter">Sorter</a> }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ RemoveNodeSorter = &quot;ByRelativePath&quot; }</code></li>
<li>YAML: <code>RemoveNodeSorter: ByRelativePath</code></li>
</ul>
<h4 id="reversenodesorter"><a class="header" href="#reversenodesorter">ReverseNodeSorter</a></h4>
<p>Reverse a node <a href="https://xplr.dev/en/sorting#sorter">sorter</a>.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Type: { ReverseNodeSorter = <a href="https://xplr.dev/en/sorting#sorter">Sorter</a> }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ ReverseNodeSorter = &quot;ByRelativePath&quot; }</code></li>
<li>YAML: <code>ReverseNodeSorter: ByRelativePath</code></li>
</ul>
<h4 id="togglenodesorter"><a class="header" href="#togglenodesorter">ToggleNodeSorter</a></h4>
<p>Remove a <a href="https://xplr.dev/en/sorting#sorter">sorter</a> if it exists,
else, add a it.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Type: { ToggleNodeSorter = { sorter = <a href="https://xplr.dev/en/sorting#sorter">Sorter</a>, reverse = bool } }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ ToggleSorterSorter: { sorter = &quot;ByRelativePath&quot;, reverse = false } }</code></li>
<li>YAML: <code>ToggleSorterSorter: {sorter: ByRelativePath, reverse: false }</code></li>
</ul>
<h4 id="reversenodesorters"><a class="header" href="#reversenodesorters">ReverseNodeSorters</a></h4>
<p>Reverse the node <a href="https://xplr.dev/en/sorting#sorter">sorters</a>.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ReverseNodeSorters&quot;</code></li>
<li>YAML: <code>ReverseNodeSorters</code></li>
</ul>
<h4 id="removelastnodesorter"><a class="header" href="#removelastnodesorter">RemoveLastNodeSorter</a></h4>
<p>Remove the last node <a href="https://xplr.dev/en/sorting#sorter">sorter</a>.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;RemoveLastNodeSorter&quot;</code></li>
<li>YAML: <code>RemoveLastNodeSorter</code></li>
</ul>
<h4 id="resetnodesorters"><a class="header" href="#resetnodesorters">ResetNodeSorters</a></h4>
<p>Reset the node <a href="https://xplr.dev/en/sorting#sorter">sorters</a> back to
the default configuration.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ResetNodeSorters&quot;</code></li>
<li>YAML: <code>ResetNodeSorters</code></li>
</ul>
<h4 id="clearnodesorters"><a class="header" href="#clearnodesorters">ClearNodeSorters</a></h4>
<p>Clear all the node <a href="https://xplr.dev/en/sorting#sorter">sorters</a>.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ClearNodeSorters&quot;</code></li>
<li>YAML: <code>ClearNodeSorters</code></li>
</ul>
<h3 id="search-operations"><a class="header" href="#search-operations">Search Operations</a></h3>
<h4 id="search-1"><a class="header" href="#search-1">Search</a></h4>
<p>Search files using the current or default (fuzzy) search algorithm.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
It gets reset automatically when changing directory.</p>
<p>Type: { Search = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ Search = &quot;pattern&quot; }</code></li>
<li>YAML: <code>Search: pattern</code></li>
</ul>
<h4 id="searchfrominput"><a class="header" href="#searchfrominput">SearchFromInput</a></h4>
<p>Calls <code>Search</code> with the input taken from the input buffer.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;SearchFromInput&quot;</code></li>
<li>YAML: <code>SearchFromInput</code></li>
</ul>
<h4 id="searchfuzzy"><a class="header" href="#searchfuzzy">SearchFuzzy</a></h4>
<p>Search files using fuzzy match algorithm.
It keeps the filters, but overrides the sorters.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
It gets reset automatically when changing directory.</p>
<p>Type: { SearchFuzzy = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SearchFuzzy = &quot;pattern&quot; }</code></li>
<li>YAML: <code>SearchFuzzy: pattern</code></li>
</ul>
<h4 id="searchfuzzyfrominput"><a class="header" href="#searchfuzzyfrominput">SearchFuzzyFromInput</a></h4>
<p>Calls <code>SearchFuzzy</code> with the input taken from the input buffer.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
It gets reset automatically when changing directory.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;SearchFuzzyFromInput&quot;</code></li>
<li>YAML: <code>SearchFuzzyFromInput</code></li>
</ul>
<h4 id="searchfuzzyunordered"><a class="header" href="#searchfuzzyunordered">SearchFuzzyUnordered</a></h4>
<p>Like <code>SearchFuzzy</code>, but doesn't not perform rank based sorting.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
It gets reset automatically when changing directory.</p>
<p>Type: { SearchFuzzyUnordered = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SearchFuzzyUnordered = &quot;pattern&quot; }</code></li>
<li>YAML: <code>SearchFuzzyUnordered: pattern</code></li>
</ul>
<h4 id="searchfuzzyunorderedfrominput"><a class="header" href="#searchfuzzyunorderedfrominput">SearchFuzzyUnorderedFromInput</a></h4>
<p>Calls <code>SearchFuzzyUnordered</code> with the input taken from the input buffer.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
It gets reset automatically when changing directory.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;SearchFuzzyUnorderedFromInput&quot;</code></li>
<li>YAML: <code>SearchFuzzyUnorderedFromInput</code></li>
</ul>
<h4 id="searchregex"><a class="header" href="#searchregex">SearchRegex</a></h4>
<p>Search files using regex match algorithm.
It keeps the filters, but overrides the sorters.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
It gets reset automatically when changing directory.</p>
<p>Type: { SearchRegex = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SearchRegex = &quot;pattern&quot; }</code></li>
<li>YAML: <code>SearchRegex: pattern</code></li>
</ul>
<h4 id="searchregexfrominput"><a class="header" href="#searchregexfrominput">SearchRegexFromInput</a></h4>
<p>Calls <code>SearchRegex</code> with the input taken from the input buffer.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
It gets reset automatically when changing directory.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;SearchRegexFromInput&quot;</code></li>
<li>YAML: <code>SearchRegexFromInput</code></li>
</ul>
<h4 id="searchregexunordered"><a class="header" href="#searchregexunordered">SearchRegexUnordered</a></h4>
<p>Like <code>SearchRegex</code>, but doesn't not perform rank based sorting.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
It gets reset automatically when changing directory.</p>
<p>Type: { SearchRegexUnordered = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ SearchRegexUnordered = &quot;pattern&quot; }</code></li>
<li>YAML: <code>SearchRegexUnordered: pattern</code></li>
</ul>
<h4 id="searchregexunorderedfrominput"><a class="header" href="#searchregexunorderedfrominput">SearchRegexUnorderedFromInput</a></h4>
<p>Calls <code>SearchRegexUnordered</code> with the input taken from the input buffer.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.
It gets reset automatically when changing directory.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;SearchRegexUnorderedFromInput&quot;</code></li>
<li>YAML: <code>SearchRegexUnorderedFromInput</code></li>
</ul>
<h4 id="togglesearchalgorithm"><a class="header" href="#togglesearchalgorithm">ToggleSearchAlgorithm</a></h4>
<p>Toggles between different search algorithms, without changing the input
buffer
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ToggleSearchAlgorithm&quot;</code></li>
<li>YAML: <code>ToggleSearchAlgorithm</code></li>
</ul>
<h4 id="enablesearchorder"><a class="header" href="#enablesearchorder">EnableSearchOrder</a></h4>
<p>Enables ranked search without changing the input buffer.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;EnableOrderedSearch&quot;</code></li>
<li>YAML: <code>EnableSearchOrder</code></li>
</ul>
<h4 id="disablesearchorder"><a class="header" href="#disablesearchorder">DisableSearchOrder</a></h4>
<p>Disabled ranked search without changing the input buffer.
You need to call <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> explicitly.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;DisableSearchOrder&quot;</code></li>
<li>YAML: <code>DisableSearchOrder</code></li>
</ul>
<h4 id="togglesearchorder"><a class="header" href="#togglesearchorder">ToggleSearchOrder</a></h4>
<p>Toggles ranked search without changing the input buffer.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ToggleSearchOrder&quot;</code></li>
<li>YAML: <code>ToggleSearchOrder</code></li>
</ul>
<h4 id="acceptsearch"><a class="header" href="#acceptsearch">AcceptSearch</a></h4>
<p>Accepts the search by keeping the latest focus while in search mode.
Automatically calls <code>ExplorePwd</code>.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;AcceptSearch&quot;</code></li>
<li>YAML: <code>AcceptSearch</code></li>
</ul>
<h4 id="cancelsearch"><a class="header" href="#cancelsearch">CancelSearch</a></h4>
<p>Cancels the search by discarding the latest focus and recovering
the focus before search.
Automatically calls <code>ExplorePwd</code>.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;CancelSearch&quot;</code></li>
<li>YAML: <code>CancelSearch</code></li>
</ul>
<h3 id="mouse-operations"><a class="header" href="#mouse-operations">Mouse Operations</a></h3>
<h4 id="enablemouse"><a class="header" href="#enablemouse">EnableMouse</a></h4>
<p>Enable mouse</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;EnableMouse&quot;</code></li>
<li>YAML: <code>EnableMouse</code></li>
</ul>
<h4 id="disablemouse"><a class="header" href="#disablemouse">DisableMouse</a></h4>
<p>Disable mouse</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;DisableMouse&quot;</code></li>
<li>YAML: <code>DisableMouse</code></li>
</ul>
<h4 id="togglemouse"><a class="header" href="#togglemouse">ToggleMouse</a></h4>
<p>Toggle mouse</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;ToggleMouse&quot;</code></li>
<li>YAML: <code>ToggleMouse</code></li>
</ul>
<h3 id="fifo-operations"><a class="header" href="#fifo-operations">Fifo Operations</a></h3>
<h4 id="startfifo"><a class="header" href="#startfifo">StartFifo</a></h4>
<p>Start piping the focused path to the given fifo path</p>
<p>Type: { StartFifo = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ StartFifo = &quot;/tmp/xplr.fifo }</code></li>
<li>YAML: <code>StartFifo: /tmp/xplr.fifo</code></li>
</ul>
<h4 id="stopfifo"><a class="header" href="#stopfifo">StopFifo</a></h4>
<p>Close the active fifo and stop piping.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;StopFifo&quot;</code></li>
<li>YAML: <code>StopFifo</code></li>
</ul>
<h4 id="togglefifo"><a class="header" href="#togglefifo">ToggleFifo</a></h4>
<p>Toggle between {Start|Stop}Fifo</p>
<p>Type: { ToggleFifo = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ ToggleFifo = &quot;/path/to/fifo&quot; }</code></li>
<li>YAML: <code>ToggleFifo: /path/to/fifo</code></li>
</ul>
<h3 id="logging"><a class="header" href="#logging">Logging</a></h3>
<h4 id="loginfo"><a class="header" href="#loginfo">LogInfo</a></h4>
<p>Log information message.</p>
<p>Type: { LogInfo = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ LogInfo = &quot;launching satellite&quot; }</code></li>
<li>YAML: <code>LogInfo: launching satellite</code></li>
</ul>
<h4 id="logsuccess"><a class="header" href="#logsuccess">LogSuccess</a></h4>
<p>Log a success message.</p>
<p>Type: { LogSuccess = &quot;String&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ LogSuccess = &quot;satellite reached destination&quot; }</code></li>
<li>YAML: <code>LogSuccess: satellite reached destination</code></li>
</ul>
<h4 id="logwarning"><a class="header" href="#logwarning">LogWarning</a></h4>
<p>Log an warning message.</p>
<p>Type: { LogWarning = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ LogWarning = &quot;satellite is heating&quot; }</code></li>
<li>YAML: <code>LogWarning: satellite is heating</code></li>
</ul>
<h4 id="logerror"><a class="header" href="#logerror">LogError</a></h4>
<p>Log an error message.</p>
<p>Type: { LogError = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ LogError = &quot;satellite crashed&quot; }</code></li>
<li>YAML: <code>LogError: satellite crashed</code></li>
</ul>
<h3 id="debugging"><a class="header" href="#debugging">Debugging</a></h3>
<h4 id="debug"><a class="header" href="#debug">Debug</a></h4>
<p>Write the application state to a file, without quitting. Also helpful
for debugging.</p>
<p>Type: { Debug = &quot;string&quot; }</p>
<p>Example:</p>
<ul>
<li>Lua: <code>{ Debug = &quot;/path/to/file&quot; }</code></li>
<li>YAML: <code>Debug: /path/to/file</code></li>
</ul>
<h3 id="quit-options"><a class="header" href="#quit-options">Quit Options</a></h3>
<h4 id="quit-1"><a class="header" href="#quit-1">Quit</a></h4>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;Quit&quot;</code></li>
<li>YAML: <code>Quit</code></li>
</ul>
<p>Quit with returncode zero (success).</p>
<h4 id="printpwdandquit"><a class="header" href="#printpwdandquit">PrintPwdAndQuit</a></h4>
<p>Print $PWD and quit.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;PrintPwdAndQuit&quot;</code></li>
<li>YAML: <code>PrintPwdAndQuit</code></li>
</ul>
<h4 id="printfocuspathandquit"><a class="header" href="#printfocuspathandquit">PrintFocusPathAndQuit</a></h4>
<p>Print the path under focus and quit. It can be empty string if there's
nothing to focus.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;PrintFocusPathAndQuit&quot;</code></li>
<li>YAML: <code>PrintFocusPathAndQuit</code></li>
</ul>
<h4 id="printselectionandquit"><a class="header" href="#printselectionandquit">PrintSelectionAndQuit</a></h4>
<p>Print the selected paths and quit. It can be empty is no path is
selected.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;PrintSelectionAndQuit&quot;</code></li>
<li>YAML: <code>PrintSelectionAndQuit</code></li>
</ul>
<h4 id="printresultandquit"><a class="header" href="#printresultandquit">PrintResultAndQuit</a></h4>
<p>Print the selected paths if it's not empty, else, print the focused
node's path.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;PrintResultAndQuit&quot;</code></li>
<li>YAML: <code>PrintResultAndQuit</code></li>
</ul>
<h4 id="printappstateandquit"><a class="header" href="#printappstateandquit">PrintAppStateAndQuit</a></h4>
<p>Print the state of application in YAML format. Helpful for debugging or
generating the default configuration file.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;PrintAppStateAndQuit&quot;</code></li>
<li>YAML: <code>PrintAppStateAndQuit</code></li>
</ul>
<h4 id="terminate"><a class="header" href="#terminate">Terminate</a></h4>
<p>Terminate the application with a non-zero return code.</p>
<p>Example:</p>
<ul>
<li>Lua: <code>&quot;Terminate&quot;</code></li>
<li>YAML: <code>Terminate</code></li>
</ul>
<h2 id="also-see-4"><a class="header" href="#also-see-4">Also See:</a></h2>
<ul>
<li><a href="message.html">Message</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="input-operation"><a class="header" href="#input-operation">Input Operation</a></h1>
<p>Cursor based input operation is a <a href="sum-type.html">sum type</a> can be one of the following:</p>
<ul>
<li>{ SetCursor = int }</li>
<li>{ InsertCharacter = str }</li>
<li>&quot;GoToPreviousCharacter&quot;</li>
<li>&quot;GoToNextCharacter&quot;</li>
<li>&quot;GoToPreviousWord&quot;</li>
<li>&quot;GoToNextWord&quot;</li>
<li>&quot;GoToStart&quot;</li>
<li>&quot;GoToEnd&quot;</li>
<li>&quot;DeletePreviousCharacter&quot;</li>
<li>&quot;DeleteNextCharacter&quot;</li>
<li>&quot;DeletePreviousWord&quot;</li>
<li>&quot;DeleteNextWord&quot;</li>
<li>&quot;DeleteLine&quot;</li>
<li>&quot;DeleteTillEnd&quot;</li>
</ul>
<h2 id="also-see-5"><a class="header" href="#also-see-5">Also See:</a></h2>
<ul>
<li><a href="message.html">Message</a></li>
<li><a href="messages.html">Full List of Messages</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="borders"><a class="header" href="#borders">Borders</a></h1>
<p>xplr allows customizing the shape and style of the borders.</p>
<h3 id="border"><a class="header" href="#border">Border</a></h3>
<p>A border is a <a href="sum-type.html">sum type</a> that can be one of the following:</p>
<ul>
<li>&quot;Top&quot;</li>
<li>&quot;Right&quot;</li>
<li>&quot;Bottom&quot;</li>
<li>&quot;Left&quot;</li>
</ul>
<h3 id="border-type"><a class="header" href="#border-type">Border Type</a></h3>
<p>A border type is a <a href="sum-type.html">sum type</a> that can be one of the following:</p>
<ul>
<li>&quot;Plain&quot;</li>
<li>&quot;Rounded&quot;</li>
<li>&quot;Double&quot;</li>
<li>&quot;Thick&quot;</li>
</ul>
<h3 id="border-style"><a class="header" href="#border-style">Border Style</a></h3>
<p>The <a href="style.html#style">style</a> of the borders.</p>
<h2 id="example"><a class="header" href="#example">Example</a></h2>
<pre><code class="language-lua">xplr.config.general.panel_ui.default.borders = { &quot;Top&quot;, &quot;Right&quot;, &quot;Bottom&quot;, &quot;Left&quot; }
xplr.config.general.panel_ui.default.border_type = &quot;Thick&quot;
xplr.config.general.panel_ui.default.border_style.fg = &quot;Black&quot;
xplr.config.general.panel_ui.default.border_style.bg = &quot;Gray&quot;
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="style"><a class="header" href="#style">Style</a></h1>
<p>A style object contains the following information:</p>
<ul>
<li><a href="style.html#fg">fg</a></li>
<li><a href="style.html#bg">bg</a></li>
<li><a href="style.html#add_modifiers">add_modifiers</a></li>
<li><a href="style.html#sub_modifiers">sub_modifiers</a></li>
</ul>
<h3 id="fg"><a class="header" href="#fg">fg</a></h3>
<p>Type: nullable <a href="style.html#color">Color</a></p>
<p>The foreground color.</p>
<h3 id="bg"><a class="header" href="#bg">bg</a></h3>
<p>Type: nullable <a href="style.html#color">Color</a></p>
<p>The background color.</p>
<h3 id="add_modifiers"><a class="header" href="#add_modifiers">add_modifiers</a></h3>
<p>Type: nullable list of <a href="style.html#modifier">Modifier</a></p>
<p>Modifiers to add.</p>
<h3 id="sub_modifiers"><a class="header" href="#sub_modifiers">sub_modifiers</a></h3>
<p>Type: nullable list of <a href="style.html#modifier">Modifier</a></p>
<p>Modifiers to remove.</p>
<h2 id="color"><a class="header" href="#color">Color</a></h2>
<p>Color is a <a href="sum-type.html">sum type</a> that can be one of the following:</p>
<ul>
<li>&quot;Reset&quot;</li>
<li>&quot;Black&quot;</li>
<li>&quot;Red&quot;</li>
<li>&quot;Green&quot;</li>
<li>&quot;Yellow&quot;</li>
<li>&quot;Blue&quot;</li>
<li>&quot;Magenta&quot;</li>
<li>&quot;Cyan&quot;</li>
<li>&quot;Gray&quot;</li>
<li>&quot;DarkGray&quot;</li>
<li>&quot;LightRed&quot;</li>
<li>&quot;LightGreen&quot;</li>
<li>&quot;LightYellow&quot;</li>
<li>&quot;LightBlue&quot;</li>
<li>&quot;LightMagenta&quot;</li>
<li>&quot;LightCyan&quot;</li>
<li>&quot;White&quot;</li>
<li>{ Rgb = { int, int, int } }</li>
<li>{ Indexed = int }</li>
</ul>
<h2 id="modifier"><a class="header" href="#modifier">Modifier</a></h2>
<p>Modifier is a <a href="sum-type.html">sum type</a> that can be one of the following:</p>
<ul>
<li>&quot;Bold&quot;</li>
<li>&quot;Dim&quot;</li>
<li>&quot;Italic&quot;</li>
<li>&quot;Underlined&quot;</li>
<li>&quot;SlowBlink&quot;</li>
<li>&quot;RapidBlink&quot;</li>
<li>&quot;Reversed&quot;</li>
<li>&quot;Hidden&quot;</li>
<li>&quot;CrossedOut&quot;</li>
</ul>
<h2 id="example-1"><a class="header" href="#example-1">Example</a></h2>
<pre><code class="language-lua">xplr.config.general.prompt.style.fg = &quot;Red&quot;
xplr.config.general.prompt.style.bg = { Rgb = { 100, 150, 200 } }
xplr.config.general.prompt.style.add_modifiers = { &quot;Bold&quot;, &quot;Italic&quot; }
xplr.config.general.prompt.style.sub_modifiers = { &quot;Hidden&quot; }
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="searching"><a class="header" href="#searching">Searching</a></h1>
<p>xplr supports searching paths using different algorithm. The search mechanism
generally appears between filters and sorters in the <code>Sort &amp; filter</code> panel.</p>
<p>Example:</p>
<pre><code>fzy:foo↓
</code></pre>
<p>This line means that the nodes visible on the table are being filtered using the
<a href="https://en.wikipedia.org/wiki/Approximate_string_matching">fuzzy matching</a> algorithm on the input <code>foo</code>. The arrow means that ranking based
ordering is being applied, i.e. <a href="sorting.html">sorters</a> are being ignored.</p>
<h2 id="node-searcher-applicable"><a class="header" href="#node-searcher-applicable">Node Searcher Applicable</a></h2>
<p>Node Searcher contains the following fields:</p>
<ul>
<li><a href="searching.html#pattern">pattern</a></li>
<li><a href="searching.html#recoverable_focus">recoverable_focus</a></li>
<li><a href="searching.html#algorithm">algorithm</a></li>
<li><a href="searching.html#unordered">unordered</a></li>
</ul>
<h3 id="pattern"><a class="header" href="#pattern">pattern</a></h3>
<p>The patterns used to search.</p>
<p>Type: string</p>
<h3 id="recoverable_focus"><a class="header" href="#recoverable_focus">recoverable_focus</a></h3>
<p>Where to focus when search is cancelled.</p>
<p>Type: nullable string</p>
<h3 id="algorithm"><a class="header" href="#algorithm">algorithm</a></h3>
<p>Search algorithm to use. Defaults to the value set in
<a href="general-config.html#xplrconfiggeneralsearchalgorithm">xplr.config.general.search.algorithm</a>.</p>
<p>It can be one of the following:</p>
<ul>
<li>Fuzzy</li>
<li>Regex</li>
</ul>
<h3 id="unordered"><a class="header" href="#unordered">unordered</a></h3>
<p>Whether to skip ordering the search result by algorithm based ranking. Defaults
to the value set in <a href="general-config.html#xplrconfiggeneralsearchunordered">xplr.config.general.search.unordered</a>.</p>
<p>Type: boolean</p>
<h2 id="example-2"><a class="header" href="#example-2">Example:</a></h2>
<pre><code class="language-lua">local searcher = {
pattern = &quot;pattern to search&quot;,
recoverable_focus = &quot;/path/to/focus/on/cancel&quot;,
algorithm = &quot;Fuzzy&quot;,
unordered = false,
}
xplr.util.explore({ searcher = searcher })
</code></pre>
<p>See <a href="xplr.util.html#xplrutilexplore">xplr.util.explore</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="sorting"><a class="header" href="#sorting">Sorting</a></h1>
<p>xplr supports sorting paths by different properties. The sorting mechanism
works like a pipeline, which in visible in the <code>Sort &amp; filter</code> panel.</p>
<p>Example:</p>
<pre><code>size↑ [i]rel↓ [c]dir↑ [c]file↑ sym↑
</code></pre>
<p>This line means that the nodes visible in the table will be first sorted by
it's size, then by case insensitive relative path, then by the
canonical (symlink resolved) type of the node, and finally by whether or not
the node is a symlink.</p>
<p>The arrows denote the order.</p>
<p>Each part of this pipeline is called <a href="sorting.html#node-sorter-applicable">Node Sorter Applicable</a>.</p>
<h2 id="node-sorter-applicable"><a class="header" href="#node-sorter-applicable">Node Sorter Applicable</a></h2>
<p>It contains the following information:</p>
<ul>
<li><a href="sorting.html#sorter">sorter</a></li>
<li><a href="sorting.html#reverse">reverse</a></li>
</ul>
<h3 id="sorter"><a class="header" href="#sorter">sorter</a></h3>
<p>A sorter is a <a href="sum-type.html">sum type</a> that can be one of the following:</p>
<ul>
<li>&quot;ByRelativePath&quot;</li>
<li>&quot;ByIRelativePath&quot;</li>
<li>&quot;ByExtension&quot;</li>
<li>&quot;ByIsDir&quot;</li>
<li>&quot;ByIsFile&quot;</li>
<li>&quot;ByIsSymlink&quot;</li>
<li>&quot;ByIsBroken&quot;</li>
<li>&quot;ByIsReadonly&quot;</li>
<li>&quot;ByMimeEssence&quot;</li>
<li>&quot;BySize&quot;</li>
<li>&quot;ByCreated&quot;</li>
<li>&quot;ByLastModified&quot;</li>
<li>&quot;ByCanonicalAbsolutePath&quot;</li>
<li>&quot;ByICanonicalAbsolutePath&quot;</li>
<li>&quot;ByCanonicalExtension&quot;</li>
<li>&quot;ByCanonicalIsDir&quot;</li>
<li>&quot;ByCanonicalIsFile&quot;</li>
<li>&quot;ByCanonicalIsReadonly&quot;</li>
<li>&quot;ByCanonicalMimeEssence&quot;</li>
<li>&quot;ByCanonicalSize&quot;</li>
<li>&quot;ByCanonicalCreated&quot;</li>
<li>&quot;ByCanonicalLastModified&quot;</li>
<li>&quot;BySymlinkAbsolutePath&quot;</li>
<li>&quot;ByISymlinkAbsolutePath&quot;</li>
<li>&quot;BySymlinkExtension&quot;</li>
<li>&quot;BySymlinkIsDir&quot;</li>
<li>&quot;BySymlinkIsFile&quot;</li>
<li>&quot;BySymlinkIsReadonly&quot;</li>
<li>&quot;BySymlinkMimeEssence&quot;</li>
<li>&quot;BySymlinkSize&quot;</li>
<li>&quot;BySymlinkCreated&quot;</li>
<li>&quot;BySymlinkLastModified&quot;</li>
</ul>
<h3 id="reverse"><a class="header" href="#reverse">reverse</a></h3>
<p>Type: boolean</p>
<p>It defined the direction of the order.</p>
<h2 id="example-3"><a class="header" href="#example-3">Example</a></h2>
<pre><code class="language-lua">xplr.config.general.initial_sorting = {
{ sorter = &quot;ByCanonicalIsDir&quot;, reverse = true },
{ sorter = &quot;ByIRelativePath&quot;, reverse = false },
}
</code></pre>
<p>This snippet defines the initial sorting logic to be applied when xplr loads.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="filtering"><a class="header" href="#filtering">Filtering</a></h1>
<p>xplr supports filtering paths by different properties. The filtering mechanism
works like a pipeline, which in visible in the <code>Sort &amp; filter</code> panel.</p>
<p>Example:</p>
<pre><code>rel!^. [i]abs=~abc [i]rel!~xyz
</code></pre>
<p>This line means that the nodes visible on the table will first be filtered by
the condition: <em>relative path does not start with <code>.</code></em>, then by the condition:
<em>absolute path contains <code>abc</code> (case insensitive)</em>, and finally by the
condition: <em>relative path does not contain <code>xyz</code></em> (case insensitive).</p>
<p>Each part of this pipeline is called <a href="filtering.html#node-filter-applicable">Node Filter Applicable</a>.</p>
<h2 id="node-filter-applicable"><a class="header" href="#node-filter-applicable">Node Filter Applicable</a></h2>
<p>It contains the following information:</p>
<ul>
<li><a href="filtering.html#filter">filter</a></li>
<li><a href="filtering.html#input">input</a></li>
</ul>
<h3 id="filter-1"><a class="header" href="#filter-1">filter</a></h3>
<p>A filter is a <a href="sum-type.html">sum type</a> that can be one of the following:</p>
<ul>
<li>&quot;RelativePathIs&quot;</li>
<li>&quot;RelativePathIsNot&quot;</li>
<li>&quot;IRelativePathIs&quot;</li>
<li>&quot;IRelativePathIsNot&quot;</li>
<li>&quot;RelativePathDoesStartWith&quot;</li>
<li>&quot;RelativePathDoesNotStartWith&quot;</li>
<li>&quot;IRelativePathDoesStartWith&quot;</li>
<li>&quot;IRelativePathDoesNotStartWith&quot;</li>
<li>&quot;RelativePathDoesContain&quot;</li>
<li>&quot;RelativePathDoesNotContain&quot;</li>
<li>&quot;IRelativePathDoesContain&quot;</li>
<li>&quot;IRelativePathDoesNotContain&quot;</li>
<li>&quot;RelativePathDoesEndWith&quot;</li>
<li>&quot;RelativePathDoesNotEndWith&quot;</li>
<li>&quot;IRelativePathDoesEndWith&quot;</li>
<li>&quot;IRelativePathDoesNotEndWith&quot;</li>
<li>&quot;RelativePathDoesMatchRegex&quot;</li>
<li>&quot;RelativePathDoesNotMatchRegex&quot;</li>
<li>&quot;IRelativePathDoesMatchRegex&quot;</li>
<li>&quot;IRelativePathDoesNotMatchRegex&quot;</li>
<li>&quot;AbsolutePathIs&quot;</li>
<li>&quot;AbsolutePathIsNot&quot;</li>
<li>&quot;IAbsolutePathIs&quot;</li>
<li>&quot;IAbsolutePathIsNot&quot;</li>
<li>&quot;AbsolutePathDoesStartWith&quot;</li>
<li>&quot;AbsolutePathDoesNotStartWith&quot;</li>
<li>&quot;IAbsolutePathDoesStartWith&quot;</li>
<li>&quot;IAbsolutePathDoesNotStartWith&quot;</li>
<li>&quot;AbsolutePathDoesContain&quot;</li>
<li>&quot;AbsolutePathDoesNotContain&quot;</li>
<li>&quot;IAbsolutePathDoesContain&quot;</li>
<li>&quot;IAbsolutePathDoesNotContain&quot;</li>
<li>&quot;AbsolutePathDoesEndWith&quot;</li>
<li>&quot;AbsolutePathDoesNotEndWith&quot;</li>
<li>&quot;IAbsolutePathDoesEndWith&quot;</li>
<li>&quot;IAbsolutePathDoesNotEndWith&quot;</li>
<li>&quot;AbsolutePathDoesMatchRegex&quot;</li>
<li>&quot;AbsolutePathDoesNotMatchRegex&quot;</li>
<li>&quot;IAbsolutePathDoesMatchRegex&quot;</li>
<li>&quot;IAbsolutePathDoesNotMatchRegex&quot;</li>
</ul>
<h3 id="input"><a class="header" href="#input">input</a></h3>
<p>Type: string</p>
<p>The input for the condition.</p>
<h2 id="example-4"><a class="header" href="#example-4">Example:</a></h2>
<pre><code class="language-lua">ToggleNodeFilter = {
filter = &quot;RelativePathDoesNotStartWith&quot;,
input = &quot;.&quot;
}
</code></pre>
<p>Here, <code>ToggleNodeFilter</code> is a <a href="message.html">message</a> that adds or removes
(toggles) the filter applied.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="column-renderer"><a class="header" href="#column-renderer">Column Renderer</a></h1>
<p>A column renderer is a Lua function that receives a <a href="column-renderer.html#table-renderer-argument">special argument</a> and
returns a string that will be displayed in each specific field of the
<a href="layout.html#table">files table</a>.</p>
<h2 id="example-customizing-table-renderer"><a class="header" href="#example-customizing-table-renderer">Example: Customizing Table Renderer</a></h2>
<pre><code class="language-lua">xplr.fn.custom.fmt_simple_column = function(m)
return m.prefix .. m.relative_path .. m.suffix
end
xplr.config.general.table.header.cols = {
{ format = &quot; path&quot; }
}
xplr.config.general.table.row.cols = {
{ format = &quot;custom.fmt_simple_column&quot; }
}
xplr.config.general.table.col_widths = {
{ Percentage = 100 }
}
-- With this config, you should only see a single column displaying the
-- relative paths.
</code></pre>
<p>xplr by default provides the following column renderers:</p>
<ul>
<li><code>xplr.fn.builtin.fmt_general_table_row_cols_0</code></li>
<li><code>xplr.fn.builtin.fmt_general_table_row_cols_1</code></li>
<li><code>xplr.fn.builtin.fmt_general_table_row_cols_2</code></li>
<li><code>xplr.fn.builtin.fmt_general_table_row_cols_3</code></li>
<li><code>xplr.fn.builtin.fmt_general_table_row_cols_4</code></li>
</ul>
<p>You can either overwrite these functions, or create new functions in
<code>xplr.fn.custom</code> and point to them.</p>
<p>Terminal colors are supported.</p>
<h2 id="table-renderer-argument"><a class="header" href="#table-renderer-argument">Table Renderer Argument</a></h2>
<p>The special argument contains the following fields</p>
<ul>
<li><a href="column-renderer.html#parent">parent</a></li>
<li><a href="column-renderer.html#relative_path">relative_path</a></li>
<li><a href="column-renderer.html#absolute_path">absolute_path</a></li>
<li><a href="column-renderer.html#extension">extension</a></li>
<li><a href="column-renderer.html#is_symlink">is_symlink</a></li>
<li><a href="column-renderer.html#is_broken">is_broken</a></li>
<li><a href="column-renderer.html#is_dir">is_dir</a></li>
<li><a href="column-renderer.html#is_file">is_file</a></li>
<li><a href="column-renderer.html#is_readonly">is_readonly</a></li>
<li><a href="column-renderer.html#mime_essence">mime_essence</a></li>
<li><a href="column-renderer.html#size">size</a></li>
<li><a href="column-renderer.html#human_size">human_size</a></li>
<li><a href="column-renderer.html#permissions">permissions</a></li>
<li><a href="column-renderer.html#created">created</a></li>
<li><a href="column-renderer.html#last_modified">last_modified</a></li>
<li><a href="column-renderer.html#uid">uid</a></li>
<li><a href="column-renderer.html#gid">gid</a></li>
<li><a href="column-renderer.html#canonical">canonical</a></li>
<li><a href="column-renderer.html#symlink">symlink</a></li>
<li><a href="column-renderer.html#index">index</a></li>
<li><a href="column-renderer.html#relative_index">relative_index</a></li>
<li><a href="column-renderer.html#is_before_focus">is_before_focus</a></li>
<li><a href="column-renderer.html#is_after_focus">is_after_focus</a></li>
<li><a href="column-renderer.html#tree">tree</a></li>
<li><a href="column-renderer.html#prefix">prefix</a></li>
<li><a href="column-renderer.html#suffix">suffix</a></li>
<li><a href="column-renderer.html#is_selected">is_selected</a></li>
<li><a href="column-renderer.html#is_focused">is_focused</a></li>
<li><a href="column-renderer.html#total">total</a></li>
<li><a href="column-renderer.html#style">style</a></li>
<li><a href="column-renderer.html#meta">meta</a></li>
</ul>
<h3 id="parent"><a class="header" href="#parent">parent</a></h3>
<p>Type: string</p>
<p>The parent path of the node.</p>
<h3 id="relative_path"><a class="header" href="#relative_path">relative_path</a></h3>
<p>Type: string</p>
<p>The path relative to the parent, i.e. the file/directory name with extension.</p>
<h3 id="absolute_path"><a class="header" href="#absolute_path">absolute_path</a></h3>
<p>Type: string</p>
<p>The absolute path (without resolving symlinks) of the node.</p>
<h3 id="extension"><a class="header" href="#extension">extension</a></h3>
<p>Type: string</p>
<p>The extension of the node.</p>
<h3 id="is_symlink"><a class="header" href="#is_symlink">is_symlink</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is a symlink.</p>
<h3 id="is_broken"><a class="header" href="#is_broken">is_broken</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is a broken symlink.</p>
<h3 id="is_dir"><a class="header" href="#is_dir">is_dir</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is a directory.</p>
<h3 id="is_file"><a class="header" href="#is_file">is_file</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is a file.</p>
<h3 id="is_readonly"><a class="header" href="#is_readonly">is_readonly</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is real-only.</p>
<h3 id="mime_essence"><a class="header" href="#mime_essence">mime_essence</a></h3>
<p>Type: string</p>
<p>The mime type of the node. For e.g. <code>text/csv</code>, <code>image/jpeg</code> etc.</p>
<h3 id="size-1"><a class="header" href="#size-1">size</a></h3>
<p>Type: integer</p>
<p>The size of the exact node. The size of a directory won't be calculated
recursively.</p>
<h3 id="human_size"><a class="header" href="#human_size">human_size</a></h3>
<p>Type: string</p>
<p>Like <a href="column-renderer.html#size">size</a> but in human readable format.</p>
<h3 id="permissions"><a class="header" href="#permissions">permissions</a></h3>
<p>Type: <a href="column-renderer.html#permission">Permission</a></p>
<p>The <a href="column-renderer.html#permission">permissions</a> applied to the node.</p>
<h3 id="created"><a class="header" href="#created">created</a></h3>
<p>Type: nullable integer</p>
<p>Creation time in nanosecond since UNIX epoch.</p>
<h3 id="last_modified"><a class="header" href="#last_modified">last_modified</a></h3>
<p>Type: nullable integer</p>
<p>Last modification time in nanosecond since UNIX epoch.</p>
<h3 id="uid"><a class="header" href="#uid">uid</a></h3>
<p>Type: integer</p>
<p>User ID of the file owner.</p>
<h3 id="gid"><a class="header" href="#gid">gid</a></h3>
<p>Type: integer</p>
<p>Group ID of the file owner.</p>
<h3 id="canonical"><a class="header" href="#canonical">canonical</a></h3>
<p>Type: nullable <a href="column-renderer.html#resolved-node-metadata">Resolved Node Metadata</a></p>
<p>If the node is a symlink, it will hold information about the symlink resolved
node. Else, it will hold information the actual node. It the symlink is broken,
it will be null.</p>
<h3 id="symlink"><a class="header" href="#symlink">symlink</a></h3>
<p>Type: nullable <a href="column-renderer.html#resolved-node-metadata">Resolved Node Metadata</a></p>
<p>If the node is a symlink and is not broken, it will hold information about the
symlink resolved node. However, it will never hold information about the actual
node. It will instead be null.</p>
<h3 id="index"><a class="header" href="#index">index</a></h3>
<p>Type: integer</p>
<p>Index (starting from 0) of the node.</p>
<h3 id="relative_index"><a class="header" href="#relative_index">relative_index</a></h3>
<p>Type: integer</p>
<p>Relative index from the focused node (i.e. 0th node).</p>
<h3 id="is_before_focus"><a class="header" href="#is_before_focus">is_before_focus</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is before the focused node.</p>
<h3 id="is_after_focus"><a class="header" href="#is_after_focus">is_after_focus</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is after the focused node.</p>
<h3 id="tree"><a class="header" href="#tree">tree</a></h3>
<p>Type: string</p>
<p>The <a href="general-config.html#tabletree">tree component</a> based on the node's index.</p>
<h3 id="prefix"><a class="header" href="#prefix">prefix</a></h3>
<p>Type: string</p>
<p>The prefix applicable for the node.</p>
<h3 id="suffix"><a class="header" href="#suffix">suffix</a></h3>
<p>Type: string</p>
<p>The suffix applicable for the node.</p>
<h3 id="is_selected"><a class="header" href="#is_selected">is_selected</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is selected.</p>
<h3 id="is_focused"><a class="header" href="#is_focused">is_focused</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is under focus.</p>
<h3 id="total"><a class="header" href="#total">total</a></h3>
<p>Type: integer</p>
<p>The total number of the nodes.</p>
<h3 id="style-1"><a class="header" href="#style-1">style</a></h3>
<p>Type: <a href="style.html#style">Style</a></p>
<p>The applicable <a href="style.html#style">style object</a> for the node.</p>
<h3 id="meta-1"><a class="header" href="#meta-1">meta</a></h3>
<p>Type: mapping of string and string</p>
<p>The applicable <a href="node-type.html#meta">meta object</a> for the node.</p>
<h2 id="permission"><a class="header" href="#permission">Permission</a></h2>
<p>Permission contains the following fields:</p>
<ul>
<li>user_read</li>
<li>user_write</li>
<li>user_execute</li>
<li>group_read</li>
<li>group_write</li>
<li>group_execute</li>
<li>other_read</li>
<li>other_write</li>
<li>other_execute</li>
<li>sticky</li>
<li>setgid</li>
<li>setuid</li>
</ul>
<p>Each field holds a boolean value.</p>
<h2 id="resolved-node-metadata"><a class="header" href="#resolved-node-metadata">Resolved Node Metadata</a></h2>
<p>It contains the following fields.</p>
<ul>
<li><a href="column-renderer.html#absolute_path">absolute_path</a></li>
<li><a href="column-renderer.html#extension">extension</a></li>
<li><a href="column-renderer.html#is_dir">is_dir</a></li>
<li><a href="column-renderer.html#is_file">is_file</a></li>
<li><a href="column-renderer.html#is_readonly">is_readonly</a></li>
<li><a href="column-renderer.html#mime_essence">mime_essence</a></li>
<li><a href="column-renderer.html#size">size</a></li>
<li><a href="column-renderer.html#human_size">human_size</a></li>
<li><a href="column-renderer.html#created">created</a></li>
<li><a href="column-renderer.html#last_modified">last_modified</a></li>
<li><a href="column-renderer.html#uid">uid</a></li>
<li><a href="column-renderer.html#gid">gid</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="lua-function-calls"><a class="header" href="#lua-function-calls">Lua Function Calls</a></h1>
<p>xplr allows you to define lua functions using the <code>xplr.fn.custom</code> Lua API.</p>
<p>These functions can be called using messages like <code>CallLua</code>, <code>CallLuaSilently</code>.</p>
<p>When called the function receives a <a href="lua-function-calls.html#lua-context">special argument</a> that
contains some useful information. The function can optionally return a list of
messages which will be handled by xplr.</p>
<h2 id="example-using-lua-function-calls"><a class="header" href="#example-using-lua-function-calls">Example: Using Lua Function Calls</a></h2>
<pre><code class="language-lua">-- Define the function
xplr.fn.custom.ask_name_and_greet = function(app)
print(&quot;What's your name?&quot;)
local name = io.read()
local greeting = &quot;Hello &quot; .. name .. &quot;!&quot;
local message = greeting .. &quot; You are inside &quot; .. app.pwd
return {
{ LogSuccess = message },
}
end
-- Map the function to a key (space)
xplr.config.modes.builtin.default.key_bindings.on_key.space = {
help = &quot;ask name and greet&quot;,
messages = {
{ CallLua = &quot;custom.ask_name_and_greet&quot; }
}
}
-- Now, when you press &quot;space&quot; in default mode, you will be prompted for your
-- name. Enter your name to receive a nice greeting and to know your location.
</code></pre>
<p>Visit the <a href="xplr.util.html">xplr.util</a> API docs for some useful utility / helper functions
that you can use in your Lua function calls.</p>
<h2 id="lua-context"><a class="header" href="#lua-context">Lua Context</a></h2>
<p>This is a special argument passed to the lua functions when called using the
<code>CallLua</code>, <code>CallLuaSilently</code> messages.</p>
<p>It contains the following information:</p>
<ul>
<li><a href="lua-function-calls.html#version">version</a></li>
<li><a href="lua-function-calls.html#pwd">pwd</a></li>
<li><a href="lua-function-calls.html#initial_pwd">initial_pwd</a></li>
<li><a href="lua-function-calls.html#vroot">vroot</a></li>
<li><a href="lua-function-calls.html#focused_node">focused_node</a></li>
<li><a href="lua-function-calls.html#directory_buffer">directory_buffer</a></li>
<li><a href="lua-function-calls.html#selection">selection</a></li>
<li><a href="lua-function-calls.html#mode">mode</a></li>
<li><a href="lua-function-calls.html#layout">layout</a></li>
<li><a href="lua-function-calls.html#input_buffer">input_buffer</a></li>
<li><a href="lua-function-calls.html#pid">pid</a></li>
<li><a href="lua-function-calls.html#session_path">session_path</a></li>
<li><a href="lua-function-calls.html#explorer_config">explorer_config</a></li>
<li><a href="lua-function-calls.html#history">history</a></li>
<li><a href="lua-function-calls.html#last_modes">last_modes</a></li>
</ul>
<h3 id="version"><a class="header" href="#version">version</a></h3>
<p>Type: string</p>
<p>xplr version. Can be used to test compatibility.</p>
<h3 id="pwd"><a class="header" href="#pwd">pwd</a></h3>
<p>Type: string</p>
<p>The present working directory.</p>
<h3 id="initial_pwd"><a class="header" href="#initial_pwd">initial_pwd</a></h3>
<p>Type: string</p>
<p>The initial working directory when xplr started.</p>
<h3 id="vroot-1"><a class="header" href="#vroot-1">vroot</a></h3>
<p>Type: nullable string</p>
<p>The current virtual root.</p>
<h3 id="focused_node"><a class="header" href="#focused_node">focused_node</a></h3>
<p>Type: nullable <a href="lua-function-calls.html#node">Node</a></p>
<p>The node under focus.</p>
<h3 id="directory_buffer"><a class="header" href="#directory_buffer">directory_buffer</a></h3>
<p>Type: nullable <a href="lua-function-calls.html#directory-buffer">Directory Buffer</a></p>
<p>The directory buffer being rendered.</p>
<h3 id="selection-1"><a class="header" href="#selection-1">selection</a></h3>
<p>Type: list of selected <a href="lua-function-calls.html#node">Node</a>s</p>
<p>The selected nodes.</p>
<h3 id="mode-1"><a class="header" href="#mode-1">mode</a></h3>
<p>Type: <a href="modes.html#mode">Mode</a></p>
<p>Current mode.</p>
<h3 id="layout-2"><a class="header" href="#layout-2">layout</a></h3>
<p>Type: <a href="layouts.html">Layout</a></p>
<p>Current layout.</p>
<h3 id="input_buffer"><a class="header" href="#input_buffer">input_buffer</a></h3>
<p>Type: nullable string</p>
<p>The input buffer.</p>
<h3 id="pid"><a class="header" href="#pid">pid</a></h3>
<p>Type: integer</p>
<p>The xplr session PID.</p>
<h3 id="session_path"><a class="header" href="#session_path">session_path</a></h3>
<p>Type: string</p>
<p>The session path.</p>
<h3 id="explorer_config"><a class="header" href="#explorer_config">explorer_config</a></h3>
<p>Type: <a href="lua-function-calls.html#explorer-config">Explorer Config</a></p>
<p>The configuration for exploring paths.</p>
<h3 id="history"><a class="header" href="#history">history</a></h3>
<p>Type: <a href="lua-function-calls.html#history-1">History</a></p>
<h3 id="last_modes"><a class="header" href="#last_modes">last_modes</a></h3>
<p>Type: list of <a href="modes.html#mode">Mode</a></p>
<p>Last modes, not popped yet.</p>
<h2 id="node"><a class="header" href="#node">Node</a></h2>
<p>A node contains the following fields:</p>
<ul>
<li><a href="lua-function-calls.html#parent">parent</a></li>
<li><a href="lua-function-calls.html#relative_path">relative_path</a></li>
<li><a href="lua-function-calls.html#absolute_path">absolute_path</a></li>
<li><a href="lua-function-calls.html#extension">extension</a></li>
<li><a href="lua-function-calls.html#is_symlink">is_symlink</a></li>
<li><a href="lua-function-calls.html#is_broken">is_broken</a></li>
<li><a href="lua-function-calls.html#is_dir">is_dir</a></li>
<li><a href="lua-function-calls.html#is_file">is_file</a></li>
<li><a href="lua-function-calls.html#is_readonly">is_readonly</a></li>
<li><a href="lua-function-calls.html#mime_essence">mime_essence</a></li>
<li><a href="lua-function-calls.html#size">size</a></li>
<li><a href="lua-function-calls.html#human_size">human_size</a></li>
<li><a href="lua-function-calls.html#permissions">permissions</a></li>
<li><a href="lua-function-calls.html#created">created</a></li>
<li><a href="lua-function-calls.html#last_modified">last_modified</a></li>
<li><a href="lua-function-calls.html#uid">uid</a></li>
<li><a href="lua-function-calls.html#gid">gid</a></li>
<li><a href="lua-function-calls.html#canonical">canonical</a></li>
<li><a href="lua-function-calls.html#symlink">symlink</a></li>
</ul>
<h3 id="parent-1"><a class="header" href="#parent-1">parent</a></h3>
<p>Type: string</p>
<p>The parent path of the node.</p>
<h3 id="relative_path-1"><a class="header" href="#relative_path-1">relative_path</a></h3>
<p>Type: string</p>
<p>The path relative to the parent, i.e. the file/directory name with extension.</p>
<h3 id="absolute_path-1"><a class="header" href="#absolute_path-1">absolute_path</a></h3>
<p>Type: string</p>
<p>The absolute path (without resolving symlinks) of the node.</p>
<h3 id="extension-1"><a class="header" href="#extension-1">extension</a></h3>
<p>Type: string</p>
<p>The extension of the node.</p>
<h3 id="is_symlink-1"><a class="header" href="#is_symlink-1">is_symlink</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is a symlink.</p>
<h3 id="is_broken-1"><a class="header" href="#is_broken-1">is_broken</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is a broken symlink.</p>
<h3 id="is_dir-1"><a class="header" href="#is_dir-1">is_dir</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is a directory.</p>
<h3 id="is_file-1"><a class="header" href="#is_file-1">is_file</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is a file.</p>
<h3 id="is_readonly-1"><a class="header" href="#is_readonly-1">is_readonly</a></h3>
<p>Type: boolean</p>
<p><code>true</code> if the node is real-only.</p>
<h3 id="mime_essence-1"><a class="header" href="#mime_essence-1">mime_essence</a></h3>
<p>Type: string</p>
<p>The mime type of the node. For e.g. <code>text/csv</code>, <code>image/jpeg</code> etc.</p>
<h3 id="size-2"><a class="header" href="#size-2">size</a></h3>
<p>Type: integer</p>
<p>The size of the exact node. The size of a directory won't be calculated
recursively.</p>
<h3 id="human_size-1"><a class="header" href="#human_size-1">human_size</a></h3>
<p>Type: string</p>
<p>Like size but in human readable format.</p>
<h3 id="permissions-1"><a class="header" href="#permissions-1">permissions</a></h3>
<p>Type: <a href="column-renderer.html#permission">Permission</a></p>
<p>The <a href="column-renderer.html#permission">permissions</a> applied to the node.</p>
<h3 id="created-1"><a class="header" href="#created-1">created</a></h3>
<p>Type: nullable integer</p>
<p>Creation time in nanosecond since UNIX epoch.</p>
<h3 id="last_modified-1"><a class="header" href="#last_modified-1">last_modified</a></h3>
<p>Type: nullable integer</p>
<p>Last modification time in nanosecond since UNIX epoch.</p>
<h3 id="uid-1"><a class="header" href="#uid-1">uid</a></h3>
<p>Type: integer</p>
<p>User ID of the file owner.</p>
<h3 id="gid-1"><a class="header" href="#gid-1">gid</a></h3>
<p>Type: integer</p>
<p>Group ID of the file owner.</p>
<h3 id="canonical-1"><a class="header" href="#canonical-1">canonical</a></h3>
<p>Type: nullable <a href="column-renderer.html#resolved-node-metadata">Resolved Node Metadata</a></p>
<p>If the node is a symlink, it will hold information about the symlink resolved
node. Else, it will hold information the actual node. It the symlink is broken,
it will be null.</p>
<h3 id="symlink-1"><a class="header" href="#symlink-1">symlink</a></h3>
<p>Type: nullable <a href="column-renderer.html#resolved-node-metadata">Resolved Node Metadata</a></p>
<p>If the node is a symlink and is not broken, it will hold information about the
symlink resolved node. However, it will never hold information about the actual
node. It will instead be null.</p>
<h2 id="directory-buffer"><a class="header" href="#directory-buffer">Directory Buffer</a></h2>
<p>Directory buffer contains the following fields:</p>
<ul>
<li><a href="lua-function-calls.html#parent">parent</a></li>
<li><a href="lua-function-calls.html#nodes">nodes</a></li>
<li><a href="lua-function-calls.html#total">total</a></li>
<li><a href="lua-function-calls.html#focus">focus</a></li>
</ul>
<h3 id="parent-2"><a class="header" href="#parent-2">parent</a></h3>
<p>Type: string</p>
<p>The parent path of the node.</p>
<h3 id="nodes"><a class="header" href="#nodes">nodes</a></h3>
<p>Type: list of <a href="lua-function-calls.html#node">Node</a>s</p>
<p>A list of visible nodes.</p>
<h3 id="total-1"><a class="header" href="#total-1">total</a></h3>
<p>Type: int</p>
<p>The count of nodes being rendered.</p>
<h3 id="focus"><a class="header" href="#focus">focus</a></h3>
<p>Type: int</p>
<p>The index of the node under focus. It can be <code>0</code> even when there's no node to
focus on.</p>
<h2 id="history-1"><a class="header" href="#history-1">History</a></h2>
<p>History contains the following fields:</p>
<ul>
<li><a href="lua-function-calls.html#loc">loc</a></li>
<li><a href="lua-function-calls.html#paths">paths</a></li>
</ul>
<h3 id="loc"><a class="header" href="#loc">loc</a></h3>
<p>Type: int</p>
<p>Location of the current path in history.</p>
<h3 id="paths"><a class="header" href="#paths">paths</a></h3>
<p>Type: list of string</p>
<p>Visited paths.</p>
<h2 id="explorer-config"><a class="header" href="#explorer-config">Explorer Config</a></h2>
<p>Explorer config contains the following fields:</p>
<ul>
<li><a href="lua-function-calls.html#filters">filters</a></li>
<li><a href="lua-function-calls.html#sorters">sorters</a></li>
<li><a href="lua-function-calls.html#searcher">searcher</a></li>
</ul>
<h3 id="filters"><a class="header" href="#filters">filters</a></h3>
<p>List of filters to apply.</p>
<p>Type: list of <a href="filtering.html#node-filter-applicable">Node Filter Applicable</a></p>
<h3 id="sorters"><a class="header" href="#sorters">sorters</a></h3>
<p>Add list or sorters to the pipeline.</p>
<p>Type: list of <a href="sorting.html#node-sorter-applicable">Node Sorter Applicable</a></p>
<h3 id="searcher"><a class="header" href="#searcher">searcher</a></h3>
<p>The searcher to use (if any).</p>
<p>Type: nullable <a href="searching.html#node-searcher-applicable">Node Searcher Applicable</a></p>
<h2 id="also-see-6"><a class="header" href="#also-see-6">Also See:</a></h2>
<ul>
<li><a href="xplr.util.html">xplr.util</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h3 id="xplrutilversion"><a class="header" href="#xplrutilversion">xplr.util.version</a></h3>
<p>Get the xplr version details.</p>
<p>Type: function() -&gt; { major: number, minor: number, patch: number }</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.version()
-- { major = 0, minor = 0, patch = 0 }
</code></pre>
<h3 id="xplrutilclone"><a class="header" href="#xplrutilclone">xplr.util.clone</a></h3>
<p>Clone/deepcopy a Lua value. Doesn't work with functions.</p>
<p>Type: function( value ) -&gt; value</p>
<p>Example:</p>
<pre><code class="language-lua">local val = { foo = &quot;bar&quot; }
local val_clone = xplr.util.clone(val)
val.foo = &quot;baz&quot;
print(val_clone.foo)
-- &quot;bar&quot;
</code></pre>
<h3 id="xplrutilexists"><a class="header" href="#xplrutilexists">xplr.util.exists</a></h3>
<p>Check if the given path exists.</p>
<p>Type: function( path:string ) -&gt; boolean</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.exists(&quot;/foo/bar&quot;)
-- true
</code></pre>
<h3 id="xplrutilis_dir"><a class="header" href="#xplrutilis_dir">xplr.util.is_dir</a></h3>
<p>Check if the given path is a directory.</p>
<p>Type: function( path:string ) -&gt; boolean</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.is_dir(&quot;/foo/bar&quot;)
-- true
</code></pre>
<h3 id="xplrutilis_file"><a class="header" href="#xplrutilis_file">xplr.util.is_file</a></h3>
<p>Check if the given path is a file.</p>
<p>Type: function( path:string ) -&gt; boolean</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.is_file(&quot;/foo/bar&quot;)
-- true
</code></pre>
<h3 id="xplrutilis_symlink"><a class="header" href="#xplrutilis_symlink">xplr.util.is_symlink</a></h3>
<p>Check if the given path is a symlink.</p>
<p>Type: function( path:string ) -&gt; boolean</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.is_file(&quot;/foo/bar&quot;)
-- true
</code></pre>
<h3 id="xplrutilis_absolute"><a class="header" href="#xplrutilis_absolute">xplr.util.is_absolute</a></h3>
<p>Check if the given path is an absolute path.</p>
<p>Type: function( path:string ) -&gt; boolean</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.is_absolute(&quot;/foo/bar&quot;)
-- true
</code></pre>
<h3 id="xplrutilpath_split"><a class="header" href="#xplrutilpath_split">xplr.util.path_split</a></h3>
<p>Split a path into its components.</p>
<p>Type: function( path:string ) -&gt; boolean</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.path_split(&quot;/foo/bar&quot;)
-- { &quot;/&quot;, &quot;foo&quot;, &quot;bar&quot; }
xplr.util.path_split(&quot;.././foo&quot;)
-- { &quot;..&quot;, &quot;foo&quot; }
</code></pre>
<h3 id="xplrutilnode"><a class="header" href="#xplrutilnode">xplr.util.node</a></h3>
<p>Get <a href="https://xplr.dev/en/lua-function-calls#node">Node</a> information of a given path.
Doesn't check if the path exists.
Returns nil if the path is &quot;/&quot;.
Errors out if absolute path can't be obtained.</p>
<p>Type: function( path:string ) -&gt; <a href="https://xplr.dev/en/lua-function-calls#node">Node</a>|nil</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.node(&quot;./bar&quot;)
-- { parent = &quot;/pwd&quot;, relative_path = &quot;bar&quot;, absolute_path = &quot;/pwd/bar&quot;, ... }
xplr.util.node(&quot;/&quot;)
-- nil
</code></pre>
<h3 id="xplrutilnode_type"><a class="header" href="#xplrutilnode_type">xplr.util.node_type</a></h3>
<p>Get the configured <a href="https://xplr.dev/en/node-type">Node Type</a> of a given <a href="https://xplr.dev/en/lua-function-calls#node">Node</a>.</p>
<p>Type: function( <a href="https://xplr.dev/en/lua-function-calls#node">Node</a>, <a href="https://xplr.dev/en/node_types">xplr.config.node_types</a>|nil ) -&gt; <a href="https://xplr.dev/en/node-type">Node Type</a></p>
<p>If the second argument is missing, global config <code>xplr.config.node_types</code>
will be used.</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.node_type(app.focused_node)
-- { style = { fg = &quot;Red&quot;, ... }, meta = { icon = &quot;&quot;, ... } ... }
xplr.util.node_type(xplr.util.node(&quot;/foo/bar&quot;), xplr.config.node_types)
-- { style = { fg = &quot;Red&quot;, ... }, meta = { icon = &quot;&quot;, ... } ... }
</code></pre>
<h3 id="xplrutildirname"><a class="header" href="#xplrutildirname">xplr.util.dirname</a></h3>
<p>Get the directory name of a given path.</p>
<p>Type: function( path:string ) -&gt; path:string|nil</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.dirname(&quot;/foo/bar&quot;)
-- &quot;/foo&quot;
</code></pre>
<h3 id="xplrutilbasename"><a class="header" href="#xplrutilbasename">xplr.util.basename</a></h3>
<p>Get the base name of a given path.</p>
<p>Type: function( path:string ) -&gt; path:string|nil</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.basename(&quot;/foo/bar&quot;)
-- &quot;bar&quot;
</code></pre>
<h3 id="xplrutilabsolute"><a class="header" href="#xplrutilabsolute">xplr.util.absolute</a></h3>
<p>Get the absolute path of the given path by prepending $PWD.
It doesn't check if the path exists.</p>
<p>Type: function( path:string ) -&gt; path:string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.absolute(&quot;foo/bar&quot;)
-- &quot;/tmp/foo/bar&quot;
</code></pre>
<h3 id="xplrutilrelative_to"><a class="header" href="#xplrutilrelative_to">xplr.util.relative_to</a></h3>
<p>Get the relative path based on the given base path or current working dir.
Will error if it fails to determine a relative path.</p>
<p>Type: function( path:string, options:table|nil ) -&gt; path:string</p>
<p>Options type: { base:string|nil, with_prefix_dots:bookean|nil, without_suffix_dots:boolean|nil }</p>
<ul>
<li>If <code>base</code> path is given, the path will be relative to it.</li>
<li>If <code>with_prefix_dots</code> is true, the path will always start with dots <code>..</code> / <code>.</code></li>
<li>If <code>without_suffix_dots</code> is true, the name will be visible instead of dots <code>..</code> / <code>.</code></li>
</ul>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.relative_to(&quot;/present/working/directory&quot;)
-- &quot;.&quot;
xplr.util.relative_to(&quot;/present/working/directory/foo&quot;)
-- &quot;foo&quot;
xplr.util.relative_to(&quot;/present/working/directory/foo&quot;, { with_prefix_dots = true })
-- &quot;./foo&quot;
xplr.util.relative_to(&quot;/present/working/directory&quot;, { without_suffix_dots = true })
-- &quot;../directory&quot;
xplr.util.relative_to(&quot;/present/working&quot;)
-- &quot;..&quot;
xplr.util.relative_to(&quot;/present/working&quot;, { without_suffix_dots = true })
-- &quot;../../working&quot;
xplr.util.relative_to(&quot;/present/working/directory&quot;, { base = &quot;/present/foo/bar&quot; })
-- &quot;../../working/directory&quot;
</code></pre>
<h3 id="xplrutilshorten"><a class="header" href="#xplrutilshorten">xplr.util.shorten</a></h3>
<p>Shorten the given absolute path using the following rules:</p>
<ul>
<li>either relative to your home dir if it makes sense</li>
<li>or relative to the current working directory</li>
<li>or absolute path if it makes the most sense</li>
</ul>
<p>Type: Similar to <code>xplr.util.relative_to</code></p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.shorten(&quot;/home/username/.config&quot;)
-- &quot;~/.config&quot;
xplr.util.shorten(&quot;/present/working/directory&quot;)
-- &quot;.&quot;
xplr.util.shorten(&quot;/present/working/directory/foo&quot;)
-- &quot;foo&quot;
xplr.util.shorten(&quot;/present/working/directory/foo&quot;, { with_prefix_dots = true })
-- &quot;./foo&quot;
xplr.util.shorten(&quot;/present/working/directory&quot;, { without_suffix_dots = true })
-- &quot;../directory&quot;
xplr.util.shorten(&quot;/present/working/directory&quot;, { base = &quot;/present/foo/bar&quot; })
-- &quot;../../working/directory&quot;
xplr.util.shorten(&quot;/tmp&quot;)
-- &quot;/tmp&quot;
</code></pre>
<h3 id="xplrutilexplore"><a class="header" href="#xplrutilexplore">xplr.util.explore</a></h3>
<p>Explore directories with the given explorer config.</p>
<p>Type: function( path:string, <a href="https://xplr.dev/en/lua-function-calls#explorer-config">ExplorerConfig</a>|nil ) -&gt; { <a href="https://xplr.dev/en/lua-function-calls#node">Node</a>, ... }</p>
<p>Example:</p>
<pre><code class="language-lua">
xplr.util.explore(&quot;/tmp&quot;)
-- { { absolute_path = &quot;/tmp/a&quot;, ... }, ... }
xplr.util.explore(&quot;/tmp&quot;, app.explorer_config)
-- { { absolute_path = &quot;/tmp/a&quot;, ... }, ... }
</code></pre>
<h3 id="xplrutilshell_execute"><a class="header" href="#xplrutilshell_execute">xplr.util.shell_execute</a></h3>
<p>Execute shell commands safely.</p>
<p>Type: function( program:string, args:{ string, ... }|nil ) -&gt; { stdout = string, stderr = string, returncode = number|nil }</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.shell_execute(&quot;pwd&quot;)
-- { stdout = &quot;/present/working/directory&quot;, stderr = &quot;&quot;, returncode = 0 }
xplr.util.shell_execute(&quot;bash&quot;, {&quot;-c&quot;, &quot;xplr --help&quot;})
-- { stdout = &quot;xplr...&quot;, stderr = &quot;&quot;, returncode = 0 }
</code></pre>
<h3 id="xplrutilshell_quote"><a class="header" href="#xplrutilshell_quote">xplr.util.shell_quote</a></h3>
<p>Quote commands and paths safely.</p>
<p>Type: function( string ) -&gt; string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.shell_quote(&quot;a'b\&quot;c&quot;)
-- 'a'&quot;'&quot;'b&quot;c'
</code></pre>
<h3 id="xplrutilshell_escape"><a class="header" href="#xplrutilshell_escape">xplr.util.shell_escape</a></h3>
<p>Escape commands and paths safely.</p>
<p>Type: function( string ) -&gt; string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.shell_escape(&quot;a'b\&quot;c&quot;)
-- &quot;\&quot;a'b\\\&quot;c\&quot;&quot;
</code></pre>
<h3 id="xplrutilfrom_json"><a class="header" href="#xplrutilfrom_json">xplr.util.from_json</a></h3>
<p>Load JSON string into Lua value.</p>
<p>Type: function( string ) -&gt; any</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.from_json([[{&quot;foo&quot;: &quot;bar&quot;}]])
-- { foo = &quot;bar&quot; }
</code></pre>
<h3 id="xplrutilto_json"><a class="header" href="#xplrutilto_json">xplr.util.to_json</a></h3>
<p>Dump Lua value into JSON (i.e. also YAML) string.</p>
<p>Type: function( value ) -&gt; string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.to_json({ foo = &quot;bar&quot; })
-- [[{ &quot;foo&quot;: &quot;bar&quot; }]]
xplr.util.to_json({ foo = &quot;bar&quot; }, { pretty = true })
-- [[{
-- &quot;foo&quot;: &quot;bar&quot;
-- }]]
</code></pre>
<h3 id="xplrutilfrom_yaml"><a class="header" href="#xplrutilfrom_yaml">xplr.util.from_yaml</a></h3>
<p>Load YAML (i.e. also JSON) string into Lua value.</p>
<p>Type: function( string ) -&gt; value</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.from_yaml([[{foo: bar}]])
-- { foo = &quot;bar&quot; }
</code></pre>
<h3 id="xplrutilto_yaml"><a class="header" href="#xplrutilto_yaml">xplr.util.to_yaml</a></h3>
<p>Dump Lua value into YAML string.</p>
<p>Type: function( value ) -&gt; string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.to_yaml({ foo = &quot;bar&quot; })
-- &quot;foo: bar&quot;
</code></pre>
<h3 id="xplrutillscolor"><a class="header" href="#xplrutillscolor">xplr.util.lscolor</a></h3>
<p>Get a <a href="https://xplr.dev/en/style">Style</a> object for the given path based on the LS_COLORS
environment variable.</p>
<p>Type: function( path:string ) -&gt; <a href="https://xplr.dev/en/style">Style</a>|nil</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.lscolor(&quot;Desktop&quot;)
-- { fg = &quot;Red&quot;, bg = nil, add_modifiers = {}, sub_modifiers = {} }
</code></pre>
<h3 id="xplrutilpaint"><a class="header" href="#xplrutilpaint">xplr.util.paint</a></h3>
<p>Apply style (escape sequence) to string using a given <a href="https://xplr.dev/en/style">Style</a> object.</p>
<p>Type: function( string, <a href="https://xplr.dev/en/style">Style</a>|nil ) -&gt; string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.paint(&quot;Desktop&quot;, { fg = &quot;Red&quot;, bg = nil, add_modifiers = {}, sub_modifiers = {} })
-- &quot;\u001b[31mDesktop\u001b[0m&quot;
</code></pre>
<h3 id="xplrutilstyle_mix"><a class="header" href="#xplrutilstyle_mix">xplr.util.style_mix</a></h3>
<p>Mix multiple <a href="https://xplr.dev/en/style">Style</a> objects into one.</p>
<p>Type: function( { <a href="https://xplr.dev/en/style">Style</a>, <a href="https://xplr.dev/en/style">Style</a>, ... } ) -&gt; <a href="https://xplr.dev/en/style">Style</a></p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.style_mix({{ fg = &quot;Red&quot; }, { bg = &quot;Blue&quot; }, { add_modifiers = {&quot;Bold&quot;} }})
-- { fg = &quot;Red&quot;, bg = &quot;Blue&quot;, add_modifiers = { &quot;Bold&quot; }, sub_modifiers = {} }
</code></pre>
<h3 id="xplrutiltextwrap"><a class="header" href="#xplrutiltextwrap">xplr.util.textwrap</a></h3>
<p>Wrap the given text to fit the specified width.
It will try to not split words when possible.</p>
<p>Type: function( string, options:number|table ) -&gt; { string, ...}</p>
<p>Options type: { width = number, initial_indent = string|nil, subsequent_indent = string|nil, break_words = boolean|nil }</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.textwrap(&quot;this will be cut off&quot;, 11)
-- { &quot;this will', 'be cut off&quot; }
xplr.util.textwrap(
&quot;this will be cut off&quot;,
{ width = 12, initial_indent = &quot;&quot;, subsequent_indent = &quot; &quot;, break_words = false }
)
-- { &quot;this will be&quot;, &quot; cut off&quot; }
</code></pre>
<h3 id="xplrutillayout_replace"><a class="header" href="#xplrutillayout_replace">xplr.util.layout_replace</a></h3>
<p>Find the target layout in the given layout and replace it with the replacement layout,
returning a new layout.</p>
<p>Type: function( layout:<a href="https://xplr.dev/en/layout">Layout</a>, target:<a href="https://xplr.dev/en/layout">Layout</a>, replacement:<a href="https://xplr.dev/en/layout">Layout</a> ) -&gt; layout:<a href="https://xplr.dev/en/layout">Layout</a></p>
<p>Example:</p>
<pre><code class="language-lua">local layout = {
Horizontal = {
splits = {
&quot;Table&quot;, -- Target
&quot;HelpMenu&quot;,
},
config = ...,
}
}
xplr.util.layout_replace(layout, &quot;Table&quot;, &quot;Selection&quot;)
-- {
-- Horizontal = {
-- splits = {
-- &quot;Selection&quot;, -- Replacement
-- &quot;HelpMenu&quot;,
-- },
-- config = ...
-- }
-- }
</code></pre>
<h3 id="xplrutilpermissions_rwx"><a class="header" href="#xplrutilpermissions_rwx">xplr.util.permissions_rwx</a></h3>
<p>Convert <a href="https://xplr.dev/en/column-renderer#permission">Permission</a> to rwxrwxrwx representation with special bits.</p>
<p>Type: function( <a href="https://xplr.dev/en/column-renderer#permission">Permission</a> ) -&gt; string</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.permissions_rwx({ user_read = true })
-- &quot;r--------&quot;
xplr.util.permissions_rwx(app.focused_node.permission)
-- &quot;rwxrwsrwT&quot;
</code></pre>
<h3 id="xplrutilpermissions_octal"><a class="header" href="#xplrutilpermissions_octal">xplr.util.permissions_octal</a></h3>
<p>Convert <a href="https://xplr.dev/en/column-renderer#permission">Permission</a> to octal representation.</p>
<p>Type: function( <a href="https://xplr.dev/en/column-renderer#permission">Permission</a> ) -&gt; { number, number, number, number }</p>
<p>Example:</p>
<pre><code class="language-lua">xplr.util.permissions_octal({ user_read = true })
-- { 0, 4, 0, 0 }
xplr.util.permissions_octal(app.focused_node.permission)
-- { 0, 7, 5, 4 }
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="environment-variables-and-pipes"><a class="header" href="#environment-variables-and-pipes">Environment Variables and Pipes</a></h1>
<p>Alternative to <code>CallLua</code>, <code>CallLuaSilently</code> messages that call Lua functions,
there are <code>Call0</code>, <code>CallSilently0</code>, <code>BashExec0</code>, <code>BashExecSilently0</code> messages
that call shell commands.</p>
<h3 id="example-simple-file-opener-using-xdg-open-and-xplr_focus_path"><a class="header" href="#example-simple-file-opener-using-xdg-open-and-xplr_focus_path">Example: Simple file opener using xdg-open and $XPLR_FOCUS_PATH</a></h3>
<pre><code class="language-lua">xplr.config.modes.builtin.default.key_bindings.on_key[&quot;X&quot;] = {
help = &quot;open&quot;,
messages = {
{
BashExecSilently0 = [===[
xdg-open &quot;${XPLR_FOCUS_PATH:?}&quot;
]===],
},
},
}
</code></pre>
<p>However, unlike the Lua functions, these shell commands have to read the useful
information and send messages via environment variables and temporary files
called &quot;pipe&quot;s. These environment variables and files are only available when
a command is being executed.</p>
<h3 id="example-using-environment-variables-and-pipes"><a class="header" href="#example-using-environment-variables-and-pipes">Example: Using Environment Variables and Pipes</a></h3>
<pre><code class="language-lua">xplr.config.modes.builtin.default.key_bindings.on_key[&quot;space&quot;] = {
help = &quot;ask name and greet&quot;,
messages = {
{
BashExec0 = [===[
echo &quot;What's your name?&quot;
read name
greeting=&quot;Hello $name!&quot;
message=&quot;$greeting You are inside $PWD&quot;
&quot;$XPLR&quot; -m 'LogSuccess: %q' &quot;$message&quot;
]===]
}
}
}
-- Now, when you press &quot;space&quot; in default mode, you will be prompted for your
-- name. Enter your name to receive a nice greeting and to know your location.
</code></pre>
<p>Visit the <a href="configure-key-bindings.html#tutorial-adding-a-new-mode"><strong>fzf integration tutorial</strong></a> for another example.</p>
<p>To see the environment variables and pipes, invoke the shell by typing <code>:!</code> in default
mode and run the following command:</p>
<pre><code>env | grep ^XPLR
</code></pre>
<p>You will see something like:</p>
<pre><code>XPLR=xplr
XPLR_FOCUS_INDEX=0
XPLR_MODE=action to
XPLR_PIPE_SELECTION_OUT=/run/user/1000/xplr/session/122278/pipe/selection_out
XPLR_INPUT_BUFFER=
XPLR_PIPE_GLOBAL_HELP_MENU_OUT=/run/user/1000/xplr/session/122278/pipe/global_help_menu_out
XPLR_PID=122278
XPLR_PIPE_MSG_IN=/run/user/1000/xplr/session/122278/pipe/msg_in
XPLR_PIPE_LOGS_OUT=/run/user/1000/xplr/session/122278/pipe/logs_out
XPLR_PIPE_RESULT_OUT=/run/user/1000/xplr/session/122278/pipe/result_out
XPLR_PIPE_HISTORY_OUT=/run/user/1000/xplr/session/122278/pipe/history_out
XPLR_FOCUS_PATH=/home/sayanarijit/Documents/GitHub/xplr/docs/en/book
XPLR_SESSION_PATH=/run/user/1000/xplr/session/122278
XPLR_APP_VERSION=0.14.3
XPLR_PIPE_DIRECTORY_NODES_OUT=/run/user/1000/xplr/session/122278/pipe/directory_nodes_out
</code></pre>
<p>The environment variables starting with <code>XPLR_PIPE_</code> are the temporary files
called <a href="environment-variables-and-pipes.html#pipes">&quot;pipe&quot;s</a>.</p>
<p>The other variables are single-line variables containing simple information:</p>
<ul>
<li><a href="environment-variables-and-pipes.html#xplr">XPLR</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_app_version">XPLR_APP_VERSION</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_focus_index">XPLR_FOCUS_INDEX</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_focus_path">XPLR_FOCUS_PATH</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_input_buffer">XPLR_INPUT_BUFFER</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_initial_pwd">XPLR_INITIAL_PWD</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_mode">XPLR_MODE</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_pid">XPLR_PID</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_session_path">XPLR_SESSION_PATH</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_vroot">XPLR_VROOT</a></li>
</ul>
<h3 id="environment-variables"><a class="header" href="#environment-variables">Environment variables</a></h3>
<h4 id="xplr"><a class="header" href="#xplr">XPLR</a></h4>
<p>The binary path of xplr command.</p>
<h4 id="xplr_app_version"><a class="header" href="#xplr_app_version">XPLR_APP_VERSION</a></h4>
<p>Self-explanatory.</p>
<h4 id="xplr_focus_index"><a class="header" href="#xplr_focus_index">XPLR_FOCUS_INDEX</a></h4>
<p>Contains the index of the currently focused item, as seen in
<a href="column-renderer.html#index">column-renderer/index</a>.</p>
<h4 id="xplr_focus_path"><a class="header" href="#xplr_focus_path">XPLR_FOCUS_PATH</a></h4>
<p>Contains the full path of the currently focused node.</p>
<h4 id="xplr_initial_pwd"><a class="header" href="#xplr_initial_pwd">XPLR_INITIAL_PWD</a></h4>
<p>The $PWD then xplr started.</p>
<h4 id="xplr_input_buffer"><a class="header" href="#xplr_input_buffer">XPLR_INPUT_BUFFER</a></h4>
<p>The line currently in displaying in the xplr input buffer. For e.g. the search
input while searching. See <a href="messages.html#reading-input">Reading Input</a>.</p>
<h4 id="xplr_mode"><a class="header" href="#xplr_mode">XPLR_MODE</a></h4>
<p>Contains the mode xplr is currently in, see <a href="modes.html#modes">modes</a>.</p>
<h4 id="xplr_pid"><a class="header" href="#xplr_pid">XPLR_PID</a></h4>
<p>Contains the process ID of the current xplr process.</p>
<h4 id="xplr_session_path"><a class="header" href="#xplr_session_path">XPLR_SESSION_PATH</a></h4>
<p>Contains the current session path, like /tmp/runtime-&quot;$USER&quot;/xplr/session/&quot;$XPLR_PID&quot;/,
you can find temporary files here, such as pipes.</p>
<h4 id="xplr_vroot"><a class="header" href="#xplr_vroot">XPLR_VROOT</a></h4>
<p>Contains the path of current virtual root, is set.</p>
<h3 id="pipes"><a class="header" href="#pipes">Pipes</a></h3>
<h4 id="input-pipe"><a class="header" href="#input-pipe">Input pipe</a></h4>
<p>Currently there is only one input pipe.</p>
<ul>
<li><a href="environment-variables-and-pipes.html#xplr_pipe_msg_in">XPLR_PIPE_MSG_IN</a></li>
</ul>
<h4 id="output-pipes"><a class="header" href="#output-pipes">Output pipes</a></h4>
<p><code>XPLR_PIPE_*_OUT</code> are the output pipes that contain data which cannot be
exposed directly via environment variables, like multi-line strings.
These pipes can be accessed as plain text files located in $XPLR_SESSION_PATH.</p>
<p>Depending on the message (e.g. <code>Call</code> or <code>Call0</code>), each line will be separated
by newline or null character (<code>\n</code> or <code>\0</code>).</p>
<ul>
<li><a href="environment-variables-and-pipes.html#xplr_pipe_selection_out">XPLR_PIPE_SELECTION_OUT</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_pipe_global_help_menu_out">XPLR_PIPE_GLOBAL_HELP_MENU_OUT</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_pipe_logs_out">XPLR_PIPE_LOGS_OUT</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_pipe_result_out">XPLR_PIPE_RESULT_OUT</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_pipe_history_out">XPLR_PIPE_HISTORY_OUT</a></li>
<li><a href="environment-variables-and-pipes.html#xplr_pipe_directory_nodes_out">XPLR_PIPE_DIRECTORY_NODES_OUT</a></li>
</ul>
<h4 id="xplr_pipe_msg_in"><a class="header" href="#xplr_pipe_msg_in">XPLR_PIPE_MSG_IN</a></h4>
<p>Append new messages to this pipe in <a href="https://www.yaml.org">YAML</a> (or <a href="https://www.json.org">JSON</a>) syntax. These
messages will be read and handled by xplr after the command execution.</p>
<p>Depending on the message (e.g. <code>Call</code> or <code>Call0</code>) you need to separate each
message using newline or null character (<code>\n</code> or <code>\0</code>).</p>
<blockquote>
<p><strong><em>NOTE:</em></strong> Since version <code>v0.20.0</code>, it's recommended to avoid writing
directly to this file, as safely escaping YAML strings is a lot of work. Use
<code>xplr -m</code> / <code>xplr --pipe-msg-in</code> to pass messages to xplr in a safer way.</p>
<p>It uses <a href="https://github.com/sayanarijit/jf">jf</a> syntax to safely convert an YAML template into a valid message.</p>
<p>Example: <code>&quot;$XPLR&quot; -m 'ChangeDirectory: %q' &quot;${HOME:?}&quot;</code></p>
</blockquote>
<h4 id="xplr_pipe_selection_out"><a class="header" href="#xplr_pipe_selection_out">XPLR_PIPE_SELECTION_OUT</a></h4>
<p>List of selected paths.</p>
<h4 id="xplr_pipe_global_help_menu_out"><a class="header" href="#xplr_pipe_global_help_menu_out">XPLR_PIPE_GLOBAL_HELP_MENU_OUT</a></h4>
<p>The full help menu.</p>
<h4 id="xplr_pipe_logs_out"><a class="header" href="#xplr_pipe_logs_out">XPLR_PIPE_LOGS_OUT</a></h4>
<p>List of logs.</p>
<h4 id="xplr_pipe_result_out"><a class="header" href="#xplr_pipe_result_out">XPLR_PIPE_RESULT_OUT</a></h4>
<p>Result (selected paths if any, else the focused path)</p>
<h4 id="xplr_pipe_history_out"><a class="header" href="#xplr_pipe_history_out">XPLR_PIPE_HISTORY_OUT</a></h4>
<p>List of last visited paths (similar to jump list in vim).</p>
<h4 id="xplr_pipe_directory_nodes_out"><a class="header" href="#xplr_pipe_directory_nodes_out">XPLR_PIPE_DIRECTORY_NODES_OUT</a></h4>
<p>List of paths, filtered and sorted as displayed in the <a href="layout.html#table">files table</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="awesome-hacks"><a class="header" href="#awesome-hacks">Awesome Hacks</a></h1>
<p>Here's a list of cool xplr hacks, i.e. snippets of code that you can just copy
and paste into your <a href="configuration.html">configuration</a> or the appropriate file, that are
too small or too niche for a full fledge <a href="plugin.html">plugin</a>.</p>
<p>Do you have something cool to share?</p>
<p><a href="https://github.com/sayanarijit/xplr/edit/main/docs/en/src/awesome-hacks.md">Edit this file</a> or <a href="https://github.com/sayanarijit/xplr/discussions/categories/show-and-tell">share them here</a> or <a href="community.html">let us know</a>.</p>
<p>You can try these hacks by writing them to a file, say <code>hack.lua</code> and passing
it to xplr with <code>--extra-config</code> or <code>-C</code>.</p>
<pre><code class="language-bash">xplr -C hack.lua
</code></pre>
<h3 id="cd-on-quit"><a class="header" href="#cd-on-quit">cd on quit</a></h3>
<p>Change directory using xplr.</p>
<details>
<summary>Expand for details</summary>
<ul>
<li>Author: <a href="https://github.com/sayanarijit">@sayanarijit</a></li>
<li>Tested on: Linux</li>
</ul>
<p>NOTE: This is a shell hack, rather than Lua config hack. Add this in
<code>.bashrc</code> or <code>.profile</code> file in your home directory.</p>
<p>With this alias set, you can navigate directories using xplr by entering
xcd command, and when you quit by pressing enter, you will enter the
directory.</p>
<p>You can of course, quit with plain Quit (i.e. by pressing q) to
gracefully cancel &quot;cd on quit&quot;.</p>
<pre><code class="language-bash">alias xcd='cd &quot;$(xplr --print-pwd-as-result)&quot;'
</code></pre>
</details>
<h3 id="spawn-multiple-sessions-in-different-tabs-iterm2"><a class="header" href="#spawn-multiple-sessions-in-different-tabs-iterm2">Spawn multiple sessions in different tabs (iTerm2)</a></h3>
<p>Creating a new session that starts with iTerm2.</p>
<details>
<summary>Expand for details</summary>
<ul>
<li>Author: <a href="https://github.com/lmburns">@lmburns</a></li>
<li>Requires: iTerm2</li>
<li>Tested on: MacOS</li>
</ul>
<pre><code class="language-lua">xplr.config.modes.builtin.default.key_bindings.on_key[&quot;ctrl-n&quot;] = {
help = &quot;new session&quot;,
messages = {
{ BashExecSilently = [[
osascript &lt;&lt;EOF
tell application &quot;iTerm2&quot;
tell current window
create tab with default profile
tell current session to write text &quot;xplr&quot;
end tell
end tell
]]
},
},
}
</code></pre>
</details>
<h3 id="bookmark"><a class="header" href="#bookmark">Bookmark</a></h3>
<p>Bookmark files using <code>m</code> and fuzzy search bookmarks using backtick.</p>
<details>
<summary>Expand for details</summary>
<p><a href="https://gifyu.com/image/rGSR"><img src="https://s4.gifyu.com/images/xplr-bookmark.gif" alt="xplr-bookmark.gif" /></a></p>
<ul>
<li>Author: <a href="https://github.com/sayanarijit">@sayanarijit</a></li>
<li>Requires: fzf</li>
<li>Tested on: Linux</li>
</ul>
<pre><code class="language-lua">xplr.config.modes.builtin.default.key_bindings.on_key.m = {
help = &quot;bookmark&quot;,
messages = {
{
BashExecSilently0 = [===[
PTH=&quot;${XPLR_FOCUS_PATH:?}&quot;
PTH_ESC=$(printf %q &quot;$PTH&quot;)
if echo &quot;${PTH:?}&quot; &gt;&gt; &quot;${XPLR_SESSION_PATH:?}/bookmarks&quot;; then
&quot;$XPLR&quot; -m 'LogSuccess: %q' &quot;$PTH_ESC added to bookmarks&quot;
else
&quot;$XPLR&quot; -m 'LogError: %q' &quot;Failed to bookmark $PTH_ESC&quot;
fi
]===],
},
},
}
xplr.config.modes.builtin.default.key_bindings.on_key[&quot;`&quot;] = {
help = &quot;go to bookmark&quot;,
messages = {
{
BashExec0 = [===[
PTH=$(cat &quot;${XPLR_SESSION_PATH:?}/bookmarks&quot; | fzf --no-sort)
PTH_ESC=$(printf %q &quot;$PTH&quot;)
if [ &quot;$PTH&quot; ]; then
&quot;$XPLR&quot; -m 'FocusPath: %q' &quot;$PTH&quot;
fi
]===],
},
},
}
</code></pre>
</details>
<h3 id="persistent-multi-session-bookmark"><a class="header" href="#persistent-multi-session-bookmark">Persistent, multi-session bookmark</a></h3>
<p>A bookmark mode that allows for a bookmark file to be used throughout multiples
sessions. It is set to the environment variable <code>$XPLR_BOOKMARK_FILE</code>. A
bookmark can be added, deleted, or jumped to.</p>
<details>
<summary>Expand for details</summary>
<ul>
<li>Author: <a href="https://github.com/lmburns">@lmburns</a></li>
<li>Requires: fzf, sd</li>
<li>Tested on: MacOS</li>
</ul>
<pre><code class="language-lua">-- With `export XPLR_BOOKMARK_FILE=&quot;$HOME/bookmarks&quot;`
-- Bookmark: mode binding
xplr.config.modes.builtin.default.key_bindings.on_key[&quot;b&quot;] = {
help = &quot;bookmark mode&quot;,
messages = {
{ SwitchModeCustom = &quot;bookmark&quot; },
},
}
xplr.config.modes.custom.bookmark = {
name = &quot;bookmark&quot;,
key_bindings = {
on_key = {
m = {
help = &quot;bookmark dir&quot;,
messages = {
{
BashExecSilently0 = [[
PTH=&quot;${XPLR_FOCUS_PATH:?}&quot;
if [ -d &quot;${PTH}&quot; ]; then
PTH=&quot;${PTH}&quot;
elif [ -f &quot;${PTH}&quot; ]; then
PTH=$(dirname &quot;${PTH}&quot;)
fi
PTH_ESC=$(printf %q &quot;$PTH&quot;)
if echo &quot;${PTH:?}&quot; &gt;&gt; &quot;${XPLR_BOOKMARK_FILE:?}&quot;; then
&quot;$XPLR&quot; -m 'LogSuccess: %q' &quot;$PTH_ESC added to bookmarks&quot;
else
&quot;$XPLR&quot; -m 'LogError: %q' &quot;Failed to bookmark $PTH_ESC&quot;
fi
]],
},
&quot;PopMode&quot;,
},
},
g = {
help = &quot;go to bookmark&quot;,
messages = {
{
BashExec0 = [===[
PTH=$(cat &quot;${XPLR_BOOKMARK_FILE:?}&quot; | fzf --no-sort)
if [ &quot;$PTH&quot; ]; then
&quot;$XPLR&quot; -m 'FocusPath: %q' &quot;$PTH&quot;
fi
]===],
},
&quot;PopMode&quot;,
},
},
d = {
help = &quot;delete bookmark&quot;,
messages = {
{
BashExec0 = [[
PTH=$(cat &quot;${XPLR_BOOKMARK_FILE:?}&quot; | fzf --no-sort)
sd &quot;$PTH\n&quot; &quot;&quot; &quot;${XPLR_BOOKMARK_FILE:?}&quot;
]],
},
&quot;PopMode&quot;,
},
},
esc = {
help = &quot;cancel&quot;,
messages = {
&quot;PopMode&quot;,
},
},
},
},
}
</code></pre>
</details>
<h3 id="another-bookmark-manager-type-thing-taken-from-wfxrs-zsh-plugin"><a class="header" href="#another-bookmark-manager-type-thing-taken-from-wfxrs-zsh-plugin">Another bookmark manager type thing, taken from <a href="https://github.com/wfxr/formarks">wfxr's zsh plugin</a>.</a></h3>
<p>Another bookmark manager type thing, taken from <a href="https://github.com/wfxr/formarks">wfxr's zsh plugin</a> which has colored output with fzf.</p>
<details>
<summary>Expand for details</summary>
<ul>
<li>Author: <a href="https://github.com/lmburns">@lmburns</a></li>
<li>Requires: fzf, exa</li>
<li>Tested on: MacOS</li>
</ul>
<pre><code class="language-lua">xplr.config.modes.builtin.go_to.key_bindings.on_key.b = {
help = &quot;bookmark jump&quot;,
messages = {
&quot;PopMode&quot;,
{ BashExec0 = [===[
field='\(\S\+\s*\)'
esc=$(printf '\033')
N=&quot;${esc}[0m&quot;
R=&quot;${esc}[31m&quot;
G=&quot;${esc}[32m&quot;
Y=&quot;${esc}[33m&quot;
B=&quot;${esc}[34m&quot;
pattern=&quot;s#^${field}${field}${field}${field}#$Y\1$R\2$N\3$B\4$N#&quot;
PTH=$(sed 's#: # -&gt; #' &quot;$PATHMARKS_FILE&quot;| nl| column -t \
| gsed &quot;${pattern}&quot; \
| fzf --ansi \
--height '40%' \
--preview=&quot;echo {}|sed 's#.*-&gt; ##'| xargs exa --color=always&quot; \
--preview-window=&quot;right:50%&quot; \
| sed 's#.*-&gt; ##')
if [ &quot;$PTH&quot; ]; then
&quot;$XPLR&quot; -m 'ChangeDirectory: %q' &quot;$PTH&quot;
fi
]===]
},
}
}
</code></pre>
</details>
<h3 id="fuzzy-search-history"><a class="header" href="#fuzzy-search-history">Fuzzy search history</a></h3>
<p>Fuzzy search the last visited directories.</p>
<details>
<summary>Expand for details</summary>
<ul>
<li>Author: <a href="https://github.com/sayanarijit">@sayanarijit</a></li>
<li>Requires: fzf</li>
<li>Tested on: Linux</li>
</ul>
<pre><code class="language-lua">xplr.config.modes.builtin.go_to.key_bindings.on_key.h = {
help = &quot;history&quot;,
messages = {
&quot;PopMode&quot;,
{
BashExec0 = [===[
PTH=$(cat &quot;${XPLR_PIPE_HISTORY_OUT:?}&quot; | sort -z -u | fzf --read0)
if [ &quot;$PTH&quot; ]; then
&quot;$XPLR&quot; -m 'ChangeDirectory: %q' &quot;$PTH&quot;
fi
]===],
},
},
}
</code></pre>
</details>
<h3 id="batch-rename"><a class="header" href="#batch-rename">Batch rename</a></h3>
<p>Batch rename the selected or visible files and directories in $PWD.</p>
<details>
<summary>Expand for details</summary>
<p><a href="https://gifyu.com/image/rGbo"><img src="https://s4.gifyu.com/images/xplr-rename.gif" alt="xplr-rename.gif" /></a></p>
<ul>
<li>Author: <a href="https://github.com/sayanarijit">@sayanarijit</a></li>
<li>Requires: <a href="https://github.com/marcusbuffett/pipe-rename">pipe-rename</a></li>
<li>Tested on: Linux</li>
</ul>
<pre><code class="language-lua">xplr.config.modes.builtin.default.key_bindings.on_key.R = {
help = &quot;batch rename&quot;,
messages = {
{
BashExec = [===[
SELECTION=$(cat &quot;${XPLR_PIPE_SELECTION_OUT:?}&quot;)
NODES=${SELECTION:-$(cat &quot;${XPLR_PIPE_DIRECTORY_NODES_OUT:?}&quot;)}
if [ &quot;$NODES&quot; ]; then
echo -e &quot;$NODES&quot; | renamer
&quot;$XPLR&quot; -m ExplorePwdAsync
fi
]===],
},
},
}
</code></pre>
</details>
<h3 id="serve-pwd"><a class="header" href="#serve-pwd">Serve $PWD</a></h3>
<p>Serve $PWD using a static web server via LAN.</p>
<details>
<summary>Expand for details</summary>
<ul>
<li>Author: <a href="https://github.com/sayanarijit">@sayanarijit</a></li>
<li>Requires: <a href="https://github.com/weihanglo/sfz">sfz</a>, fzf</li>
<li>Tested on: Linux</li>
</ul>
<pre><code class="language-lua">xplr.config.modes.builtin.default.key_bindings.on_key.S = {
help = &quot;serve $PWD&quot;,
messages = {
{
BashExec0 = [===[
IP=$(ip addr | grep -w inet | cut -d/ -f1 | grep -Eo '[0-9]{1,3}\.[0-9]{ 1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | fzf --prompt 'Select IP &gt; ')
echo &quot;IP: ${IP:?}&quot;
read -p &quot;Port (default 5000): &quot; PORT
echo
sfz --all --cors --no-ignore --bind ${IP:?} --port ${PORT:-5000} . &amp;
sleep 1 &amp;&amp; read -p '[press enter to exit]'
kill -9 %1
]===],
},
},
}
</code></pre>
</details>
<h3 id="image-viewer-imv"><a class="header" href="#image-viewer-imv">Image viewer (imv)</a></h3>
<p>Preview images using <a href="https://sr.ht/%7Eexec64/imv">imv</a>.</p>
<details>
<summary>Expand for details</summary>
<ul>
<li>Author: <a href="https://github.com/sayanarijit">@sayanarijit</a></li>
<li>Requires: <a href="https://sr.ht/%7Eexec64/imv">imv</a>, <a href="https://www.semicomplete.com/projects/xdotool">xdotool</a></li>
<li>Tested on: Linux, FreeBSD 13.1-RELEASE</li>
</ul>
<pre><code class="language-lua">xplr.config.modes.builtin.default.key_bindings.on_key.P = {
help = &quot;preview&quot;,
messages = {
{
BashExecSilently0 = [===[
FIFO_PATH=&quot;/tmp/xplr.fifo&quot;
if [ -e &quot;$FIFO_PATH&quot; ]; then
&quot;$XPLR&quot; -m StopFifo
rm -f -- &quot;$FIFO_PATH&quot;
else
mkfifo &quot;$FIFO_PATH&quot;
&quot;$HOME/.local/bin/imv-open.sh&quot; &quot;$FIFO_PATH&quot; &quot;$XPLR_FOCUS_PATH&quot; &amp;
&quot;$XPLR&quot; -m 'StartFifo: %q' &quot;$FIFO_PATH&quot;
fi
]===],
},
},
}
</code></pre>
<p>$HOME/.local/bin/imv-open.sh</p>
<pre><code class="language-bash">#!/usr/bin/env bash
FIFO_PATH=&quot;$1&quot;
IMAGE=&quot;$2&quot;
MAINWINDOW=&quot;$(xdotool getactivewindow)&quot;
IMV_PID=&quot;$(pgrep imv)&quot;
if [ ! &quot;$IMV_PID&quot; ]; then
imv &quot;$IMAGE&quot; &amp;
IMV_PID=$!
fi
sleep 0.5
xdotool windowactivate &quot;$MAINWINDOW&quot;
while read -r path; do
imv-msg &quot;$IMV_PID&quot; close all
imv-msg &quot;$IMV_PID&quot; open &quot;$path&quot;
done &lt; &quot;$FIFO_PATH&quot;
imv-msg &quot;$IMV_PID&quot; quit
[ -e &quot;$FIFO_PATH&quot; ] &amp;&amp; rm -f -- &quot;$FIFO_PATH&quot;
</code></pre>
</details>
<h3 id="text-preview-pane"><a class="header" href="#text-preview-pane">Text preview pane</a></h3>
<p>Preview text files in a native xplr pane (should be fast enough).</p>
<details>
<summary>Expand for details</summary>
<ul>
<li>Author: <a href="https://github.com/sayanarijit">@sayanarijit</a></li>
<li>Requires: none</li>
<li>Tested on: Linux, FreeBSD 13.1-RELEASE</li>
</ul>
<pre><code class="language-lua">local function stat(node)
return xplr.util.to_yaml(xplr.util.node(node.absolute_path))
end
local function read(path, height)
local p = io.open(path)
if p == nil then
return nil
end
local i = 0
local res = &quot;&quot;
for line in p:lines() do
if line:match(&quot;[^ -~\n\t]&quot;) then
p:close()
return
end
res = res .. line .. &quot;\n&quot;
if i == height then
break
end
i = i + 1
end
p:close()
return res
end
xplr.fn.custom.preview_pane = {}
xplr.fn.custom.preview_pane.render = function(ctx)
local title = nil
local body = &quot;&quot;
local n = ctx.app.focused_node
if n and n.canonical then
n = n.canonical
end
if n then
title = { format = n.absolute_path, style = xplr.util.lscolor(n.absolute_path) }
if n.is_file then
body = read(n.absolute_path, ctx.layout_size.height) or stat(n)
else
body = stat(n)
end
end
return { CustomParagraph = { ui = { title = title }, body = body } }
end
local preview_pane = { Dynamic = &quot;custom.preview_pane.render&quot; }
local split_preview = {
Horizontal = {
config = {
constraints = {
{ Percentage = 60 },
{ Percentage = 40 },
},
},
splits = {
&quot;Table&quot;,
preview_pane,
},
},
}
xplr.config.layouts.builtin.default =
xplr.util.layout_replace(xplr.config.layouts.builtin.default, &quot;Table&quot;, split_preview)
</code></pre>
</details>
<h3 id="tere-navigation"><a class="header" href="#tere-navigation">Tere Navigation</a></h3>
<p>Navigate using the <a href="https://github.com/mgunyho/tere">tere</a> file explorer (defaults to type-to-nav system).</p>
<details>
<summary>Expand for details</summary>
<ul>
<li>Author: <a href="https://github.com/sayanarijit">@sayanarijit</a></li>
<li>Requires: <a href="https://github.com/mgunyho/tere">tere</a></li>
<li>Tested on: Linux</li>
</ul>
<pre><code class="language-lua">xplr.config.modes.builtin.default.key_bindings.on_key.T = {
help = &quot;tere nav&quot;,
messages = {
{ BashExec0 = [[&quot;$XPLR&quot; -m 'ChangeDirectory: %q' &quot;$(tere)&quot;]] },
},
}
</code></pre>
</details>
<h2 id="also-see-7"><a class="header" href="#also-see-7">Also See:</a></h2>
<ul>
<li><a href="awesome-plugins.html">Awesome Plugins</a></li>
<li><a href="awesome-integrations.html">Awesome Integrations</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="plugin"><a class="header" href="#plugin">Plugin</a></h1>
<p>xplr supports pluggable Lua modules that can be used to easily configure or
extend xplr UI and functionalities.</p>
<ul>
<li><a href="installing-plugins.html">Installing Plugins</a></li>
<li><a href="writing-plugins.html">Writing Plugins</a></li>
<li><a href="awesome-plugins.html">Awesome Plugins</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="installing-plugins"><a class="header" href="#installing-plugins">Installing Plugins</a></h1>
<p>One way to install plugins is to use a plugin manager like <a href="https://github.com/dtomvan/xpm.xplr">dtomvan/xpm.xplr</a>.</p>
<p>But you can also install and manage plugins manually.</p>
<h2 id="install-manually"><a class="header" href="#install-manually">Install Manually</a></h2>
<ul>
<li>
<p>Add the following line in <code>~/.config/xplr/init.lua</code></p>
<pre><code class="language-lua">local home = os.getenv(&quot;HOME&quot;)
package.path = home
.. &quot;/.config/xplr/plugins/?/init.lua;&quot;
.. home
.. &quot;/.config/xplr/plugins/?.lua;&quot;
.. package.path
</code></pre>
</li>
<li>
<p>Clone the plugin</p>
<pre><code class="language-bash">mkdir -p ~/.config/xplr/plugins
git clone https://github.com/sayanarijit/material-landscape2.xplr ~/.config/xplr/plugins/material-landscape2
</code></pre>
</li>
<li>
<p>Require the module in <code>~/.config/xplr/init.lua</code></p>
<pre><code class="language-lua">require(&quot;material-landscape2&quot;).setup()
-- The setup arguments might differ for different plugins.
-- Visit the project README for setup instructions.
</code></pre>
</li>
</ul>
<h2 id="luarocks-support"><a class="header" href="#luarocks-support">Luarocks Support</a></h2>
<p>Some plugins may require <a href="https://luarocks.org">luarocks</a> to work.</p>
<p>Setup luarocks with the following steps:</p>
<ul>
<li>
<p>Install luarocks (via your package managers or follow the <a href="https://luarocks.org">official guide</a>).</p>
</li>
<li>
<p>Add <code>eval &quot;$(luarocks path --lua-version 5.1)&quot;</code> in your <code>.bashrc</code> or <code>.zshrc</code>.</p>
</li>
<li>
<p>Add the following lines in <code>~/.config/xplr/init.lua</code></p>
<pre><code class="language-lua">package.path = os.getenv(&quot;LUA_PATH&quot;) .. &quot;;&quot; .. package.path
package.cpath = os.getenv(&quot;LUA_CPATH&quot;) .. &quot;;&quot; .. package.cpath
</code></pre>
<p>Now you can install packages using luarocks. Be sure to append <code>--lua-version</code>.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="language-bash">luarocks install luafilesystem --local --lua-version 5.1
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="writing-plugins"><a class="header" href="#writing-plugins">Writing Plugins</a></h1>
<p>Anyone who can write <a href="https://www.lua.org">Lua</a> code, can write xplr plugins.</p>
<p>Just follow the instructions and best practices:</p>
<h2 id="naming"><a class="header" href="#naming">Naming</a></h2>
<p>xplr plugins are named using hiphen (<code>-</code>) separated words that may also include
integers. They will be plugged using the <code>require()</code> function in Lua.</p>
<h2 id="structure"><a class="header" href="#structure">Structure</a></h2>
<p>A minimal plugin should confirm to the following structure:</p>
<pre><code>.
├── README.md
└── init.lua
</code></pre>
<p>You can also use <a href="https://github.com/sayanarijit/plugin-template1.xplr">this template</a>.</p>
<h3 id="readmemd"><a class="header" href="#readmemd">README.md</a></h3>
<p>This is where you document what the plugin does, how to use it, etc.</p>
<h3 id="initlua"><a class="header" href="#initlua">init.lua</a></h3>
<p>This file is executed to load the plugin. It should expose a <code>setup()</code>
function, which will be used by the users to setup the plugin.</p>
<p>Example:</p>
<pre><code class="language-lua">local function setup(args)
local xplr = xplr
-- do stuff with xplr
end
return { setup = setup }
</code></pre>
<h2 id="publishing"><a class="header" href="#publishing">Publishing</a></h2>
<p>When publishing plugins on GitHub or other repositories, it's a best practice
to append <code>.xplr</code> to the name to make them distinguishable. Similar to the
<code>*.nvim</code> naming convention for <a href="https://neovim.io">Neovim</a> plugins.</p>
<p>Finally, after publishing, don't hesitate to
<a href="https://github.com/sayanarijit/xplr/discussions/categories/show-and-tell">let us know</a>.</p>
<h2 id="best-practices"><a class="header" href="#best-practices">Best practices</a></h2>
<ul>
<li>Try not to execute a lot of commands at startup, it may make xplr slow to
start.</li>
<li>When executing commands, prefer <code>Call0</code> over <code>Call</code>, <code>BashExec0</code> over
<code>BashExec</code> and so on. File names may contain newline characters
(e.g. <code>foo$'\n'bar</code>).</li>
<li>File names may also contain quotes. Avoid writing directly to
<code>$XPLR_PIPE_MSG_IN</code>. Use <code>xplr -m</code> / <code>xplr --pipe-msg-in</code> instead.</li>
<li>Check for empty variables using the syntax <code>${FOO:?}</code> or use a default value
<code>${FOO:-defaultvalue}</code>.</li>
</ul>
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
<p>Visit <a href="awesome-plugins.html">Awesome Plugins</a> for xplr plugin examples.</p>
<h2 id="also-see-8"><a class="header" href="#also-see-8">Also See</a></h2>
<ul>
<li><a href="https://github.com/sayanarijit/xplr/wiki/Hacks">Tip: A list of hacks yet to make it as Lua plugins</a></li>
<li><a href="https://github.com/sayanarijit/xplr/discussions/274">Tip: Some UI and themeing tips</a></li>
<li><a href="https://github.com/sayanarijit/xplr/discussions/273">Tip: A list of handy utility functions</a></li>
<li><a href="https://github.com/sayanarijit/xplr/discussions/250">Tip: Share tips and tricks working with Lua</a></li>
<li><a href="configure-key-bindings.html#tutorial-adding-a-new-mode">Tutorial: Adding a New Mode</a></li>
<li><a href="environment-variables-and-pipes.html#example-using-environment-variables-and-pipes">Example: Using Environment Variables and Pipes</a></li>
<li><a href="lua-function-calls.html#example-using-lua-function-calls">Example: Using Lua Function Calls</a></li>
<li><a href="layout.html#example-defining-custom-layout">Example: Defining Custom Layout</a></li>
<li><a href="column-renderer.html#example-customizing-table-renderer">Example: Customizing Table Renderer</a></li>
<li><a href="layout.html#example-render-a-custom-dynamic-table">Example: Render a custom dynamic table</a></li>
<li><a href="https://github.com/sayanarijit/xplr/discussions/529#discussioncomment-4073734">Example: Implementing a directory visit counter</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="awesome-plugins"><a class="header" href="#awesome-plugins">Awesome Plugins</a></h1>
<p>Here's a list of awesome xplr plugins that you might want to <a href="installing-plugins.html">check out</a>. If none
of the following plugins work for you, it's very easy to
<a href="writing-plugins.html">write your own</a>.</p>
<h3 id="extension-2"><a class="header" href="#extension-2">Extension</a></h3>
<ul>
<li><a href="https://github.com/sayanarijit/command-mode.xplr"><strong>sayanarijit/command-mode.xplr</strong></a> The missing command mode for xplr.</li>
<li><a href="https://github.com/igorepst/context-switch.xplr"><strong>igorepst/context-switch.xplr</strong></a> Context switch plugin for xplr.</li>
<li><a href="https://github.com/sayanarijit/dual-pane.xplr"><strong>sayanarijit/dual-pane.xplr</strong></a> Implements support for dual-pane navigation into xplr.</li>
<li><a href="https://github.com/sayanarijit/map.xplr"><strong>sayanarijit/map.xplr</strong></a> Visually inspect and interactively execute batch commands using xplr.</li>
<li><a href="https://github.com/sayanarijit/offline-docs.xplr"><strong>sayanarijit/offline-docs.xplr</strong></a> Fetch the appropriate version of xplr docs and browse offline.</li>
<li><a href="https://github.com/sayanarijit/regex-search.xplr"><strong>sayanarijit/regex-search.xplr</strong></a> Bring back the regex based search in xplr.</li>
<li><a href="https://github.com/sayanarijit/registers.xplr"><strong>sayanarijit/registers.xplr</strong></a> Use multiple registers to store the selected paths.</li>
<li><a href="https://github.com/sayanarijit/tree-view.xplr"><strong>sayanarijit/tree-view.xplr</strong></a> Hackable tree view for xplr</li>
<li><a href="https://github.com/sayanarijit/tri-pane.xplr"><strong>sayanarijit/tri-pane.xplr</strong></a> xplr plugin that implements ranger-like three pane layout.</li>
<li><a href="https://github.com/sayanarijit/type-to-nav.xplr"><strong>sayanarijit/type-to-nav.xplr</strong></a> Inspired by <a href="https://github.com/jarun/nnn/wiki/concepts#type-to-nav">nnn's type-to-nav mode</a> for xplr,
with some tweaks.</li>
<li><a href="https://github.com/dtomvan/term.xplr"><strong>dtomvan/term.xplr</strong></a> Terminal integration for xplr.</li>
<li><a href="https://github.com/sayanarijit/wl-clipboard.xplr"><strong>sayanarijit/wl-clipboard.xplr</strong></a> Copy and paste with system clipboard using wl-clipboard</li>
<li><a href="https://github.com/dtomvan/xpm.xplr"><strong>dtomvan/xpm.xplr</strong></a> The XPLR Plugin Manager.</li>
<li><a href="https://github.com/emsquid/style.xplr"><strong>emsquid/style.xplr</strong></a> Helper plugin that allows you to integrate xplr's <a href="style.html">Style</a> anywhere.</li>
</ul>
<h3 id="integration"><a class="header" href="#integration">Integration</a></h3>
<ul>
<li><a href="https://github.com/sayanarijit/alacritty.xplr"><strong>sayanarijit/alacritty.xplr</strong></a> <a href="https://github.com/alacritty/alacritty">Alacritty</a> integration for xplr.</li>
<li><a href="https://github.com/sayanarijit/dragon.xplr"><strong>sayanarijit/dragon.xplr</strong></a> Drag and drop files using <a href="https://github.com/mwh/dragon">dragon</a>.</li>
<li><a href="https://github.com/sayanarijit/dua-cli.xplr"><strong>sayanarijit/dua-cli.xplr</strong></a> Get the disk usage using <a href="https://github.com/Byron/dua-cli">dua-cli</a> with selection
support.</li>
<li><a href="https://github.com/sayanarijit/fzf.xplr"><strong>sayanarijit/fzf.xplr</strong></a> Fuzzy search using <a href="https://github.com/junegunn/fzf">fzf</a> to focus on a file or enter.</li>
<li><a href="https://github.com/sayanarijit/find.xplr"><strong>sayanarijit/find.xplr</strong></a> An interactive finder plugin to complement <a href="https://github.com/sayanarijit/map.xplr">map.xplr</a>.</li>
<li><a href="https://github.com/Junker/nuke.xplr"><strong>Junker/nuke.xplr</strong></a> Open files in apps by file type or mime.</li>
<li><a href="https://github.com/sayanarijit/nvim-ctrl.xplr"><strong>sayanarijit/nvim-ctrl.xplr</strong></a> Send files to running Neovim sessions using
<a href="https://github.com/chmln/nvim-ctrl">nvim-ctrl</a>.</li>
<li><a href="https://github.com/dtomvan/ouch.xplr"><strong>dtomvan/ouch.xplr</strong></a> This plugin uses <a href="https://github.com/ouch-org/ouch">ouch</a> to compress and decompress files.</li>
<li><a href="https://github.com/dtomvan/paste-rs.xplr"><strong>dtomvan/paste-rs.xplr</strong></a> Use this plugin to paste your files to
<a href="https://paste.rs">paste.rs</a>, and open/delete them later using <a href="https://github.com/junegunn/fzf">fzf</a>.</li>
<li><a href="https://github.com/sayanarijit/preview-tabbed.xplr"><strong>sayanarijit/preview-tabbed.xplr</strong></a> Preview paths using suckless <a href="https://tools.suckless.org/tabbed/">tabbed</a> and
<a href="https://github.com/jarun/nnn/blob/master/plugins/preview-tabbed">nnn preview-tabbed</a>.</li>
<li><a href="https://github.com/sayanarijit/qrcp.xplr"><strong>sayanarijit/qrcp.xplr</strong></a> Send and receive files via QR code using <a href="https://github.com/claudiodangelis/qrcp">qrcp</a>.</li>
<li><a href="https://github.com/sayanarijit/scp.xplr"><strong>sayanarijit/scp.xplr</strong></a> Integrate xplr with scp.</li>
<li><a href="https://github.com/sayanarijit/trash-cli.xplr"><strong>sayanarijit/trash-cli.xplr</strong></a> Trash files and directories using <a href="https://github.com/andreafrancia/trash-cli">trash-cli</a>.</li>
<li><a href="https://github.com/sayanarijit/xclip.xplr"><strong>sayanarijit/xclip.xplr</strong></a> Copy and paste with system clipboard using <a href="https://github.com/astrand/xclip">xclip</a>.</li>
<li><a href="https://github.com/sayanarijit/zoxide.xplr"><strong>sayanarijit/zoxide.xplr</strong></a> Change directory using the <a href="https://github.com/ajeetdsouza/zoxide">zoxide</a> database.</li>
</ul>
<h3 id="theme"><a class="header" href="#theme">Theme</a></h3>
<ul>
<li><a href="https://github.com/sayanarijit/material-landscape.xplr"><strong>sayanarijit/material-landscape.xplr</strong></a> Material Landscape</li>
<li><a href="https://github.com/sayanarijit/material-landscape2.xplr"><strong>sayanarijit/material-landscape2.xplr</strong></a> Material Landscape 2</li>
<li><a href="https://github.com/sayanarijit/zentable.xplr"><strong>sayanarijit/zentable.xplr</strong></a> A clean, distraction free xplr table UI</li>
<li><a href="https://github.com/prncss-xyz/icons.xplr"><strong>prncss-xyz/icons.xplr</strong></a> An icon theme for xplr.</li>
<li><a href="https://github.com/dtomvan/extra-icons.xplr"><strong>dtomvan/extra-icons.xplr</strong></a> Adds more icons to icons.xplr, compatible
with zentable.xplr.</li>
<li><a href="https://gitlab.com/hartan/web-devicons.xplr"><strong>hartan/web-devicons.xplr</strong></a> Adds <a href="https://github.com/nvim-tree/nvim-web-devicons">nvim-web-devicons</a> to xplr with
optional coloring</li>
</ul>
<h2 id="also-see-9"><a class="header" href="#also-see-9">Also See:</a></h2>
<ul>
<li><a href="awesome-hacks.html">Awesome Hacks</a></li>
<li><a href="awesome-integrations.html">Awesome Integrations</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="integration-1"><a class="header" href="#integration-1">Integration</a></h1>
<p>xplr is designed to integrate well with other tools and commands. It can be
used as a file picker or a pluggable file manager.</p>
<ul>
<li><a href="awesome-integrations.html">Awesome Integrations</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="awesome-integrations"><a class="header" href="#awesome-integrations">Awesome Integrations</a></h1>
<p>Here's a list of awesome xplr integrations that you might want to check out.</p>
<p>If none of the following integrations work for you, you can create your own and
<a href="https://github.com/sayanarijit/xplr/discussions/categories/show-and-tell">let us know</a>.</p>
<h3 id="editor"><a class="header" href="#editor">Editor</a></h3>
<ul>
<li><a href="https://github.com/is0n/fm-nvim"><strong>fm-nvim</strong></a> Neovim plugin that lets you use your favorite terminal file managers from within Neovim.</li>
<li><a href="https://github.com/voldikss/vim-floaterm#xplr"><strong>vim-floaterm</strong></a> xplr integrated in vim-floaterm (Neo)vim plugin.</li>
<li><a href="https://github.com/sayanarijit/xplr.vim"><strong>xplr.vim</strong></a> Pick files in Vim using xplr.</li>
</ul>
<h3 id="github"><a class="header" href="#github">Github</a></h3>
<ul>
<li><a href="https://github.com/sayanarijit/gh-xplr"><strong>gh-xplr</strong></a> Explore GitHub repos using xplr via GitHub CLI.</li>
</ul>
<h3 id="shell"><a class="header" href="#shell">Shell</a></h3>
<ul>
<li><a href="https://github.com/romkatv/powerlevel10k/blob/191d1b89e325ee3b6d2d75a394654aaf4f077a7c/internal/p10k.zsh#L4756-L4768"><strong>powerlevel10k</strong></a> Powerlevel10k prompt for xplr shell.</li>
</ul>
<h3 id="security-tools"><a class="header" href="#security-tools">Security Tools</a></h3>
<ul>
<li><a href="https://github.com/orhun/gpg-tui#importreceive"><strong>gpg-tui</strong></a> Import GPG certificates using xplr.</li>
</ul>
<h2 id="also-see-10"><a class="header" href="#also-see-10">Also See:</a></h2>
<ul>
<li><a href="awesome-hacks.html">Awesome Hacks</a></li>
<li><a href="awesome-plugins.html">Awesome Plugins</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="alternatives"><a class="header" href="#alternatives">Alternatives</a></h1>
<p>These are the alternative TUI/CLI file managers/explorers you might want to check out (in no particular order).</p>
<ul>
<li><a href="https://github.com/jarun/nnn/">nnn</a></li>
<li><a href="https://github.com/vifm/vifm">vifm</a></li>
<li><a href="https://github.com/ranger/ranger">ranger</a></li>
<li><a href="https://github.com/gokcehan/lf">lf</a></li>
<li><a href="https://github.com/kamiyaa/joshuto">joshuto</a></li>
<li><a href="https://github.com/dylanaraps/fff">fff</a></li>
<li><a href="https://github.com/MidnightCommander/mc">mc</a></li>
<li><a href="https://github.com/Canop/broot">broot</a></li>
<li><a href="https://github.com/rabite0/hunter">hunter</a></li>
<li><a href="https://git.2f30.org/noice/">noice</a></li>
<li><a href="https://github.com/pasqu4le/clifm">clifm</a></li>
<li><a href="https://github.com/leo-arch/clifm">clifm</a> (non curses)</li>
<li><a href="https://github.com/kyoheiu/felix">felix</a></li>
</ul>
<p><a href="community.html">add more</a></p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="upgrade-guide"><a class="header" href="#upgrade-guide">Upgrade Guide</a></h1>
<p>When you upgrade xplr, you might see an error like this</p>
<pre><code>Incompatible script version in: /home/sayanarijit/.config/xplr/init.lua. The script version is: 0.9.0, the required version is: 0.10.1. Visit https://github.com/sayanarijit/xplr/wiki/Upgrade-Guide
</code></pre>
<p>All you need to do is follow the <a href="upgrade-guide.html#instructions">instructions</a> starting from
your config version, all the way to the required version.</p>
<details>
<summary>Expand for more information</summary>
<p>With every update, we either implement a <code>major</code> breaking change (e.g.
deprecating or replacing messages), or a <code>minor</code> feature addition (e.g. adding
new messages) or <code>patch</code>, fixes, and optimization (e.g. performance
optimization).</p>
<p>Knowing that we use the <code>{major}.{minor}.{patch}</code> versioning format,</p>
<ul>
<li>Major version mismatch are generally incompatible. xplr will fail
with error.</li>
<li>Minor version upgrades (not downgrades) and patch fixes are backwards
compatible. You might get notified by log a message which you can disable by
updating the version in your config file.</li>
<li>However, if the config file has a higher value for the minor version
than the app, then also xplr will fail with error, suggesting you
to visit this page.
Though in that case, you will be downgrading your config file based on your
app version.</li>
</ul>
<p>e.g.</p>
<ul>
<li><code>1.0.0</code> -&gt; <code>1.0.x</code>: Patch (fully compatible).</li>
<li><code>1.0.0</code> -&gt; <code>1.x.x</code>: Only backwards compatible. You can't generally use for
e.g. <code>app-1.0.0</code> with <code>config-1.1.0</code>. But vice versa is fine.</li>
<li><code>1.0.0</code> -&gt; <code>x.x.x</code>: Not compatible at all.</li>
</ul>
<p>Note that until we're <code>v1</code>, we'll be using the <code>{minor}</code> version number as
<code>{major}</code>, and the <code>{patch}</code> number as <code>{minor}</code> to determine
compatibility.</p>
</details>
<h3 id="instructions"><a class="header" href="#instructions">Instructions</a></h3>
<h4 id="v0202---v0212"><a class="header" href="#v0202---v0212"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.20.2">v0.20.2</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.21.2">v0.21.2</a></a></h4>
<ul>
<li>Some plugins might stop rendering colors. Wait for them to update.</li>
<li>Rename <code>xplr.config.general.sort_and_filter_ui.search_identifier</code> to
<code>xplr.config.general.sort_and_filter_ui.search_identifiers</code>.</li>
<li>Resolved Node API will not contain the <code>permissions</code> field anymore.
Use the utility function <code>xplr.util.node</code> to get its permissions.</li>
<li>Layout <code>CustomContent</code> has been undocumented. It will stay for compatibility,
but you should prefer using the following new layouts, because they support
custom title:
<ul>
<li>Static</li>
<li>Dynamic</li>
</ul>
</li>
<li>Use the new messages for improved search operations:
<ul>
<li>Search</li>
<li>SearchFromInput</li>
<li>SearchFuzzyUnordered</li>
<li>SearchFuzzyUnorderedFromInput</li>
<li>SearchRegex</li>
<li>SearchRegexFromInput</li>
<li>SearchRegexUnordered</li>
<li>SearchRegexUnorderedFromInput</li>
<li>ToggleSearchAlgorithm</li>
<li>EnableSearchOrder</li>
<li>DisableSearchOrder</li>
<li>ToggleSearchOrder</li>
</ul>
</li>
<li>Use skim's <a href="https://github.com/lotabout/skim#search-syntax">search syntax</a> to customize the search.</li>
<li>Set your preferred search algorithm and ordering:
<code>xplr.config.general.search.algorithm = &quot;Fuzzy&quot; -- or &quot;Regex&quot;</code>.
<code>xplr.config.general.search.unordered = false -- or true</code></li>
<li>You need to clear the selection list manually after performing batch
operation like copy, softlink creation etc.</li>
<li>Use the following new key bindings:
<ul>
<li><code>:sl</code> to list selection in a $PAGER.</li>
<li><code>:ss</code> to create softlink of the selected items.</li>
<li><code>:sh</code> to create hardlink of the selected items.</li>
<li><code>:se</code> to edit selection list in your $EDITOR.</li>
<li>Better conflict handling: add suffix rather than overriding/skipping.</li>
</ul>
</li>
<li>Navigate between the selected paths using the following messages:
<ul>
<li>FocusPreviousSelection (<code>ctrl-p</code>)</li>
<li>FocusNextSelection (<code>ctrl-n</code>)</li>
</ul>
</li>
<li>Use <code>LS_COLORS</code> environment variable, along with the following utility</li>
<li>functions for applying better styling/theaming.
<ul>
<li>xplr.util.lscolor</li>
<li>xplr.util.paint</li>
<li>xplr.util.textwrap</li>
<li>xplr.util.style_mix</li>
</ul>
</li>
<li>Use new the fields in Column Renderer Argument:
<ul>
<li>style</li>
<li>permissions</li>
</ul>
</li>
<li>Use the following config to specify how the paths in selection list should be
rendered:
<ul>
<li>xplr.config.general.selection.item.format</li>
<li>xplr.config.general.selection.item.style</li>
</ul>
</li>
<li>Use the following utility functions to work with the file permissions:
<ul>
<li>xplr.util.permissions_rwx</li>
<li>xplr.util.permissions_octal</li>
</ul>
</li>
<li>Type <code>:p</code> to edit file permissions interactively.</li>
<li>Also check out the following utility functions:
<ul>
<li>xplr.util.layout_replace</li>
<li>xplr.util.relative_to</li>
<li>xplr.util.shorthand</li>
<li>xplr.util.clone</li>
<li>xplr.util.exists</li>
<li>xplr.util.is_dir</li>
<li>xplr.util.is_file</li>
<li>xplr.util.is_symlink</li>
<li>xplr.util.is_absolute</li>
<li>xplr.util.path_split</li>
<li>xplr.util.node</li>
<li>xplr.util.node_type</li>
<li>xplr.util.shell_escape</li>
</ul>
</li>
<li>Executables will me marked with the mime type: <code>application/x-executable</code>.</li>
<li>macOS legacy coreutils will be generally supported, but please update it.</li>
</ul>
<p>Thanks to @noahmayr for contributing to a major part of this release.</p>
<h4 id="v0194---v0202"><a class="header" href="#v0194---v0202"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.19.4">v0.19.4</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.20.2">v0.20.2</a></a></h4>
<ul>
<li>BREAKING: xplr shell (<code>:!</code>) will default to null (<code>\0</code>) delimited pipes, as
opposed to newline (<code>\n</code>) delimited ones (i.e. will use <code>Call0</code> instead of
<code>Call</code>).</li>
<li>Use new messages for safer file path handling (<code>\0</code> delimited):
<ul>
<li>Call0</li>
<li>CallSilently0</li>
<li>BashExec0</li>
<li>BashExecSilently0</li>
</ul>
</li>
<li>Use new sub-commands for safer message passing:
<ul>
<li><code>-m FORMAT [ARGUMENT]...</code> / <code>--pipe-msg-in FORMAT [ARGUMENT]...</code></li>
<li><code>-M FORMAT [ARGUMENT]...</code> / <code>--print-msg-in FORMAT [ARGUMENT]...</code>
Where FORMAT is a YAML string that may contain <code>%s</code>, <code>%q</code> and <code>%%</code>
placeholders and ARGUMENT is the value per placeholder. See <code>init.lua</code>.</li>
</ul>
</li>
<li>Following hooks can be defined in the config files using an optional
<code>return { on_* = { list, of, messages }, ... }</code> statement at the end.
<ul>
<li>on_load</li>
<li>on_focus_change</li>
<li>on_directory_change</li>
<li>on_mode_switch (since v0.20.2)</li>
<li>on_layout_switch (since v0.20.2)</li>
</ul>
</li>
<li>Use <code>--vroot</code> to isolate navigation of an xplr session inside a specific
directory. Interaction still requires passing full path, and shell,
lua functions etc still can access paths outside vroot.</li>
<li>Use the following messages to switch vroot at runtime, or the use key
bindings available in the new builtin mode &quot;vroot&quot; (mapped to <code>:</code> <code>v</code>).
<ul>
<li>SetVroot</li>
<li>UnsetVroot</li>
<li>ToggleVroot</li>
<li>ResetVroot</li>
</ul>
</li>
<li>Use <code>$XPLR_INITIAL_PWD</code> and Lua equivalent to implement workspace like
features without using virtual root. Use keys <code>gi</code> to go to the initial
working directory from anywhere.</li>
<li>Use the convenient <code>xplr.util</code> utility functions in your Lua function calls.
See xplr.util API docs.</li>
</ul>
<h4 id="v0180---v0194"><a class="header" href="#v0180---v0194"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.18.0">v0.18.0</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.19.4">v0.19.4</a></a></h4>
<ul>
<li>BREAKING: The builtin modes cannot be accessed using space separated names
anymore. Use underscore separated mode names. For e.g.
<code>SwitchModeBuiltin: create file</code> becomes <code>SwitchModeBuiltin: create_file</code> and
so on. Kindly go through your config, find and update them, or copy from the
latest <code>init.lua</code>.</li>
<li>Now you can use <code>xplr.config.general.global_key_bindings</code> to define a set of
key bindings that are available by default in every mode. e.g. <code>esc</code>
and <code>ctrl-c</code>, and remove boilerplate code from your config.</li>
<li>You can use the new builtin mode <code>go_to_path</code> which can be used for typing or
pasting paths to enter into or to focus on. Type <code>g</code> <code>p</code> to enter this mode.</li>
<li>Now you can use basic tab completion in the <code>go_to_path</code>, <code>create_file</code>,
<code>create_directory</code>, <code>rename</code> and <code>duplicate_as</code> modes.</li>
<li>Use the builtin function <code>xplr.fn.builtin.try_complete_path</code> to add easy tab
completion support into your own configuration.</li>
<li>Now you can open OSC 7 compatible terminals into the <code>xplr</code>'s current working
directory by spawning new terminal sessions via the terminal supported key
bindings.</li>
<li>Use <code>NO_COLOR</code> environment variable to disable OSC 7 compliance along with
colors.</li>
<li>If you have fully copied the default <code>init.lua</code> locally, you might want to
go through the latest improvements in <code>init.lua</code>. Specifically the <code>search</code>,
<code>filter</code> and <code>sort</code> modes. Also, search for <code>SetInputPrompt</code> and the <code>tab</code>
key bindings.</li>
<li>Since version 0.19.1, you can access uid and gid of the file owner in the Lua
API.</li>
<li>The input buffer will support more readline-like keys.
Also, added &quot;DeleteTillEnd&quot; as another cursor based &quot;InputOperation&quot; option.</li>
<li>Fixed applying regex based filters via the CLI and <code>$XPLR_PIPE_MSG_IN</code> pipe.</li>
<li>You can use the <code>prompt</code> field to define input prompt for each mode, instead
of using the <code>SetInputPrompt</code> message.</li>
<li>Since version v0.19.4, the native search will default to skim-v2 based fuzzy
matching. <code>esc</code> while in search mode will recover the initial focus. People
who prefer the regex based search, can use the <code>regex-search.xplr</code> plugin.
The following messages will be available for search based operations:
<ul>
<li>SearchFuzzy</li>
<li>SearchFuzzyFromInput</li>
<li>AcceptSearch</li>
<li>CancelSearch</li>
</ul>
</li>
<li>Since version v0.19.4, quick scrolling operations are supported using the
following messages and keys:
<ul>
<li>ScrollUp -------- page-up</li>
<li>ScrollDown ------ page-down</li>
<li>ScrollUpHalf ---- {</li>
<li>ScrollDownHalf -- }</li>
</ul>
</li>
</ul>
<p><sub>Like this project so far? <strong><a href="contribute.html">Please consider contributing</a></strong>.</sub></p>
<h4 id="v0176---v0180"><a class="header" href="#v0176---v0180"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.17.6">v0.17.6</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.18.0">v0.18.0</a></a></h4>
<ul>
<li>Key binding <code>f</code> <code>r</code> and <code>f</code> <code>R</code> will now filter using regex.</li>
<li>Key binding <code>f</code> <code>backspace</code> will now remove the last filter.</li>
<li>Search mode now defaults to regex search.</li>
<li><code>Node</code> metadata in the Lua API will contain two new fields:
<ul>
<li><code>created</code></li>
<li><code>last_modified</code></li>
</ul>
</li>
<li>The last column in the files table now displays the last modification time.</li>
<li>You can now use <code>--read0</code>, <code>--write0</code> and <code>-0</code>/<code>--null</code> to read and/or print
null character delimited paths.</li>
<li>You can now the following regex filters:
<ul>
<li><code>RelativePathDoesMatchRegex</code></li>
<li><code>RelativePathDoesNotMatchRegex</code></li>
<li><code>IRelativePathDoesMatchRegex</code></li>
<li><code>IRelativePathDoesNotMatchRegex</code></li>
<li><code>AbsolutePathDoesMatchRegex</code></li>
<li><code>AbsolutePathDoesNotMatchRegex</code></li>
<li><code>IAbsolutePathDoesMatchRegex</code></li>
<li><code>IAbsolutePathDoesNotMatchRegex</code></li>
</ul>
</li>
<li>You can use a new <code>SetInputPrompt</code> to set the input prompt dynamically.</li>
<li>You can now use the following timestamp based sorters:
<ul>
<li>&quot;ByCreated&quot;</li>
<li>&quot;ByLastModified&quot;</li>
<li>&quot;ByCanonicalCreated&quot;</li>
<li>&quot;ByCanonicalLastModified&quot;</li>
<li>&quot;BySymlinkCreated&quot;</li>
<li>&quot;BySymlinkLastModified&quot;</li>
</ul>
</li>
</ul>
<h4 id="v0164---v0176"><a class="header" href="#v0164---v0176"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.16.4">v0.16.4</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.17.6">v0.17.6</a></a></h4>
<ul>
<li>Deprecated <code>app.directory_buffer</code>, <code>app.history</code>, and <code>app.last_modes</code> in
the custom dynamic layout renderer context.
As of now, there's no way to access these fields in dynamic layouts. While
<code>app.history</code> and <code>app.last_modes</code> can be re-added upon request
(with justification), <code>app.directory_buffer</code> has been deprecated for good.
However, there's no change in the <code>CallLua*</code> context.</li>
<li>Set <code>xplr.config.general.hide_remaps_in_help_menu</code> to <code>true</code> to hide the
remaps in help menu.</li>
<li><code>None</code> will be serialized to <code>nil</code> in Lua.</li>
<li><code>LuaEval</code> can now return a function that will be called with the Lua Context
argument. Refer to the <code>Full List of Messages</code> doc for example.</li>
<li>From version v0.17.1, set <code>xplr.config.general.disable_debug_error_mode</code> to
<code>true</code> to disable switching to the &quot;debug error&quot; mode when startup errors
occur.</li>
<li>From version v0.17.2, you can use CLI argument <code>--print-pwd-as-result</code> for cd
on quit, and key binding <code>ctrl-d</code> to duplicate a path in the same directory
with a different name.</li>
<li>Since version v0.17.3, you can use <code>border_type</code>, <code>border_style</code> to customize
borders, and <code>enforce_bounded_index_navigation</code> to customize up/down
navigation behavior when focus is on the top or bottom node.</li>
</ul>
<h4 id="v0152---v0164"><a class="header" href="#v0152---v0164"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.15.2">v0.15.2</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.16.4">v0.16.4</a></a></h4>
<ul>
<li>Deprecated <code>config.general.cursor</code>. The default terminal cursor will be used
for the time being.</li>
<li>Opening xplr inside a symlink will not resolve the path.</li>
<li>You can now replace most boilerplate configuration handling keys to send
<code>BufferInputFromKey</code>, <code>RemoveInputBufferLastCharacter</code>,
<code>RemoveInputBufferLastWord</code>, <code>SetInputBuffer = &quot;&quot;</code> etc. messages with a
single <code>UpdateInputBufferFromKey</code> message.</li>
<li>You can now pass multiple paths as command-line arguments or via stdin to
select paths, e.g. <code>xplr -- $PWD /path/to/select/1 /path/to/select/2</code>.</li>
<li>Pass <code>--force-focus</code> to focus on the first path even if it's a directory,
e.g. <code>xplr . --force-focus</code>.</li>
<li>Use new messages <code>LuaEval</code> and <code>LuaEvalSilently</code> to run Lua code without
needing to define a function. However, the <code>app</code> context won't be available.</li>
<li>You can now use new key handlers in the config:
<ul>
<li>on_alphanumeric</li>
<li>on_character</li>
<li>on_navigation</li>
<li>on_function</li>
</ul>
</li>
</ul>
<h4 id="v0147---v0152"><a class="header" href="#v0147---v0152"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.14.7">v0.14.7</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.15.2">v0.15.2</a></a></h4>
<ul>
<li>Deprecated <code>config</code> field from <code>CallLua</code> argument. Use the globally available
<code>xplr.config</code> instead.</li>
<li><code>xplr.config.general.disable_recover_mode</code> has been deprecated. Use
<code>xplr.config.general.enable_recover_mode</code> instead.</li>
<li>Use <code>xplr.config.general.focus_selection_ui</code> to highlight selected files
under focus differently than files under focus that are not selected.</li>
<li>Use <code>PopModeKeepingInputBuffer</code>, and SwitchMode alternatives to switching to
different modes without resetting the input buffer.</li>
<li>Use the new <code>CustomContent</code> layout option to render custom content.</li>
<li>Use the new <code>layout</code> field in a mode to define custom layout for a specific
mode.</li>
<li>Library users please refer to the latest API docs and examples.</li>
</ul>
<h4 id="v0137---v0147"><a class="header" href="#v0137---v0147"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.13.7">v0.13.7</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.14.7">v0.14.7</a></a></h4>
<ul>
<li>macOS users need to place their config file (<code>init.lua</code>) in
<code>$HOME/.config/xplr/</code> or <code>/etc/xplr/</code>.</li>
<li>Library users please refer to the latest API docs.</li>
<li>Check out the new messages: <code>{Start|Stop|Toggle}Fifo</code>. These enable support
for <a href="https://github.com/sayanarijit/xplr/pull/229#issue-662426960">FIFO based file previews</a>.</li>
<li>You can disable the recover mode using <code>config.general.disable_recover_mode = true</code>.</li>
<li>Try running <code>xplr --help</code>. Yes, CLI has been implemented.</li>
<li>Since version <code>v0.14.3</code>, <code>StartFifo</code> and <code>ToggleFifo</code> will write to the FIFO
path when called. So, there's no need to pipe the focus path explicitly.</li>
<li>Since version <code>v0.14.3</code>, general config <code>xplr.config.start_fifo</code> is available
which can be set to a file path to start a fifo when xplr starts.</li>
<li>Since version <code>v0.14.4</code>, <code>$XPLR_SESSION_PATH</code> can be used to dump session
related data.</li>
<li>Since version <code>v0.14.6</code>, the <code>-C</code> or <code>--extra-config</code> CLI argument is
available.</li>
</ul>
<h4 id="v0121---v0137"><a class="header" href="#v0121---v0137"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.12.1">v0.12.1</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.13.7">v0.13.7</a></a></h4>
<ul>
<li>Lua functions called using <a href="https://docs.rs/xplr/latest/xplr/app/enum.ExternalMsg.html#variant.CallLua"><code>CallLua</code></a> and <a href="https://docs.rs/xplr/latest/xplr/app/enum.ExternalMsg.html#variant.CallLuaSilently"><code>CallLuaSilently</code></a> messages will receive <a href="https://docs.rs/xplr/latest/xplr/app/struct.CallLuaArg.html"><code>CallLuaArg</code></a> object as the function argument (instead of the <a href="https://docs.rs/xplr/latest/xplr/app/struct.App.html"><code>App</code></a> object).</li>
<li>Each <code>node_types</code> config will inherit defaults from matching less specific <code>node_types</code> config and overwrite them.</li>
<li>Since version <code>v0.13.2</code>, you don't need to use/send <code>Refresh</code> anymore. It will be auto-handled by xplr.</li>
</ul>
<h4 id="v0111---v0121"><a class="header" href="#v0111---v0121"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.11.1">v0.11.1</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.12.1">v0.12.1</a></a></h4>
<ul>
<li><code>xplr.config.node_types.mime_essence</code> has split into type and subtype. Hence, instead of <code>xplr.config.node_types.mime_essence[&quot;text/plain&quot;] = ..</code> use <code>xplr.config.node_types.mime_essence[&quot;text&quot;] = { plain = .. }</code>.</li>
<li>You can also define <code>xplr.config.node_types.mime_essence[&quot;text&quot;][&quot;*&quot;]</code> that will match all text types (<code>text/*</code>).</li>
</ul>
<h4 id="v0102---v0111"><a class="header" href="#v0102---v0111"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.10.2">v0.10.2</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.11.1">v0.11.1</a></a></h4>
<ul>
<li><code>remaps:</code> has been removed to avoid confusion. Use lua assignments instead.
For e.g.
<pre><code>xplr.config.modes.builtin.default.key_bindings.on_key[&quot;v&quot;] = xplr.config.modes.builtin.default.key_bindings.on_key.space
</code></pre>
</li>
</ul>
<h4 id="v091---v0102"><a class="header" href="#v091---v0102"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.9.1">v0.9.1</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.10.2">v0.10.2</a></a></h4>
<ul>
<li><a href="https://github.com/sayanarijit/xplr/blob/85696ded7a/src/config.yml"><code>config.yml</code></a> has been fully replaced with <a href="https://github.com/sayanarijit/xplr/blob/main/src/init.lua"><code>init.lua</code></a>. If you have a lot of customization in your <code>config.yml</code>, <a href="https://github.com/sayanarijit/xplr-yml2lua">xplr-yml2lua</a> can help you with migrating it to <code>init.lua</code>.</li>
<li><code>Handlebars</code> templates has been replaced with <a href="https://github.com/sayanarijit/xplr/blob/bfdb7736b99bc3c5ae53e7d621ba0e7ca2299b14/src/init.lua#L2005-L2064">Lua functions</a>. You can either remove the customizations or overwrite the functions accordingly.</li>
<li>Added new messages <code>CallLua</code> and <code>CallLuaSilently</code> to call lua functions. The app state will be passed as input to the functions, and the returned messages will be handled by xplr. <code>CallLua</code> and <code>CallLuaSilently</code> are more flexible (and probably faster) alternatives to <code>Call</code>, <code>CallSilently</code>, <code>BashExec</code> and <code>BashExecSilently</code>. <a href="https://github.com/sayanarijit/xplr/pull/177#issue-650643573">e.g.</a></li>
</ul>
<h4 id="v090---v091"><a class="header" href="#v090---v091"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.9.0">v0.9.0</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.9.1">v0.9.1</a></a></h4>
<ul>
<li>You can now set <code>remaps: {key: null}</code> to un-map a key.</li>
<li><code>gx</code> will open the item under focus.</li>
<li>New key map <code>:sx</code> will open the selected items.</li>
</ul>
<h4 id="v080---v090"><a class="header" href="#v080---v090"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.8.0">v0.8.0</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.9.0">v0.9.0</a></a></h4>
<p>Your previous config should mostly work fine. However, in case you are using <code>SwitchMode</code> heavily in your custom config, follow along.</p>
<ul>
<li>Introduced new message <code>PopMode</code>. You might want to use this message instead of <code>SwitchMode*</code> when returning back to the previous mode.</li>
<li>After using (the group of) <code>PopMode</code> and <code>SwitchMode*</code> messages, you are now required to <code>Refresh</code> manually to avoid the UI lag.</li>
<li>Pressing any invalid key will now lead you to the <code>recover</code> mode and will protect you from typing further invalid keys. Press <code>esc</code> to escape the <code>recover</code> mode.</li>
<li>Introduced new message <code>LogWarning</code>, similar to other <code>Log*</code> messages.</li>
<li>Creating files and directories has been optimized for batch creation.</li>
</ul>
<h4 id="v072---v080"><a class="header" href="#v072---v080"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.7.2">v0.7.2</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.8.0">v0.8.0</a></a></h4>
<p>If you have made changes to the config file,</p>
<ul>
<li>Replace message <code>Explore</code> with <code>ExplorePwd</code> or <code>ExplorePwdAsync</code> or probably <code>ExploreParentsAsync</code>.</li>
<li>Pipe <code>$XPLR_PIPE_FOCUS_OUT</code> has been removed. Use <code>$XPLR_FOCUS_PATH</code> env var instead.</li>
<li>You might want to review your path escaping logics. For e.g. use <code>echo FocusPath: &quot;'&quot;$PWD&quot;'&quot; &gt;&gt; $PIPE</code> instead of <code>echo &quot;FocusPath: $PWD&quot; &gt;&gt; $PIPE</code>.</li>
</ul>
<h4 id="v070---v072"><a class="header" href="#v070---v072"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.7.0">v0.7.0</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.7.2">v0.7.2</a></a></h4>
<ul>
<li>Just update the <code>version</code> in your config file.</li>
<li>For version &gt;= <code>v0.7.1</code>, you might want to free up or remap the <code>tab</code> key in <code>search</code> mode to enable easy selection during search.</li>
</ul>
<h4 id="v060---v070"><a class="header" href="#v060---v070"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.6.0">v0.6.0</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.7.0">v0.7.0</a></a></h4>
<p>If you haven't made any changes in the config file, you should be fine just updating the version number. Else,</p>
<ul>
<li>You can make the <code>Table: ...</code>, <code>InputAndLogs: ...</code> layout values null and define the common properties in the <code>general.panel_ui</code> instead.</li>
</ul>
<h4 id="v0513---v060"><a class="header" href="#v0513---v060"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.5.13">v0.5.13</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.6.0">v0.6.0</a></a></h4>
<p>If you haven't made any changes in the config file, you should be fine just updating the version number. Else,</p>
<ul>
<li>Rename <code>add_modifier: {bits: 1}</code> to <code>add_modifiers: [Bold]</code>, <code>sub_modifier: {bits: 1}</code> to <code>sub_modifiers: [Bold]</code> and so on.</li>
<li>Rename <code>percentage: 10</code> to <code>Percentage: 10</code>, <code>ratio: 1</code> to <code>Ratio: 1</code> and so on.</li>
<li>You might want to free up or remap the <code>ctrl-w</code> key binding in <code>default</code> mode to enable layout switching.</li>
</ul>
<p>Optionally, checkout this new theme to learn more about what's new.</p>
<h4 id="v050---v0513"><a class="header" href="#v050---v0513"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.5.0">v0.5.0</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.5.13">v0.5.13</a></a></h4>
<ul>
<li>Just update the <code>version</code> in your config file.</li>
<li>For versions &gt;= <code>v0.5.8</code>, you can set <code>$OPENER</code> env var to declare a global GUI file opener (to open files using keys <code>gx</code>).</li>
<li>You might also want to update other mappings to handle files with names starting with <code>-</code> (hiphen). For example, instead of <code>rm ${filename}</code> use <code>rm -- ${filename}</code>. Same goes for <code>cp</code>, <code>mv</code>, <code>cat</code>, <code>touch</code> etc.</li>
<li>For version &gt;= <code>v0.5.13</code>, you might want to use the more specific <code>SwitchModeBuiltin</code> and <code>SwitchModeCustom</code> messages instead of the general <code>SwitchMode</code> message.</li>
</ul>
<h4 id="v043---v050"><a class="header" href="#v043---v050"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.4.3">v0.4.3</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.5.0">v0.5.0</a></a></h4>
<p>If you haven't have any changes in the config file, you should be fine just updating the version number.</p>
<p>Else do the following</p>
<ul>
<li>Replace <code>{RelativePathIs, case_sensitive: true}</code> with <code>RelativePathIs</code>.</li>
<li>Replace <code>{RelativePathIs, case_sensitive: false}</code> with <code>IRelativePathIs</code>.</li>
<li>Do the same with other filters you are using.</li>
<li>You might want to update your <code>backspace</code> handling to use the <code>RemoveInputBufferLastCharacter</code> message.</li>
<li>You might want to free-up <code>f</code>, <code>s</code>, <code>ctrl-r</code> and <code>ctrl-u</code> key bindings in the default mode, or remap them.</li>
<li>You might want to use the new UI variables.</li>
<li>Update your config version to <code>v0.5.0</code>.</li>
</ul>
<h4 id="v042---v043"><a class="header" href="#v042---v043"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.4.2">v0.4.2</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.4.3">v0.4.3</a></a></h4>
<p>If you have customized <code>general.table.row.cols</code>, you might want to <a href="https://github.com/sayanarijit/xplr/blob/af1cda5762/src/config.yml#L46-L48">update it</a> to use the new variables with better symlink support.</p>
<h4 id="v041---v042"><a class="header" href="#v041---v042"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.4.1">v0.4.1</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.4.2">v0.4.2</a></a></h4>
<p>In case you have mapped the keys <code>q</code>, <code>ctrl-i</code> and <code>ctrl-o</code>, you may want to revisit the default mode key bindings and remap accordingly to use the new functionalities.</p>
<h4 id="v0313---v041"><a class="header" href="#v0313---v041"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.3.13">v0.3.13</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.4.1">v0.4.1</a></a></h4>
<p>A lot has changed (apologies). But I promise from now on, upgrading will be much less painful (thanks to <a href="https://github.com/maximbaz">@maximbaz</a>'s valuable <a href="https://github.com/sayanarijit/xplr/issues/45#issue-854447104">inputs</a> and <a href="https://github.com/sayanarijit/xplr/pull/47">code reviews</a>).</p>
<p>So, to start with the upgrade, let's remove everything from your config file except the <code>version</code> field and your custom modifications. If <code>version</code> is the only thing remaining, update it to <code>v0.4.1</code> and you are done.</p>
<p>Else, do the following</p>
<ul>
<li>Rename <code>general.focused_ui</code> to <code>general.focus_ui</code> (<a href="https://github.com/sayanarijit/xplr/blob/055c1083d6/src/config.yml#L124">see here</a>).</li>
<li>Rename <code>filetypes</code> to <code>node_types</code>. (<a href="https://github.com/sayanarijit/xplr/blob/055c1083d6/src/config.yml#L145">see here</a>)</li>
<li>Rename <code>custom</code> field to <code>meta</code>. (<a href="https://github.com/sayanarijit/xplr/blob/055c1083d6/src/config.yml#L154-L155">see here</a>)</li>
<li>Move <code>icon</code> to <code>meta.icon</code>. (<a href="https://github.com/sayanarijit/xplr/blob/055c1083d6/src/config.yml#L45">see here</a>)</li>
<li>Rename <code>normal_ui</code> to <code>default_ui</code>. (<a href="https://github.com/sayanarijit/xplr/blob/055c1083d6/src/config.yml#L114">see here</a>)</li>
<li>Split <code>modes</code> into <code>modes.builtin</code> and <code>modes.custom</code> (<a href="https://github.com/sayanarijit/xplr/blob/055c1083d6/src/config.yml#L180-L181">see here</a>). Migrate your custom modes to <code>modes.custom</code>. And copy only the changes in the in-built modes in <code>modes.builtin</code>.</li>
<li>Finally, update the <code>version</code> to <code>v0.4.1</code>.</li>
</ul>
<h4 id="v038---v0313"><a class="header" href="#v038---v0313"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.3.8">v0.3.8</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.3.13">v0.3.13</a></a></h4>
<p>Your current config should work fine. However, you might want to replace some <code>Call</code> and <code>BashExec</code> messages with <code>CallSilently</code> and <code>BashExecSilently</code> to remove the flickering of the screen.</p>
<p>If you haven't made any changes to the configuration, you can delete and regenerate it.</p>
<p>Else, do the following</p>
<ul>
<li>Check the new default config by temporarily removing your current config (with backup) and dumping the new config.</li>
<li>Search for <code>Call</code> and <code>BashExec</code> in the new config.</li>
<li>Compare and probably replace the associated actions in your current config</li>
</ul>
<h4 id="v030---v038"><a class="header" href="#v030---v038"><a href="https://github.com/sayanarijit/xplr/releases/tag/v0.3.0">v0.3.0</a> -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.3.8">v0.3.8</a></a></h4>
<p>Your current config should work fine. However, you might want to replace some <code>ResetNodeFilters</code> messages with <code>RemoveNodeFilter</code> and <code>RemoveNodeFilterFromInput</code> to get a better search and filter experience.</p>
<p>If you haven't made any changes to the configuration, you can delete and regenerate it.</p>
<p>Else, do the following</p>
<ul>
<li>Check the new default config by temporarily removing your current config (with backup) and dumping the new config.</li>
<li>Search for <code>RemoveNodeFilterFromInput</code> in the new config.</li>
<li>Compare and probably replace the associated actions in your current config.</li>
</ul>
<h4 id="v0214---v030"><a class="header" href="#v0214---v030">v0.2.14 -&gt; <a href="https://github.com/sayanarijit/xplr/releases/tag/v0.3.0">v0.3.0</a></a></h4>
<p>If you haven't made any changes to the configuration, you can delete and regenerate it.</p>
<p>Else do the following:</p>
<ul>
<li><code>$XPLR_APP_YAML</code> has been removed. You can use <code>Debug</code> to export the app state.</li>
<li><code>$XPLR_RESULT</code> has been ported to file <code>$XPLR_PIPE_RESULT_OUT</code>. Use <code>cat</code> instead of <code>echo</code>, <code>&lt;</code> instead of <code>&lt;&lt;&lt;</code> etc.</li>
<li><code>$XPLR_GLOBAL_HELP_MENU</code> has been ported to
file <code>$XPLR_PIPE_GLOBAL_HELP_MENU_OUT</code>. Use <code>cat</code> instead of <code>echo</code>, <code>&lt;</code> instead of <code>&lt;&lt;&lt;</code> etc.</li>
<li><code>$XPLR_DIRECTORY_NODES</code> has been ported to
file <code>$XPLR_PIPE_DIRECTORY_NODES_OUT</code>. Use <code>cat</code> instead of <code>echo</code>, <code>&lt;</code> instead of <code>&lt;&lt;&lt;</code> etc.</li>
<li><code>$XPLR_LOGS</code> has been ported to file <code>$XPLR_PIPE_LOGS_OUT</code>. Use <code>cat</code> instead of <code>echo</code>, <code>&lt;</code> instead of <code>&lt;&lt;&lt;</code> etc.</li>
<li><code>$XPLR_PIPE_RESULT</code> has been ported to file <code>$XPLR_PIPE_RESULT_OUT</code>. Use <code>cat</code> instead of <code>echo</code>, <code>&lt;</code> instead of <code>&lt;&lt;&lt;</code> etc.</li>
<li>Finally, update the <code>version</code> in your config file.</li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="community"><a class="header" href="#community">Community</a></h1>
<p>Building an active community of awesome people and learning stuff together is
one of my reasons to publish this tool and maintain it. Hence, please feel free
to reach out via your preferred way.</p>
<ul>
<li>Real-time chat lovers can join our <a href="https://matrix.to/#/#xplr-pub:matrix.org"><strong>matrix room</strong></a> or <a href="https://discord.gg/JmasSPCcz3"><strong>discord channel</strong></a>.</li>
<li>Forum discussion veterans can <a href="https://github.com/sayanarijit/xplr/discussions"><strong>start a new GitHub discussion</strong></a>.</li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><p>If you like xplr, and want to contribute, that would be really awesome.</p>
<p>You can contribute to this project in the following ways</p>
<ul>
<li>
<p>Contribute your time and expertise (read <a href="https://github.com/sayanarijit/xplr/blob/main/CONTRIBUTING.md">CONTRIBUTING.md</a> for instructions).</p>
<ul>
<li><strong>Developers:</strong> You can help me improve my code, fix things, implement features etc.</li>
<li><strong>Repository maintainers:</strong> You can save the users from the pain of managing xplr in their system manually.</li>
<li><strong>Code Reviewers:</strong> Teach me your ways of code.</li>
<li><strong>Designers:</strong> You can make the logo even more awesome, donate stickers and blog post worthy pictures.</li>
<li><strong>Bloggers, YouTubers &amp; broadcasters:</strong> You can help spread the word.</li>
</ul>
</li>
<li>
<p>Contribute by donating or sponsoring me via any of the following ways.</p>
<ul>
<li><a href="https://github.com/sponsors/sayanarijit?o=esb">GitHub Sponsors</a></li>
<li><a href="https://opencollective.com/xplr">Open Collective</a></li>
<li><a href="https://ko-fi.com/sayanarijit">ko-fi</a></li>
<li><a href="https://liberapay.com/sayanarijit">liberapay</a></li>
<li><a href="https://paypal.me/sayanarijit">PayPal</a></li>
</ul>
</li>
</ul>
<p>For further queries or concern related to <code>xplr</code>, <a href="community.html">just ask us</a>.</p>
<h3 id="backers"><a class="header" href="#backers">Backers</a></h3>
<p><a href="https://opencollective.com/xplr#backer"><img src="https://opencollective.com/xplr/tiers/backer.svg?width=890" /></a></p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
</nav>
</div>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
<script type="text/javascript">
window.addEventListener('load', function() {
window.setTimeout(window.print, 100);
});
</script>
</body>
</html>