Add support for FIFO based previewer

Adds basic support for nnn-like FIFO based previewer.

The FIFO can be manager with the following messages:

- StartFifo: /path/to/fifo
- StopFifo
- ToggleFifo: /path/to/fifo

A basic nnn plugin wrapper example:

```lua
-- Usage Example:
--
--   require("nnn_preview_wrapper").setup{
--     plugin_path = os.getenv("HOME") .. "/.config/nnn/plugins/preview-tabbed",
--     fifo_path = "/tmp/xplr.fifo",
--     mode = "action",
--     key = "p",
--   }
--
-- Press `:p` to toggle preview mode.

local function setup(o)

  if o.fifo_path == nil then
    o.fifo_path = os.getenv("NNN_FIFO")
  end

  if o.mode == nil then
    o.mode = "action"
  end

  if o.key == nil then
    o.key = "p"
  end

  local enabled = false
  local message = nil

  os.execute('[ ! -p "' .. o.fifo_path ..'" ] && mkfifo "' .. o.fifo_path .. '"')

  xplr.fn.custom.preview_toggle = function(app)

    if enabled then
      enabled = false
      message = "StopFifo"
    else
      os.execute('NNN_FIFO="' .. o.fifo_path .. '" "'.. o.plugin_path .. '" & ')
      enabled = true
      message = { StartFifo = o.fifo_path }
    end

    return { message }
  end

  xplr.config.modes.builtin[o.mode].key_bindings.on_key[o.key] = {
    help = "search with preview",
    messages = {
      "PopMode",
      { CallLuaSilently = "custom.preview_toggle" },
    },
  }
end

return { setup = setup }
```

Press `:p` to toggle preview mode.

Closes: https://github.com/sayanarijit/xplr/issues/205
pull/236/head
Arijit Basu 3 years ago committed by Arijit Basu
parent 2962a8d52d
commit a2f42ac6fc

@ -1272,6 +1272,17 @@ pub enum ExternalMsg {
/// Toggle mouse
ToggleMouse,
/// Start piping the focused path to the given fifo path
///
/// **Example:** `StartFifo: /tmp/xplr.fifo`
StartFifo(String),
/// Close the active fifo and stop piping.
StopFifo,
/// Toggle betwen {Start|Stop}Fifo
ToggleFifo(String),
/// Log information message.
///
/// **Example:** `LogInfo: launching satellite`
@ -1363,6 +1374,9 @@ pub enum MsgOut {
EnableMouse,
DisableMouse,
ToggleMouse,
StartFifo(String),
StopFifo,
ToggleFifo(String),
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
@ -1720,6 +1734,9 @@ impl App {
ExternalMsg::EnableMouse => self.enable_mouse(),
ExternalMsg::DisableMouse => self.disable_mouse(),
ExternalMsg::ToggleMouse => self.toggle_mouse(),
ExternalMsg::StartFifo(f) => self.start_fifo(f),
ExternalMsg::StopFifo => self.stop_fifo(),
ExternalMsg::ToggleFifo(f) => self.toggle_fifo(f),
ExternalMsg::LogInfo(l) => self.log_info(l),
ExternalMsg::LogSuccess(l) => self.log_success(l),
ExternalMsg::LogWarning(l) => self.log_warning(l),
@ -2450,6 +2467,21 @@ impl App {
Ok(self)
}
fn start_fifo(mut self, path: String) -> Result<Self> {
self.msg_out.push_back(MsgOut::StartFifo(path));
Ok(self)
}
fn stop_fifo(mut self) -> Result<Self> {
self.msg_out.push_back(MsgOut::StopFifo);
Ok(self)
}
fn toggle_fifo(mut self, path: String) -> Result<Self> {
self.msg_out.push_back(MsgOut::ToggleFifo(path));
Ok(self)
}
pub fn log_info(mut self, message: String) -> Result<Self> {
self.logs_hidden = false;
self.logs.push(Log::new(LogLevel::Info, message));

@ -15,6 +15,7 @@ use crossterm::terminal as term;
use mlua::LuaSerdeExt;
use std::fs;
use std::io;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, ExitStatus, Stdio};
use std::sync::mpsc;
@ -153,6 +154,9 @@ impl Runner {
// let mut stdout = stdout.lock();
execute!(stdout, term::EnterAlternateScreen)?;
let mut fifo: Option<fs::File> = None;
let mut last_focus: Option<app::Node> = None;
let mut mouse_enabled = app.config().general().enable_mouse();
if mouse_enabled {
if let Err(e) = execute!(stdout, event::EnableMouseCapture) {
@ -238,6 +242,14 @@ impl Runner {
tx_pwd_watcher.send(app.pwd().clone())?;
// UI
terminal.draw(|f| ui::draw(f, &app, &lua))?;
// Fifo
let focus = app.focused_node();
if focus != last_focus.as_ref() {
if let Some(ref mut file) = fifo {
writeln!(file, "{}", app.focused_node_str())?;
};
last_focus = focus.cloned();
}
}
app::MsgOut::EnableMouse => {
@ -282,6 +294,41 @@ impl Runner {
}
}
app::MsgOut::StartFifo(path) => {
if let Some(file) = fifo {
fifo = None;
std::mem::drop(file);
}
match fs::OpenOptions::new().write(true).open(path) {
Ok(file) => fifo = Some(file),
Err(e) => {
app = app.log_error(e.to_string())?;
}
}
}
app::MsgOut::StopFifo => {
if let Some(file) = fifo {
fifo = None;
std::mem::drop(file);
}
}
app::MsgOut::ToggleFifo(path) => {
if let Some(file) = fifo {
fifo = None;
std::mem::drop(file);
} else {
match fs::OpenOptions::new().write(true).open(path) {
Ok(file) => fifo = Some(file),
Err(e) => {
app = app.log_error(e.to_string())?;
}
}
}
}
app::MsgOut::CallLuaSilently(func) => {
tx_event_reader.send(true)?;

Loading…
Cancel
Save