summaryrefslogtreecommitdiff
path: root/src/renderers
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-01-23 09:42:09 +0800
committer魏曹先生 <1992414357@qq.com>2026-01-23 09:42:09 +0800
commitf9fa7d65d775959efbc9609ccafd1fdce76129e4 (patch)
tree111fc1933cfbe4bdc4e82207f53b6c1b74cc35e3 /src/renderers
parentaee17b68b2b213553cd06406a3a5713ec91f374d (diff)
Add localization and refactor status command output
Diffstat (limited to 'src/renderers')
-rw-r--r--src/renderers/status.rs252
1 files changed, 248 insertions, 4 deletions
diff --git a/src/renderers/status.rs b/src/renderers/status.rs
index 0bf1c5c..d51252e 100644
--- a/src/renderers/status.rs
+++ b/src/renderers/status.rs
@@ -1,18 +1,262 @@
+use rust_i18n::t;
+
use crate::{
- outputs::status::JVStatusResult,
+ outputs::status::{JVStatusOutput, JVStatusWrongModifyReason},
r_println,
systems::cmd::{
errors::CmdRenderError,
renderer::{JVRenderResult, JVResultRenderer},
},
+ utils::{
+ display::{SimpleTable, md},
+ env::auto_update_outdate,
+ },
};
pub struct JVStatusRenderer;
-impl JVResultRenderer<JVStatusResult> for JVStatusRenderer {
- async fn render(_data: &JVStatusResult) -> Result<JVRenderResult, CmdRenderError> {
+enum Mode {
+ StructuralChangesMode,
+ ContentChangesMode,
+ Clean,
+}
+
+impl JVResultRenderer<JVStatusOutput> for JVStatusRenderer {
+ async fn render(data: &JVStatusOutput) -> Result<JVRenderResult, CmdRenderError> {
let mut r = JVRenderResult::default();
- r_println!(r, "Nothing");
+
+ // Render Header
+ render_header(&mut r, data);
+
+ // Render Info and Mode
+ render_info_and_mode(&mut r, data);
+
+ // Render Hint
+ render_hint(&mut r, data);
+
Ok(r)
}
}
+
+fn render_header(r: &mut JVRenderResult, data: &JVStatusOutput) {
+ let account = &data.current_account;
+ let sheet = &data.current_sheet;
+ r_println!(
+ r,
+ "{}",
+ md(t!("status.header", account = account, sheet = sheet))
+ );
+}
+
+fn render_info_and_mode(r: &mut JVRenderResult, data: &JVStatusOutput) {
+ let mut info_erased = String::default();
+ let mut info_moved = String::default();
+ let mut info_lost = String::default();
+ let mut info_created = String::default();
+ let mut info_modified = String::default();
+
+ // Collect erased items
+ if !data.analyzed_result.erased.is_empty() {
+ info_erased.push_str(format!("{}\n", md(t!("status.info_display.erased.header"))).as_str());
+ for erased in data.analyzed_result.erased.iter() {
+ info_erased.push_str(
+ format!(
+ "{}\n",
+ md(t!(
+ "status.info_display.erased.item",
+ item = erased.display()
+ ))
+ )
+ .as_str(),
+ );
+ }
+ }
+
+ // Collect moved items
+ if !data.analyzed_result.moved.is_empty() {
+ let mut table = SimpleTable::new(vec![
+ format!("{}", md(t!("status.info_display.moved.header"))),
+ "".to_string(),
+ ]);
+ for (_, (from, to)) in data.analyzed_result.moved.iter() {
+ table.push_item(vec![
+ format!(
+ "{}",
+ md(t!("status.info_display.moved.left", left = from.display()))
+ ),
+ format!(
+ "{}",
+ md(t!("status.info_display.moved.right", right = to.display()))
+ ),
+ ]);
+ }
+ info_moved.push_str(table.to_string().as_str());
+ }
+
+ // Collect lost items
+ if !data.analyzed_result.lost.is_empty() {
+ info_lost.push_str(format!("{}\n", md(t!("status.info_display.lost.header"))).as_str());
+ for lost in data.analyzed_result.lost.iter() {
+ info_lost.push_str(
+ format!(
+ "{}\n",
+ md(t!("status.info_display.lost.item", item = lost.display()))
+ )
+ .as_str(),
+ );
+ }
+ }
+
+ // Collect created items
+ if !data.analyzed_result.created.is_empty() {
+ info_created
+ .push_str(format!("{}\n", md(t!("status.info_display.created.header"))).as_str());
+ for created in data.analyzed_result.created.iter() {
+ info_created.push_str(
+ format!(
+ "{}\n",
+ md(t!(
+ "status.info_display.created.item",
+ item = created.display()
+ ))
+ )
+ .as_str(),
+ );
+ }
+ }
+
+ // Collect modified items
+ if !data.analyzed_result.modified.is_empty() {
+ info_modified
+ .push_str(format!("{}\n", md(t!("status.info_display.modified.header"))).as_str());
+ for modified in data.analyzed_result.modified.iter() {
+ if let Some(reason) = data.wrong_modified_items.get(modified) {
+ let reason_str = match reason {
+ JVStatusWrongModifyReason::BaseVersionMismatch {
+ base_version,
+ latest_version,
+ } => md(t!(
+ "status.info_display.modified.reason.base_version_mismatch",
+ base_version = base_version,
+ latest_version = latest_version
+ )),
+ JVStatusWrongModifyReason::ModifiedButNotHeld { holder } => md(t!(
+ "status.info_display.modified.reason.modified_but_not_held",
+ holder = holder
+ )),
+ JVStatusWrongModifyReason::NoHolder => {
+ md(t!("status.info_display.modified.reason.no_holder"))
+ }
+ };
+ info_modified.push_str(
+ format!(
+ "{}\n",
+ md(t!(
+ "status.info_display.modified.item_wrong",
+ item = modified.display(),
+ reason = reason_str
+ ))
+ )
+ .as_str(),
+ );
+ continue;
+ }
+ info_modified.push_str(
+ format!(
+ "{}\n",
+ md(t!(
+ "status.info_display.modified.item",
+ item = modified.display()
+ ))
+ )
+ .as_str(),
+ );
+ }
+ }
+
+ let structural_info = vec![info_erased, info_moved, info_lost].join("\n");
+ let content_info = vec![info_created, info_modified].join("\n");
+
+ let mode = get_mode(data);
+ match mode {
+ Mode::StructuralChangesMode => {
+ r_println!(
+ r,
+ "{}",
+ md(t!("status.current_mode.structural", info = structural_info))
+ );
+ }
+ Mode::ContentChangesMode => {
+ r_println!(
+ r,
+ "{}",
+ md(t!("status.current_mode.content", info = content_info))
+ );
+ }
+ Mode::Clean => r_println!(r, "{}", md(t!("status.current_mode.clean"))),
+ }
+}
+
+fn render_hint(r: &mut JVRenderResult, data: &JVStatusOutput) {
+ // Outdate Hint
+ let update_time = &data.update_time;
+ let now_time = &data.now_time;
+ let duration_minutes: i64 = (now_time
+ .duration_since(*update_time)
+ .unwrap_or_default()
+ .as_secs()
+ / 60) as i64;
+ let outdate_minutes = auto_update_outdate();
+
+ // Outdated
+ if duration_minutes > outdate_minutes {
+ let hours = duration_minutes / 60;
+ let minutes = duration_minutes % 60;
+ let seconds = (now_time
+ .duration_since(*update_time)
+ .unwrap_or_default()
+ .as_secs()
+ % 60) as i64;
+
+ r_println!(
+ r,
+ "{}",
+ md(t!(
+ "status.hints.outdate",
+ h = hours,
+ m = minutes,
+ s = seconds
+ ))
+ );
+ }
+
+ let in_ref_sheet = &data.in_ref_sheet;
+ let is_host_mode = &data.is_host_mode;
+
+ // Readonly
+ if *in_ref_sheet && !is_host_mode {
+ r_println!(r, "{}", md(t!("status.hints.readonly")));
+ }
+
+ // Host
+ if *is_host_mode {
+ r_println!(r, "{}", md(t!("status.hints.host")));
+ }
+}
+
+fn get_mode(data: &JVStatusOutput) -> Mode {
+ let analyzed = &data.analyzed_result;
+
+ // If there are any lost, moved, or erased items, use structural changes mode
+ if !analyzed.moved.is_empty() || !analyzed.lost.is_empty() || !analyzed.erased.is_empty() {
+ Mode::StructuralChangesMode
+ }
+ // Otherwise, if there are any created or modified items, use content changes mode
+ else if !analyzed.created.is_empty() || !analyzed.modified.is_empty() {
+ Mode::ContentChangesMode
+ }
+ // Otherwise, it's clean
+ else {
+ Mode::Clean
+ }
+}