Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: patch cover colors #96

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::log_on_error;
use ansi_to_tui::IntoText;
use color_eyre::eyre::bail;
use config::Config;
use cover_renderer::render_cover;
use logging::Logger;
use patch_hub::lore::{lore_api_client::BlockingLoreAPIClient, lore_session, patch::Patch};
use patch_renderer::{render_patch_preview, PatchRenderer};
Expand All @@ -19,6 +20,7 @@ use std::collections::HashMap;
use crate::utils;

mod config;
pub mod cover_renderer;
pub mod logging;
pub mod patch_renderer;
pub mod screens;
Expand Down Expand Up @@ -140,18 +142,31 @@ impl App {
let mut patches_preview: Vec<Text> = Vec::new();
for raw_patch in &raw_patches {
let raw_patch = raw_patch.replace('\t', " ");
let patch_preview =
match render_patch_preview(&raw_patch, self.config.patch_renderer()) {

let (raw_cover, raw_patch) = lore_session::split_cover(&raw_patch);

let rendered_cover = match render_cover(raw_cover, self.config.cover_renderer())
{
Ok(render) => render,
Err(_) => {
Logger::error("Failed to render cover preview with external program");
raw_cover.to_string()
}
};

let rendered_patch =
match render_patch_preview(raw_patch, self.config.patch_renderer()) {
Ok(render) => render,
Err(_) => {
Logger::error(
"Failed to render patch preview with external program",
);
raw_patch
raw_patch.to_string()
}
}
.into_text()?;
patches_preview.push(patch_preview);
};

patches_preview
.push(format!("{}---\n{}", rendered_cover, rendered_patch).into_text()?);
}
self.patchset_details_and_actions_state = Some(PatchsetDetailsAndActionsState {
representative_patch,
Expand Down Expand Up @@ -254,6 +269,9 @@ impl App {
if let Ok(patch_renderer) = edit_config.extract_patch_renderer() {
self.config.set_patch_renderer(patch_renderer.into())
}
if let Ok(cover_renderer) = edit_config.extract_cover_renderer() {
self.config.set_cover_renderer(cover_renderer.into())
}
if let Ok(max_log_age) = edit_config.max_log_age() {
self.config.set_max_log_age(max_log_age)
}
Expand Down
9 changes: 8 additions & 1 deletion src/app/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{
path::Path,
};

use super::patch_renderer::PatchRenderer;
use super::{cover_renderer::CoverRenderer, patch_renderer::PatchRenderer};

#[cfg(test)]
mod tests;
Expand All @@ -29,6 +29,8 @@ pub struct Config {
data_dir: String,
/// Renderer to use for patch previews
patch_renderer: PatchRenderer,
/// Renderer to use for patchset covers
cover_renderer: CoverRenderer,
/// Maximum age of a log file in days
max_log_age: usize,
}
Expand All @@ -47,6 +49,7 @@ impl Config {
logs_path: format!("{data_dir}/logs"),
git_send_email_options: "--dry-run --suppress-cc=all".to_string(),
patch_renderer: Default::default(),
cover_renderer: Default::default(),
cache_dir,
data_dir,
max_log_age: 30,
Expand Down Expand Up @@ -144,6 +147,10 @@ impl Config {
self.patch_renderer = patch_renderer;
}

pub fn set_cover_renderer(&mut self, cover_renderer: CoverRenderer) {
self.cover_renderer = cover_renderer;
}

pub fn set_max_log_age(&mut self, max_log_age: usize) {
self.max_log_age = max_log_age;
}
Expand Down
78 changes: 78 additions & 0 deletions src/app/cover_renderer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use std::{
fmt::Display,
io::Write,
process::{Command, Stdio},
};

use serde::{Deserialize, Serialize};

use super::logging::Logger;

#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default)]
pub enum CoverRenderer {
#[default]
#[serde(rename = "default")]
Default,
#[serde(rename = "bat")]
Bat,
}

impl From<String> for CoverRenderer {
fn from(value: String) -> Self {
match value.as_str() {
"bat" => CoverRenderer::Bat,
_ => CoverRenderer::Default,
}
}
}

impl From<&str> for CoverRenderer {
fn from(value: &str) -> Self {
match value {
"bat" => CoverRenderer::Bat,
_ => CoverRenderer::Default,
}
}
}

impl Display for CoverRenderer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CoverRenderer::Default => write!(f, "default"),
CoverRenderer::Bat => write!(f, "bat"),
}
}
}

pub fn render_cover(raw: &str, renderer: &CoverRenderer) -> color_eyre::Result<String> {
let text = match renderer {
CoverRenderer::Default => Ok(raw.to_string()),
CoverRenderer::Bat => bat_cover_renderer(raw),
}?;

Ok(text)
}

/// Renders a .mbx cover using the `bat` command line tool.
///
/// # Errors
///
/// If bat isn't installed or if the command fails, an error will be returned.
fn bat_cover_renderer(patch: &str) -> color_eyre::Result<String> {
let mut bat = Command::new("bat")
.arg("-pp")
.arg("-f")
.arg("-l")
.arg("mbx")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.map_err(|e| {
Logger::error(format!("Failed to spawn bat for cover preview: {}", e));
e
})?;

bat.stdin.as_mut().unwrap().write_all(patch.as_bytes())?;
let output = bat.wait_with_output()?;
Ok(String::from_utf8(output.stdout)?)
}
16 changes: 15 additions & 1 deletion src/app/screens/edit_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ impl EditConfigState {
EditableConfig::PatchRenderer,
config.patch_renderer().to_string(),
);
config_buffer.insert(
EditableConfig::CoverRenderer,
config.cover_renderer().to_string(),
);
config_buffer.insert(EditableConfig::MaxLogAge, config.max_log_age().to_string());

EditConfigState {
Expand Down Expand Up @@ -172,6 +176,11 @@ impl EditConfigState {
Ok(patch_renderer)
}

pub fn extract_cover_renderer(&mut self) -> Result<String, ()> {
let cover_renderer = self.extract_config_buffer_val(&EditableConfig::CoverRenderer);
Ok(cover_renderer)
}

/// Extracts the max log age from the config
///
/// # Errors
Expand All @@ -195,6 +204,7 @@ enum EditableConfig {
DataDir,
GitSendEmailOpt,
PatchRenderer,
CoverRenderer,
MaxLogAge,
}

Expand All @@ -208,7 +218,8 @@ impl TryFrom<usize> for EditableConfig {
2 => Ok(EditableConfig::DataDir),
3 => Ok(EditableConfig::GitSendEmailOpt),
4 => Ok(EditableConfig::PatchRenderer),
5 => Ok(EditableConfig::MaxLogAge),
5 => Ok(EditableConfig::CoverRenderer),
6 => Ok(EditableConfig::MaxLogAge),
_ => bail!("Invalid index {} for EditableConfig", value), // Handle out of bounds
}
}
Expand All @@ -223,6 +234,9 @@ impl Display for EditableConfig {
EditableConfig::PatchRenderer => {
write!(f, "Patch Renderer (bat, delta, diff-so-fancy)")
}
EditableConfig::CoverRenderer => {
write!(f, "Cover Renderer (bat)")
}
EditableConfig::GitSendEmailOpt => write!(f, "`git send email` option"),
EditableConfig::MaxLogAge => write!(f, "Max Log Age (0 = forever)"),
}
Expand Down
15 changes: 15 additions & 0 deletions src/lore/lore_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,21 @@ pub fn split_patchset(patchset_path_str: &str) -> Result<Vec<String>, String> {
Ok(patches)
}

/// Takes the string that represents a patch and splits it into the cover and the actual diff.
///
/// The cover is everything before the first "---" line.
pub fn split_cover(patch: &str) -> (&str, &str) {
let mut cover: &str = patch;
let mut diff: &str = "";

if let Some(cover_end) = patch.find("\n---\n") {
cover = &patch[..cover_end + 1];
diff = &patch[cover_end + 5..];
}

(cover, diff)
}

fn extract_patches(mbox_path: &Path, patches: &mut Vec<String>) {
let mut current_patch: String = String::new();
let mut is_reading_patch: bool = false;
Expand Down
1 change: 1 addition & 0 deletions src/test_samples/app/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"cache_dir": "/cache_dir",
"data_dir": "/data_dir",
"patch_renderer": "default",
"cover_renderer": "default",
"max_log_age": 42
}