Skip to content

Commit

Permalink
adding ad_repl
Browse files Browse the repository at this point in the history
  • Loading branch information
sminez committed Nov 13, 2024
1 parent 877835b commit 2f718ec
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 233 deletions.
43 changes: 35 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions crates/ad_client/examples/event_filter.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use ad_client::{Client, EventFilter, Outcome};
use std::error::Error;
use ad_client::{Client, EventFilter, Outcome, Source};
use std::io;

fn main() -> Result<(), Box<dyn Error>> {
fn main() -> io::Result<()> {
let mut client = Client::new()?;
client.open(".")?;
let buffer = client.current_buffer()?;
Expand All @@ -15,11 +15,12 @@ struct Filter;
impl EventFilter for Filter {
fn handle_load(
&mut self,
_src: Source,
from: usize,
to: usize,
txt: &str,
_client: &mut Client,
) -> Result<Outcome, Box<dyn std::error::Error>> {
) -> io::Result<Outcome> {
println!("got load: {from}->{to} {txt:?}");
match txt {
"README.md" => Ok(Outcome::Passthrough),
Expand Down
78 changes: 35 additions & 43 deletions crates/ad_client/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Handling of event filtering
use crate::Client;
use ad_event::{FsysEvent, Kind};
use std::error::Error;
use ad_event::{FsysEvent, Kind, Source};
use std::io;

/// Outcome of handling an event within an [EventFilter]
#[derive(Debug)]
Expand All @@ -16,9 +16,6 @@ pub enum Outcome {
Exit,
}

// FIXME: once the tagging of events in the editor is working correctly this should have methods
// that are specificy to the source (Mouse / Keyboard / Fsys) rather than just the kind.

/// An event filter takes control over a buffer's events file and handles processing the events
/// that come through. Any events without a corresponding handler are written back to ad for
/// internal processing.
Expand All @@ -27,86 +24,81 @@ pub trait EventFilter {
/// Handle text being inserted into the buffer body
fn handle_insert(
&mut self,
src: Source,
from: usize,
to: usize,
txt: &str,
client: &mut Client,
) -> Result<Outcome, Box<dyn Error>> {
Ok(Outcome::Passthrough)
) -> io::Result<Outcome> {
Ok(Outcome::Handled)
}

/// Handle text being deleted from the buffer body
fn handle_delete(
&mut self,
src: Source,
from: usize,
to: usize,
client: &mut Client,
) -> Result<Outcome, Box<dyn Error>> {
Ok(Outcome::Passthrough)
) -> io::Result<Outcome> {
Ok(Outcome::Handled)
}

/// Handle a load event in the body
fn handle_load(
&mut self,
src: Source,
from: usize,
to: usize,
txt: &str,
client: &mut Client,
) -> Result<Outcome, Box<dyn Error>> {
) -> io::Result<Outcome> {
Ok(Outcome::Passthrough)
}

/// Handle an execute event in the body
fn handle_execute(
&mut self,
src: Source,
from: usize,
to: usize,
txt: &str,
client: &mut Client,
) -> Result<Outcome, Box<dyn Error>> {
) -> io::Result<Outcome> {
Ok(Outcome::Passthrough)
}
}

pub(crate) fn run_filter<F>(
buffer: &str,
mut filter: F,
client: &mut Client,
) -> Result<(), Box<dyn Error>>
pub(crate) fn run_filter<F>(buffer: &str, mut filter: F, client: &mut Client) -> io::Result<()>
where
F: EventFilter,
{
let mut buf = String::new();
for line in client.event_lines(buffer)? {
buf.push_str(&line);
let evts = match FsysEvent::try_from_str(&buf) {
Ok(evts) => evts,
Err(_) => continue,
};
buf.clear();
let evt = FsysEvent::try_from_str(&line)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;

for evt in evts.into_iter() {
let outcome = match evt.kind {
Kind::LoadBody => filter.handle_load(evt.ch_from, evt.ch_to, &evt.txt, client)?,
Kind::ExecuteBody => {
filter.handle_execute(evt.ch_from, evt.ch_to, &evt.txt, client)?
}
Kind::InsertBody => {
filter.handle_insert(evt.ch_from, evt.ch_to, &evt.txt, client)?
}
Kind::DeleteBody => filter.handle_delete(evt.ch_from, evt.ch_to, client)?,
_ => Outcome::Passthrough,
};
let outcome = match evt.kind {
Kind::LoadBody => {
filter.handle_load(evt.source, evt.ch_from, evt.ch_to, &evt.txt, client)?
}
Kind::ExecuteBody => {
filter.handle_execute(evt.source, evt.ch_from, evt.ch_to, &evt.txt, client)?
}
Kind::InsertBody => {
filter.handle_insert(evt.source, evt.ch_from, evt.ch_to, &evt.txt, client)?
}
Kind::DeleteBody => filter.handle_delete(evt.source, evt.ch_from, evt.ch_to, client)?,
_ => Outcome::Passthrough,
};

match outcome {
Outcome::Handled => (),
Outcome::Passthrough => client.write_event(buffer, &evt.as_event_file_line())?,
Outcome::PassthroughAndExit => {
client.write_event(buffer, &evt.as_event_file_line())?;
return Ok(());
}
Outcome::Exit => return Ok(()),
match outcome {
Outcome::Handled => (),
Outcome::Passthrough => client.write_event(buffer, &evt.as_event_file_line())?,
Outcome::PassthroughAndExit => {
client.write_event(buffer, &evt.as_event_file_line())?;
return Ok(());
}
Outcome::Exit => return Ok(()),
}
}

Expand Down
58 changes: 46 additions & 12 deletions crates/ad_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
clippy::undocumented_unsafe_blocks
)]
use ninep::client::{ReadLineIter, UnixClient};
use std::{error::Error, io, os::unix::net::UnixStream};
use std::{io, io::Write, os::unix::net::UnixStream};

mod event;

pub use ad_event::Source;
pub use event::{EventFilter, Outcome};

/// A simple 9p client for ad
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Client {
inner: UnixClient,
}
Expand Down Expand Up @@ -102,9 +103,9 @@ impl Client {
self._write_buffer_file(buffer, "dot", 0, content.as_bytes())
}

/// Write the provided string to the specified offset in the given buffer.
pub fn write_body(&mut self, buffer: &str, offset: u64, content: &str) -> io::Result<usize> {
self._write_buffer_file(buffer, "body", offset, content.as_bytes())
/// Append the provided string to the given buffer.
pub fn append_to_body(&mut self, buffer: &str, content: &str) -> io::Result<usize> {
self._write_buffer_file(buffer, "body", 0, content.as_bytes())
}

/// Set the addr of the given buffer.
Expand All @@ -113,16 +114,17 @@ impl Client {
}

/// Replace the xdot of the given buffer with the provided string.
pub fn write_xdot(&mut self, buffer: &str, offset: u64, content: &str) -> io::Result<usize> {
self._write_buffer_file(buffer, "xdot", offset, content.as_bytes())
pub fn write_xdot(&mut self, buffer: &str, content: &str) -> io::Result<usize> {
self._write_buffer_file(buffer, "xdot", 0, content.as_bytes())
}

/// Set the xaddr of the given buffer.
pub fn write_xaddr(&mut self, buffer: &str, content: &str) -> io::Result<usize> {
self._write_buffer_file(buffer, "xaddr", 0, content.as_bytes())
}

fn _ctl(&mut self, command: &str, args: &str) -> io::Result<()> {
/// Send a control message to ad.
pub fn ctl(&mut self, command: &str, args: &str) -> io::Result<()> {
self.inner
.write("ctl", 0, format!("{command} {args}").as_bytes())?;

Expand All @@ -131,24 +133,56 @@ impl Client {

/// Echo a string message in the status line.
pub fn echo(&mut self, msg: impl AsRef<str>) -> io::Result<()> {
self._ctl("echo", msg.as_ref())
self.ctl("echo", msg.as_ref())
}

/// Open the requested file.
pub fn open(&mut self, path: impl AsRef<str>) -> io::Result<()> {
self._ctl("open", path.as_ref())
self.ctl("open", path.as_ref())
}

/// Open the requested file in a new window.
pub fn open_in_new_window(&mut self, path: impl AsRef<str>) -> io::Result<()> {
self.ctl("open-in-new-window", path.as_ref())
}

/// Reload the currently active buffer.
pub fn reload_current_buffer(&mut self) -> io::Result<()> {
self._ctl("reload", "")
self.ctl("reload", "")
}

/// Run a provided [EventFilter] until it exits or errors
pub fn run_event_filter<F>(&mut self, buffer: &str, filter: F) -> Result<(), Box<dyn Error>>
pub fn run_event_filter<F>(&mut self, buffer: &str, filter: F) -> io::Result<()>
where
F: EventFilter,
{
event::run_filter(buffer, filter, self)
}

/// Create a [Write] impl that can be used to continuously write to the given path
pub fn body_writer(&self, bufid: &str) -> io::Result<impl Write> {
let client = UnixClient::new_unix("ad", "")?;

Ok(BodyWriter {
path: format!("buffers/{bufid}/body"),
client,
})
}
}

/// A writer for appending to the body of a buffer
#[derive(Debug)]
pub struct BodyWriter {
path: String,
client: UnixClient,
}

impl Write for BodyWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.client.write(&self.path, 0, buf)
}

fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
2 changes: 2 additions & 0 deletions crates/ad_event/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ keywords = [ "terminal", "editor", "text-editor", ]
categories = [ "development-tools", "text-editors", "command-line-utilities" ]

[dependencies]
serde = { version = "1.0.214", features = ["derive"] }
serde_json = "1.0.132"

[dev-dependencies]
simple_test_case = "1"
Loading

0 comments on commit 2f718ec

Please sign in to comment.