-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
I've been thinking of ideas for the library API that can provide more powerful functionality, while also reducing how much of the bat internals are exposed. Feedback would be appreciated.
I think we should rework/refactor input sourcing for bat
-as-a-library. The current implementation only allows specifying input sources (via InputFile
) from STDIN, the filesystem, and the embedded preview string.
For an API, we should have something a bit more generalized:
- Accepts any
Read
trait as an input source. - Accepts any string as an input source.
- Contains custom "properties" (see below)
- Contains metadata (e.g. syntax name, file name, file encoding, etc.)
Properties:
For extensibility, there should be some way to add extra fields ("properties") to an input source. This would allow features to be implemented cleanly without significantly modifying the internal code. One example would be moving the git change data into a property, and passing the property to the Decoration
impl instead of the InteractivePrinter
.
There are a couple ways we could implement this:
Generics:
We could make everything generic, and put all the properties in a single struct.
This would be fairly performant since all the hard work is done at compile-time, but it wouldn't work well when mixing external code (e.g. custom decorations) with built-in features.
HashMap<&'static str, Any>:
Rather than having to know everything at compile-time, we could use a hashmap of Any
. This would allow us to split off parts of bat
into cargo features (e.g. git support), and allows for mixing and matching of various types of properties.
Both the HashMap
and Any
will incur a runtime performance hit, but that could easily be mitigated by using a builder that reads and caches the data once per input source:
trait SomethingBuilder {
fn create(&mut self, input: &Input) -> Box<dyn Something>;
}
struct MySomethingBuilder {}
impl SomethingBuilder for MySomethingBuilder {
fn create(&mut self, input: &Input) -> Box<dyn Something> {
Something::new(
input.properties()
.get("thing")
.and_then(|v| v.downcast_ref::<Thing>())
.unwrap()
)
}
}