Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

Commit

Permalink
Merge pull request #247 from swsnr/resource-client
Browse files Browse the repository at this point in the history
Expose resource handling in API
  • Loading branch information
swsnr authored Apr 12, 2023
2 parents a62d9d1 + e5f53c9 commit e01485e
Show file tree
Hide file tree
Showing 11 changed files with 664 additions and 477 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ Use `cargo release` to create a new release.
- mdcat now fills paragraph text to the column limit, i.e. fills up short lines and wraps long lines (see [GH-4]).
- mdcat now allows to control color and style via a new `theme` field in `mdcat::Settings` of type `mdcat::Theme` (see [GH-48]).
`mdcat::Theme::default()` provides the standard mdcat 1.x colors and style.
- mdcat now exposes resource handling via the new `mdcat::resources::ResourceUrlHandler` trait (see [GH-247]).

### Changed
- Update all dependencies.
- `mdcat::Settings` now holds a reference to a syntax set, so the syntax set can now be shared among multiple different settings.

### Changed
- Explicitly set minimum rust version in `Cargo.toml`, and document MSRV policy.

### Removed
- `mdcat::Settings.resource_access` and the corresponding `ResourceAccess` enum (see [GH-247]).

[GH-4]: https://github.com/swsnr/mdcat/issues/4
[GH-48]: https://github.com/swsnr/mdcat/issues/48
[GH-247]: https://github.com/swsnr/mdcat/issues/247

## [1.1.1] – 2023-03-18

Expand Down
47 changes: 36 additions & 11 deletions src/bin/mdcat/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ use std::io::Result;
use std::io::{stdin, BufWriter};
use std::path::PathBuf;

use mdcat::resources::DispatchingResourceHandler;
use mdcat::resources::FileResourceHandler;
use mdcat::resources::HttpResourceHandler;
use mdcat::resources::ResourceUrlHandler;
use mdcat::resources::DEFAULT_RESOURCE_READ_LIMIT;
use mdcat::Theme;
use pulldown_cmark::{Options, Parser};
use syntect::parsing::SyntaxSet;
Expand All @@ -23,7 +28,6 @@ use tracing_subscriber::EnvFilter;

use crate::output::Output;
use mdcat::terminal::{TerminalProgram, TerminalSize};
use mdcat::ResourceAccess;
use mdcat::{Environment, Settings};

mod args;
Expand Down Expand Up @@ -52,8 +56,13 @@ fn read_input<T: AsRef<str>>(filename: T) -> Result<(PathBuf, String)> {
}
}

