Further improve the API.

This improves the compatibility and adds the ability to introduce
non-breaking changes by using a builder pattern.

Example:

```rust
fn main() {
    match xplr::runner(None).and_then(|a| a.run()) {
        Ok(Some(out)) => print!("{}", out),
        Ok(None) => {}
        Err(err) => {
            if !err.to_string().is_empty() {
                eprintln!("error: {}", err);
            };

            std::process::exit(1);
        }
    }
}
```
pull/229/head
Arijit Basu 3 years ago committed by Arijit Basu
parent fd3e8a5a9f
commit 2962a8d52d

@ -1,6 +1,5 @@
fn main() {
let pwd = std::path::PathBuf::from("/");
match xplr::run(pwd, None, None) {
match xplr::runner(None).and_then(|a| a.run()) {
Ok(Some(out)) => print!("{}", out),
Ok(None) => {}
Err(err) => {

@ -4,7 +4,7 @@ use crate::explorer;
use crate::input::Key;
use crate::lua;
use crate::permissions::Permissions;
use crate::runner;
use crate::runner::Runner;
use crate::ui::Layout;
use anyhow::{bail, Result};
use chrono::{DateTime, Local};
@ -1595,6 +1595,8 @@ impl App {
last_modes: Default::default(),
};
fs::create_dir_all(app.session_path())?;
if let Some(err) = load_err {
app.log_error(err)
} else {
@ -2796,24 +2798,8 @@ impl App {
last_modes: self.last_modes.clone(),
}
}
pub fn run(self, focused_path: Option<PathBuf>, lua: &mlua::Lua) -> Result<Option<String>> {
runner::run(self, focused_path, lua)
}
}
/// Run xplr TUI
pub fn run(
pwd: PathBuf,
focused_path: Option<PathBuf>,
on_load: Option<Vec<ExternalMsg>>,
) -> Result<Option<String>> {
let lua = mlua::Lua::new();
let mut app = App::create(pwd, &lua)?;
if let Some(msgs) = on_load {
for msg in msgs {
app = app.enqueue(Task::new(MsgIn::External(msg), None));
}
}
app.run(focused_path, &lua)
pub fn runner(path: Option<PathBuf>) -> Result<Runner> {
Runner::new(path)
}

@ -108,17 +108,10 @@ fn main() {
} else if cli.version {
println!("xplr {}", xplr::app::VERSION);
} else {
let mut pwd = PathBuf::from(cli.path.unwrap_or_else(|| ".".into()))
.canonicalize()
.unwrap_or_default();
let mut focused_path = None;
if pwd.is_file() {
focused_path = pwd.file_name().map(|p| p.into());
pwd = pwd.parent().map(|p| p.into()).unwrap_or_else(|| ".".into());
}
match app::run(pwd, focused_path, Some(cli.on_load)) {
match app::runner(cli.path.as_ref().map(PathBuf::from))
.map(|a| a.with_on_load(cli.on_load))
.and_then(|a| a.run())
{
Ok(Some(out)) => print!("{}", out),
Ok(None) => {}
Err(err) => {

@ -15,4 +15,4 @@ pub mod pwd_watcher;
pub mod runner;
pub mod ui;
pub use app::run;
pub use app::runner;

@ -86,11 +86,38 @@ fn call(app: &app::App, cmd: app::Command, silent: bool) -> io::Result<ExitStatu
.status()
}
pub(crate) fn run(
mut app: app::App,
pub struct Runner {
pwd: PathBuf,
focused_path: Option<PathBuf>,
lua: &mlua::Lua,
) -> Result<Option<String>> {
on_load: Vec<app::ExternalMsg>,
}
impl Runner {
pub(crate) fn new(path: Option<PathBuf>) -> Result<Self> {
let mut pwd = path.unwrap_or_else(|| ".".into()).canonicalize()?;
let mut focused_path = None;
if pwd.is_file() {
focused_path = pwd.file_name().map(|p| p.into());
pwd = pwd.parent().map(|p| p.into()).unwrap_or_else(|| ".".into());
}
Ok(Self {
pwd,
focused_path,
on_load: Default::default(),
})
}
pub fn with_on_load(mut self, on_load: Vec<app::ExternalMsg>) -> Self {
self.on_load = on_load;
self
}
pub fn run(self) -> Result<Option<String>> {
let lua = mlua::Lua::new();
let mut app = app::App::create(self.pwd, &lua)?;
fs::create_dir_all(app.session_path())?;
let (tx_msg_in, rx_msg_in) = mpsc::channel();
@ -99,7 +126,8 @@ pub(crate) fn run(
app = app.explore_pwd()?;
app = if let Some(f) = focused_path
app = if let Some(f) = self
.focused_path
.clone()
.map(|f| f.to_string_lossy().to_string())
{
@ -111,7 +139,7 @@ pub(crate) fn run(
explorer::explore_recursive_async(
app.explorer_config().clone(),
app.pwd().into(),
focused_path,
self.focused_path,
app.directory_buffer().map(|d| d.focus()).unwrap_or(0),
tx_msg_in.clone(),
);
@ -142,6 +170,11 @@ pub(crate) fn run(
pwd_watcher::keep_watching(app.pwd(), tx_msg_in.clone(), rx_pwd_watcher)?;
// pipe_reader::keep_reading(app.pipe().msg_in().clone(), tx_msg_in.clone());
// Enqueue on_load messages
for msg in self.on_load {
tx_msg_in.send(app::Task::new(app::MsgIn::External(msg), None))?;
}
'outer: for task in rx_msg_in {
match app.handle_task(task) {
Ok(a) => {
@ -209,7 +242,10 @@ pub(crate) fn run(
app::MsgOut::EnableMouse => {
if !mouse_enabled {
match execute!(terminal.backend_mut(), event::EnableMouseCapture) {
match execute!(
terminal.backend_mut(),
event::EnableMouseCapture
) {
Ok(_) => {
mouse_enabled = true;
}
@ -226,13 +262,16 @@ pub(crate) fn run(
} else {
app::ExternalMsg::EnableMouse
};
app =
app.handle_task(app::Task::new(app::MsgIn::External(msg), None))?;
app = app
.handle_task(app::Task::new(app::MsgIn::External(msg), None))?;
}
app::MsgOut::DisableMouse => {
if mouse_enabled {
match execute!(terminal.backend_mut(), event::DisableMouseCapture) {
match execute!(
terminal.backend_mut(),
event::DisableMouseCapture
) {
Ok(_) => {
mouse_enabled = false;
}
@ -333,7 +372,10 @@ pub(crate) fn run(
tx_event_reader.send(false)?;
if mouse_enabled {
match execute!(terminal.backend_mut(), event::EnableMouseCapture) {
match execute!(
terminal.backend_mut(),
event::EnableMouseCapture
) {
Ok(_) => {
mouse_enabled = true;
}
@ -392,7 +434,10 @@ pub(crate) fn run(
tx_event_reader.send(false)?;
if mouse_enabled {
match execute!(terminal.backend_mut(), event::EnableMouseCapture) {
match execute!(
terminal.backend_mut(),
event::EnableMouseCapture
) {
Ok(_) => {
mouse_enabled = true;
}
@ -424,3 +469,4 @@ pub(crate) fn run(
result
}
}

Loading…
Cancel
Save