Skip to content

Commit

Permalink
refactor(tui): separate the changelog generate/write logic
Browse files Browse the repository at this point in the history
  • Loading branch information
orhun committed Dec 1, 2024
1 parent f1af005 commit 42d0ac7
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 103 deletions.
46 changes: 26 additions & 20 deletions git-cliff-core/src/changelog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,38 @@ use std::time::{
};

/// Changelog generator.
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Changelog<'a> {
/// Releases that the changelog will contain.
pub releases: Vec<Release<'a>>,
/// Configuration.
pub config: Config,
header_template: Option<Template>,
body_template: Template,
footer_template: Option<Template>,
config: &'a Config,
additional_context: HashMap<String, serde_json::Value>,
}

impl<'a> Changelog<'a> {
/// Constructs a new instance.
pub fn new(releases: Vec<Release<'a>>, config: &'a Config) -> Result<Self> {
let mut changelog = Changelog::build(releases, config)?;
changelog.add_remote_data()?;
changelog.process_commits();
changelog.process_releases();
Ok(changelog)
}

/// Builds a changelog from releases and config.
fn build(releases: Vec<Release<'a>>, config: &'a Config) -> Result<Self> {
///
/// Processes the commits/releases and fetches the remote data
/// if `process_data` is set to `true`.
pub fn new(
releases: Vec<Release<'a>>,
config: Config,
process_data: bool,
) -> Result<Self> {
let trim = config.changelog.trim.unwrap_or(true);
Ok(Self {
let mut changelog = Self {
releases,
header_template: match &config.changelog.header {
Some(header) => {
Some(Template::new("header", header.to_string(), trim)?)
}
None => None,
},
body_template: get_body_template(config, trim)?,
body_template: get_body_template(&config, trim)?,
footer_template: match &config.changelog.footer {
Some(footer) => {
Some(Template::new("footer", footer.to_string(), trim)?)
Expand All @@ -69,12 +68,18 @@ impl<'a> Changelog<'a> {
},
config,
additional_context: HashMap::new(),
})
};
if process_data {
changelog.add_remote_data()?;
changelog.process_commits();
changelog.process_releases();
}
Ok(changelog)
}

/// Constructs an instance from a serialized context object.
pub fn from_context<R: Read>(input: &mut R, config: &'a Config) -> Result<Self> {
Changelog::build(serde_json::from_reader(input)?, config)
pub fn from_context<R: Read>(input: &mut R, config: Config) -> Result<Self> {
Changelog::new(serde_json::from_reader(input)?, config, false)
}

/// Adds a key value pair to the template context.
Expand Down Expand Up @@ -431,6 +436,7 @@ impl<'a> Changelog<'a> {

/// Adds information about the remote to the template context.
pub fn add_remote_context(&mut self) -> Result<()> {
debug!("Adding remote context...");
self.additional_context.insert(
"remote".to_string(),
serde_json::to_value(self.config.remote.clone())?,
Expand Down Expand Up @@ -1024,7 +1030,7 @@ mod test {
#[test]
fn changelog_generator() -> Result<()> {
let (config, releases) = get_test_data();
let mut changelog = Changelog::new(releases, &config)?;
let mut changelog = Changelog::new(releases, config, true)?;
changelog.bump_version()?;
changelog.releases[0].timestamp = 0;
let mut out = Vec::new();
Expand Down Expand Up @@ -1143,7 +1149,7 @@ chore(deps): fix broken deps
",
),
));
let changelog = Changelog::new(releases, &config)?;
let changelog = Changelog::new(releases, config, true)?;
let mut out = Vec::new();
changelog.generate(&mut out)?;
assert_eq!(
Expand Down Expand Up @@ -1247,7 +1253,7 @@ chore(deps): fix broken deps
{% endfor %}{% endfor %}"#
.to_string(),
);
let mut changelog = Changelog::new(releases, &config)?;
let mut changelog = Changelog::new(releases, config, true)?;
changelog.add_context("custom_field", "Hello")?;
let mut out = Vec::new();
changelog.generate(&mut out)?;
Expand Down
2 changes: 1 addition & 1 deletion git-cliff-core/src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use tera::{
};

/// Wrapper for [`Tera`].
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Template {
/// Template name.
name: String,
Expand Down
10 changes: 7 additions & 3 deletions git-cliff-tui/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,21 @@ pub fn handle_key_events(
KeyCode::Char('c') | KeyCode::Char('C') => {
if key_event.modifiers == KeyModifiers::CONTROL {
state.quit();
} else if let Some(clipboard) = &mut state.clipboard {
if let Err(e) = clipboard.set_contents(state.changelog.clone()) {
eprintln!("Failed to set clipboard contents: {e}");
} else if let Some(contents) = state.get_changelog_contents()? {
if let Some(clipboard) = &mut state.clipboard {
if let Err(e) = clipboard.set_contents(contents) {
eprintln!("Failed to set clipboard contents: {e}");
}
}
}
}
KeyCode::Char('k') | KeyCode::Char('K') | KeyCode::Up => {
state.list_state.select_previous();
state.process_changelog()?;
}
KeyCode::Char('j') | KeyCode::Char('J') | KeyCode::Down => {
state.list_state.select_next();
state.process_changelog()?;
}
KeyCode::Char('h') | KeyCode::Char('H') | KeyCode::Left => {
state.markdown.scroll_index =
Expand Down
72 changes: 36 additions & 36 deletions git-cliff-tui/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use std::{
path::{
Path,
PathBuf,
},
thread,
use std::path::{
Path,
PathBuf,
};

use crate::{
Expand Down Expand Up @@ -60,6 +57,9 @@ fn main() -> Result<()> {
}
}

// Generate the changelog.
state.generate_changelog()?;

// Initialize the terminal user interface.
let events = EventHandler::new(250);
let mut terminal = ratatui::init();
Expand Down Expand Up @@ -104,37 +104,37 @@ fn main() -> Result<()> {
Event::Mouse(_) => {}
Event::Resize(_, _) => {}
Event::Generate | Event::AutoGenerate => {
if event == Event::AutoGenerate && !state.autoload {
continue;
}
let sender = events.sender.clone();
let args = state.args.clone();
state.is_generating = true;
state.args.config = PathBuf::from(
state.configs[state.list_state.selected().unwrap_or_default()]
.file
.clone(),
);
thread::spawn(move || {
let mut output = Vec::new();
sender
.send(match git_cliff::run(args, &mut output) {
Ok(()) => Event::RenderMarkdown(
String::from_utf8_lossy(&output).to_string(),
),
Err(e) => Event::Error(e.to_string()),
})
.expect("failed to send event");
});
// if event == Event::AutoGenerate && !state.autoload {
// continue;
// }
// let sender = events.sender.clone();
// let args = state.args.clone();
// state.is_generating = true;
// state.args.config = PathBuf::from(
// state.configs[state.list_state.selected().
// unwrap_or_default()] .file
// .clone(),
// );
// thread::spawn(move || {
// let mut output = Vec::new();
// sender
// .send(match git_cliff::run(args, &mut output) {
// Ok(()) => Event::RenderMarkdown(
// String::from_utf8_lossy(&output).to_string(),
// ),
// Err(e) => Event::Error(e.to_string()),
// })
// .expect("failed to send event");
// });
}
Event::RenderMarkdown(changelog) => {
state.is_generating = false;
state.changelog = changelog;
state.markdown.component = Some(md_tui::parser::parse_markdown(
None,
&state.changelog,
state.markdown.area.width,
));
Event::RenderMarkdown(_) => {
// state.is_generating = false;
// state.changelog = changelog;
// state.markdown.component =
// Some(md_tui::parser::parse_markdown( None,
// &state.changelog,
// state.markdown.area.width,
// ));
}
Event::Error(e) => {
state.error = Some(e);
Expand Down
54 changes: 49 additions & 5 deletions git-cliff-tui/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use copypasta::ClipboardContext;
use git_cliff::args::Args;
use git_cliff::core::changelog::Changelog;
use git_cliff::core::embed::BuiltinConfig;
use md_tui::nodes::root::ComponentRoot;
use ratatui::layout::Rect;
Expand Down Expand Up @@ -32,7 +33,7 @@ pub struct Markdown {

/// Is the application running?
/// Application state.
pub struct State {
pub struct State<'a> {
/// git-cliff arguments.
pub args: Args,
/// Is the application running?
Expand All @@ -41,8 +42,8 @@ pub struct State {
pub configs: Vec<Config>,
/// The state of the list.
pub list_state: ListState,
/// Changelog contents.
pub changelog: String,
/// Changelog.
pub changelog: Option<Changelog<'a>>,
/// Error message.
pub error: Option<String>,
/// Rendered markdown.
Expand All @@ -59,7 +60,7 @@ pub struct State {
pub is_generating: bool,
}

impl State {
impl<'a> State<'a> {
/// Constructs a new instance.
pub fn new(args: Args) -> Result<Self> {
let configs = BuiltinConfig::iter()
Expand All @@ -78,7 +79,7 @@ impl State {
list_state.select_first();
list_state
},
changelog: String::new(),
changelog: None,
error: None,
markdown: Markdown::default(),
autoload: true,
Expand All @@ -93,6 +94,49 @@ impl State {
})
}

/// Generates the changelog.
pub fn generate_changelog(&mut self) -> Result<()> {
self.changelog = Some(git_cliff::generate_changelog(&mut self.args)?);
Ok(())
}

/// Returns the changelog contents.
pub fn get_changelog_contents(&mut self) -> Result<Option<String>> {
if let Some(changelog) = &self.changelog {
let config = git_cliff::core::embed::BuiltinConfig::parse(
self.configs[self.list_state.selected().unwrap_or_default()]
.file
.clone(),
)?
.0;
let changelog =
Changelog::new(changelog.releases.clone(), config.clone(), false)?;
let mut output = Vec::new();
git_cliff::write_changelog(
self.args.clone(),
changelog.clone(),
&mut output,
)?;
let contents = String::from_utf8(output)?;
self.changelog = Some(changelog);
Ok(Some(contents))
} else {
Ok(None)
}
}

/// Processes the changelog contents.
pub fn process_changelog(&mut self) -> Result<()> {
if let Some(contents) = &self.get_changelog_contents()? {
self.markdown.component = Some(md_tui::parser::parse_markdown(
None,
&contents,
self.markdown.area.width,
));
}
Ok(())
}

/// Handles the tick event of the terminal.
pub fn tick(&mut self) {
if self.is_generating {
Expand Down
Loading

0 comments on commit 42d0ac7

Please sign in to comment.