#[instrument(skip(output, settings), level = "debug")]
fn process_file(filename: &str, settings: &Settings, output: &mut Output) -> Result<()> {
#[instrument(skip(output, settings, resource_handler), level = "debug")]
fn process_file(
filename: &str,
settings: &Settings,
resource_handler: &dyn ResourceUrlHandler,
output: &mut Output,
) -> Result<()> {
let (base_dir, input) = read_input(filename)?;
event!(
Level::TRACE,
Expand All @@ -67,7 +76,7 @@ fn process_file(filename: &str, settings: &Settings, output: &mut Output) -> Res
let env = Environment::for_local_directory(&base_dir)?;

let mut sink = BufWriter::new(output.writer());
mdcat::push_tty(settings, &env, &mut sink, parser)
mdcat::push_tty(settings, &env, resource_handler, &mut sink, parser)
.and_then(|_| {
event!(Level::TRACE, "Finished rendering, flushing output");
sink.flush()
Expand Down Expand Up @@ -126,26 +135,42 @@ fn main() {
let settings = Settings {
terminal_capabilities: terminal.capabilities(),
terminal_size: TerminalSize { columns, ..size },
resource_access: if args.local_only {
ResourceAccess::LocalOnly
} else {
ResourceAccess::RemoteAllowed
},
syntax_set: &SyntaxSet::load_defaults_newlines(),
theme: Theme::default(),
};
let mut resource_handlers: Vec<Box<dyn ResourceUrlHandler>> = vec![Box::new(
FileResourceHandler::new(DEFAULT_RESOURCE_READ_LIMIT),
)];
if !args.local_only {
let user_agent =
concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
event!(
target: "mdcat::main",
Level::DEBUG,
"Remote resource access permitted, creating HTTP client with user agent {}",
user_agent
);
resource_handlers.push(Box::new(
HttpResourceHandler::with_user_agent(
DEFAULT_RESOURCE_READ_LIMIT,
user_agent,
)
// TODO: Properly return this error?
.unwrap(),
));
}
let resource_handler = DispatchingResourceHandler::new(resource_handlers);
event!(
target: "mdcat::main",
Level::TRACE,
?settings.terminal_size,
?settings.terminal_capabilities,
?settings.resource_access,
"settings"
);
args.filenames
.iter()
.try_fold(0, |code, filename| {
process_file(filename, &settings, &mut output)
process_file(filename, &settings, &resource_handler, &mut output)
.map(|_| code)
.or_else(|error| {
eprintln!("Error: {filename}: {error}");
Expand Down
26 changes: 17 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ use syntect::parsing::SyntaxSet;
use tracing::instrument;
use url::Url;

// Expose some select things for use in main
pub use crate::resources::ResourceAccess;
use crate::resources::ResourceUrlHandler;
use crate::terminal::capabilities::TerminalCapabilities;
use crate::terminal::TerminalSize;

// Expose some select things for use in main
pub use crate::theme::Theme;

mod references;
mod resources;
pub mod resources;
mod svg;
pub mod terminal;
mod theme;
Expand All @@ -46,8 +47,6 @@ pub struct Settings<'a> {
pub terminal_capabilities: TerminalCapabilities,
/// The size of the terminal mdcat writes to.
pub terminal_size: TerminalSize,
/// Whether remote resource access is permitted.
pub resource_access: ResourceAccess,
/// Syntax set for syntax highlighting of code blocks.
pub syntax_set: &'a SyntaxSet,
/// Colour theme for mdcat
Expand Down Expand Up @@ -112,6 +111,7 @@ impl Environment {
pub fn push_tty<'a, 'e, W, I>(
settings: &Settings,
environment: &Environment,
resource_handler: &dyn ResourceUrlHandler,
writer: &'a mut W,
mut events: I,
) -> Result<()>
Expand All @@ -123,7 +123,15 @@ where
let StateAndData(final_state, final_data) = events.try_fold(
StateAndData(State::default(), StateData::default()),
|StateAndData(state, data), event| {
write_event(writer, settings, environment, state, data, event)
write_event(
writer,
settings,
environment,
&resource_handler,
state,
data,
event,
)
},
)?;
finish(writer, settings, environment, final_state, final_data)
Expand All @@ -133,14 +141,16 @@ where
mod tests {
use pulldown_cmark::Parser;

use crate::resources::NoopResourceHandler;

use super::*;

fn render_string(input: &str, settings: &Settings) -> anyhow::Result<String> {
let source = Parser::new(input);
let mut sink = Vec::new();
let env =
Environment::for_local_directory(&std::env::current_dir().expect("Working directory"))?;
push_tty(settings, &env, &mut sink, source)?;
push_tty(settings, &env, &NoopResourceHandler, &mut sink, source)?;
Ok(String::from_utf8_lossy(&sink).into())
}

Expand All @@ -158,7 +168,6 @@ mod tests {
render_string(
markup,
&Settings {
resource_access: ResourceAccess::LocalOnly,
syntax_set: &SyntaxSet::default(),
terminal_capabilities: TerminalProgram::Dumb.capabilities(),
terminal_size: TerminalSize::default(),
Expand Down Expand Up @@ -303,7 +312,6 @@ Hello Donald[2]
render_string(
markup,
&Settings {
resource_access: ResourceAccess::LocalOnly,
syntax_set: &SyntaxSet::default(),
terminal_capabilities: TerminalProgram::Dumb.capabilities(),
terminal_size: TerminalSize::default(),
Expand Down
34 changes: 25 additions & 9 deletions src/render.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Sebastian Wiesner <[email protected]>
// Copyright Sebastian Wiesner <[email protected]>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
Expand All @@ -12,6 +12,7 @@ use std::io::Result;
use anstyle::Effects;
use anstyle::Style;
use anyhow::anyhow;
use anyhow::Context;
use pulldown_cmark::Event::*;
use pulldown_cmark::Tag::*;
use pulldown_cmark::{Event, LinkType};
Expand All @@ -22,6 +23,8 @@ use tracing::{event, instrument, Level};
use url::Url;

use crate::render::highlighting::HIGHLIGHTER;
use crate::resources::ResourceUrlHandler;
use crate::svg;
use crate::theme::CombineStyle;
use crate::{Environment, Settings};

Expand All @@ -42,11 +45,12 @@ pub use state::State;
pub use state::StateAndData;

#[allow(clippy::cognitive_complexity)]
#[instrument(level = "trace", skip(writer, settings, environment))]
#[instrument(level = "trace", skip(writer, settings, environment, resource_handler))]
pub fn write_event<'a, W: Write>(
writer: &mut W,
settings: &Settings,
environment: &Environment,
resource_handler: &dyn ResourceUrlHandler,
state: State,
data: StateData<'a>,
event: Event<'a>,
Expand Down Expand Up @@ -667,10 +671,19 @@ pub fn write_event<'a, W: Write>(
terminology.write_inline_image(writer, settings.terminal_size, url)?;
Some(RenderedImage)
}
(Some(ITerm2(iterm2)), Some(ref url)) => iterm2
.read_and_render(url, settings.resource_access)
(Some(ITerm2(iterm2)), Some(ref url)) =>
resource_handler
.read_resource(url)
.with_context(|| format!("Failed to read resource from {url}"))
.and_then(|mime_data| {
if mime_data.mime_type == Some(mime::IMAGE_SVG) {
svg::render_svg(&mime_data.data)
} else {
Ok(mime_data.data)
}
})
.map_err(|error| {
event!(Level::ERROR, ?error, %url, ?settings.resource_access, "failed to render image in iterm2: {:#}", error);
event!(Level::ERROR, ?error, %url, "failed to render image in iterm2: {:#}", error);
error
})
.and_then(|contents| {
Expand All @@ -692,10 +705,13 @@ pub fn write_event<'a, W: Write>(
anyhow!("Terminal pixel size not available")
})
.and_then(|size| {
let image = kitty.read_and_render(url, settings.resource_access, size).map_err(|error| {
event!(Level::ERROR, ?error, %url, ?settings.resource_access, "failed to render image in kitty: {:#}", error);
error
})?;
let image = resource_handler.read_resource(url)
.with_context(|| format!("Failed to read data from {url}"))
.and_then(|mime_data| kitty.render(url, mime_data, size))
.map_err(|error| {
event!(Level::ERROR, ?error, %url, "failed to render image in kitty: {:#}", error);
error
})?;
kitty.write_inline_image(writer, image).map_err(|error| {
event!(Level::ERROR, ?error, "failed to write iterm kitty: {:#}", error);
error
Expand Down
Loading

0 comments on commit e01485e

Please sign in to comment.