Skip to content

Commit

Permalink
feat: patch cover colors
Browse files Browse the repository at this point in the history
This uses similar design for patch rendering. The cover of a patch is
everything before the `---` line that separates the email part of a
patch and the actual diff.

Currently, only `bat` was configured as an option besides the `default`

This also includes a config option for the cover renderer

Closes: #71

Signed-off-by: OJarrisonn <j.h.m.t.v.10@gmail.com>
Reviewed-by: David Tadokoro <davidbtadokoro@usp.br>
Signed-off-by: David Tadokoro <davidbtadokoro@usp.br>
  • Loading branch information
OJarrisonn authored and davidbtadokoro committed Nov 27, 2024
1 parent b73e85a commit 48d87bc
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 8 deletions.
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, ui::popup::PopUp};
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 @@ -164,18 +166,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.details_actions = Some(DetailsActions {
representative_patch,
Expand Down Expand Up @@ -283,6 +298,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 EditConfig {
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());

EditConfig {
Expand Down Expand Up @@ -172,6 +176,11 @@ impl EditConfig {
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
}

0 comments on commit 48d87bc

Please sign in to comment.