From 88d6bf80f5cdbbb90ead197bd41a67eb8c44e50e Mon Sep 17 00:00:00 2001 From: Rubén Beltrán del Río Date: Sat, 17 Jan 2026 11:22:22 +0100 Subject: Make clippy stricter and fix --- src/preferences/models.rs | 21 +++-- src/preferences/pages/editor.rs | 24 +++-- src/preferences/pages/general.rs | 2 +- src/preferences/pages/map.rs | 65 +++++++++---- src/preferences/pages/stages.rs | 78 ++++++++-------- src/preferences/pages/templates.rs | 16 ++-- src/preferences/window.rs | 187 ++++++++++++++++++++++--------------- 7 files changed, 238 insertions(+), 155 deletions(-) (limited to 'src/preferences') diff --git a/src/preferences/models.rs b/src/preferences/models.rs index dee84e6..81fa4d1 100644 --- a/src/preferences/models.rs +++ b/src/preferences/models.rs @@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; -/// Stage labels for custom stages (matches Swift Stage struct) +/// Stage labels for custom stages #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)] pub struct Stage { pub i: String, @@ -26,7 +26,7 @@ pub struct Stage { pub iv: String, } -/// Custom stage definition (matches Swift CustomStage) +/// Custom stage definition #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct CustomStage { @@ -73,7 +73,7 @@ impl CustomStage { } } -/// Template for new maps (matches Swift Template) +/// Template for new maps #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Template { @@ -106,7 +106,7 @@ impl Template { } } -/// JSON import/export format (matches Swift UserPreferencesJSON) +/// JSON import/export format /// All fields optional to support partial imports #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] @@ -136,6 +136,7 @@ pub struct UserPreferencesJson { /// Main preferences struct stored in app #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] +#[allow(clippy::struct_excessive_bools)] // These are independent boolean preferences, not a state machine pub struct UserPreferences { // Map preferences pub show_map_background: bool, @@ -218,10 +219,10 @@ impl UserPreferences { self.use_custom_font = *v; } if let Some(ref v) = json.custom_font_name { - self.custom_font_name = v.clone(); + self.custom_font_name.clone_from(v); } if let Some(ref v) = json.default_export_format { - self.default_export_format = v.clone(); + self.default_export_format.clone_from(v); } if let Some(v) = json.use_smart_label_positioning { self.use_smart_label_positioning = v; @@ -230,7 +231,7 @@ impl UserPreferences { self.use_custom_editor_font = *v; } if let Some(ref v) = json.custom_editor_font_name { - self.custom_editor_font_name = v.clone(); + self.custom_editor_font_name.clone_from(v); } if let Some(v) = json.editor_font_size { self.editor_font_size = v; @@ -239,13 +240,13 @@ impl UserPreferences { self.soft_wrap_lines = v; } if let Some(ref v) = json.map_templates { - self.map_templates = v.clone(); + self.map_templates.clone_from(v); } if let Some(ref v) = json.custom_stages { - self.custom_stages = v.clone(); + self.custom_stages.clone_from(v); } if let Some(ref v) = json.view_style { - self.view_style = v.clone(); + self.view_style.clone_from(v); } if let Some(v) = json.zoom { self.zoom = v; diff --git a/src/preferences/pages/editor.rs b/src/preferences/pages/editor.rs index d4acb94..336a488 100644 --- a/src/preferences/pages/editor.rs +++ b/src/preferences/pages/editor.rs @@ -33,7 +33,7 @@ pub struct EditorPage { } impl EditorPage { - pub fn new(preferences: &UserPreferences, sender: Sender) -> Self { + pub fn new(preferences: &UserPreferences, sender: &Sender) -> Self { let container = gtk::Box::new(gtk::Orientation::Vertical, 20); container.set_margin_top(20); container.set_margin_bottom(20); @@ -57,7 +57,9 @@ impl EditorPage { }); } font_size_box.append(&font_size_spin); - font_size_box.append(>k::Label::new(Some(&tr!("preferences.editor.font_size.unit")))); + font_size_box.append(>k::Label::new(Some(&tr!( + "preferences.editor.font_size.unit" + )))); container.append(&font_size_box); // Editor Style section @@ -68,7 +70,10 @@ impl EditorPage { container.append(&style_label); // Soft Wrap Lines - let soft_wrap_row = create_switch_row(&tr!("preferences.editor.editor_style.soft_wrap_lines"), preferences.soft_wrap_lines); + let soft_wrap_row = create_switch_row( + &tr!("preferences.editor.editor_style.soft_wrap_lines"), + preferences.soft_wrap_lines, + ); let soft_wrap_switch = soft_wrap_row.1.clone(); { let sender = sender.clone(); @@ -80,8 +85,10 @@ impl EditorPage { container.append(&soft_wrap_row.0); // Use Custom Font - let custom_font_row = - create_switch_row(&tr!("preferences.editor.editor_style.use_custom_font"), preferences.use_custom_editor_font); + let custom_font_row = create_switch_row( + &tr!("preferences.editor.editor_style.use_custom_font"), + preferences.use_custom_editor_font, + ); let custom_font_switch = custom_font_row.1.clone(); container.append(&custom_font_row.0); @@ -90,6 +97,8 @@ impl EditorPage { font_row.append(>k::Label::new(Some(&tr!("preferences.editor.font")))); let font_button = gtk::FontButton::new(); + + #[allow(clippy::cast_possible_truncation)] font_button.set_font(&format!( "{} {}", preferences.custom_editor_font_name, preferences.editor_font_size as i32 @@ -140,15 +149,16 @@ impl EditorPage { pub fn sync_from(&self, preferences: &UserPreferences) { self.font_size_spin.set_value(preferences.editor_font_size); - self.soft_wrap_switch.set_active(preferences.soft_wrap_lines); + self.soft_wrap_switch + .set_active(preferences.soft_wrap_lines); self.custom_font_switch .set_active(preferences.use_custom_editor_font); self.font_button .set_sensitive(preferences.use_custom_editor_font); + #[allow(clippy::cast_possible_truncation)] // Font size is always a small positive number self.font_button.set_font(&format!( "{} {}", preferences.custom_editor_font_name, preferences.editor_font_size as i32 )); } } - diff --git a/src/preferences/pages/general.rs b/src/preferences/pages/general.rs index d70e9e6..ad15c82 100644 --- a/src/preferences/pages/general.rs +++ b/src/preferences/pages/general.rs @@ -28,7 +28,7 @@ pub struct GeneralPage { } impl GeneralPage { - pub fn new(sender: Sender) -> Self { + pub fn new(sender: &Sender) -> Self { let container = gtk::Box::new(gtk::Orientation::Vertical, 20); container.set_margin_top(20); container.set_margin_bottom(20); diff --git a/src/preferences/pages/map.rs b/src/preferences/pages/map.rs index 5ffd04a..4355c6f 100644 --- a/src/preferences/pages/map.rs +++ b/src/preferences/pages/map.rs @@ -34,7 +34,7 @@ pub struct MapPage { } impl MapPage { - pub fn new(preferences: &UserPreferences, sender: Sender) -> Self { + pub fn new(preferences: &UserPreferences, sender: &Sender) -> Self { let container = gtk::Box::new(gtk::Orientation::Vertical, 20); container.set_margin_top(20); container.set_margin_bottom(20); @@ -42,15 +42,36 @@ impl MapPage { container.set_margin_end(20); container.set_valign(gtk::Align::Start); - // Map Style section + let (show_background_switch, smart_positioning_switch, custom_font_switch, font_button) = + Self::init_style_section(&container, preferences, sender); + + let export_format_dropdown = Self::init_export_section(&container, preferences, sender); + + Self { + container, + show_background_switch, + smart_positioning_switch, + custom_font_switch, + font_button, + export_format_dropdown, + } + } + + fn init_style_section( + container: >k::Box, + preferences: &UserPreferences, + sender: &Sender, + ) -> (gtk::Switch, gtk::Switch, gtk::Switch, gtk::FontButton) { let style_label = gtk::Label::new(Some(&tr!("preferences.map.map_style.title"))); style_label.add_css_class("heading"); style_label.set_halign(gtk::Align::Start); container.append(&style_label); // Show Background - let background_row = - create_switch_row(&tr!("preferences.map.map_style.show_background"), preferences.show_map_background); + let background_row = create_switch_row( + &tr!("preferences.map.map_style.show_background"), + preferences.show_map_background, + ); let show_background_switch = background_row.1.clone(); { let sender = sender.clone(); @@ -77,7 +98,10 @@ impl MapPage { container.append(&smart_row.0); // Use Custom Font - let custom_font_row = create_switch_row(&tr!("preferences.map.map_style.use_custom_font"), preferences.use_custom_font); + let custom_font_row = create_switch_row( + &tr!("preferences.map.map_style.use_custom_font"), + preferences.use_custom_font, + ); let custom_font_switch = custom_font_row.1.clone(); container.append(&custom_font_row.0); @@ -115,7 +139,19 @@ impl MapPage { }); } - // Export section + ( + show_background_switch, + smart_positioning_switch, + custom_font_switch, + font_button, + ) + } + + fn init_export_section( + container: >k::Box, + preferences: &UserPreferences, + sender: &Sender, + ) -> gtk::DropDown { let export_label = gtk::Label::new(Some(&tr!("preferences.map.export.title"))); export_label.add_css_class("heading"); export_label.set_halign(gtk::Align::Start); @@ -123,9 +159,12 @@ impl MapPage { container.append(&export_label); let export_row = gtk::Box::new(gtk::Orientation::Horizontal, 10); - export_row.append(>k::Label::new(Some(&tr!("preferences.map.export.default_format")))); + export_row.append(>k::Label::new(Some(&tr!( + "preferences.map.export.default_format" + )))); - let formats = gtk::StringList::new(&[&tr!("export_formats.png"), &tr!("export_formats.svg")]); + let formats = + gtk::StringList::new(&[&tr!("export_formats.png"), &tr!("export_formats.svg")]); let export_format_dropdown = gtk::DropDown::new(Some(formats), None::); let selected = match preferences.default_export_format.as_str() { "svg" => 1, @@ -145,14 +184,7 @@ impl MapPage { export_row.append(&export_format_dropdown); container.append(&export_row); - Self { - container, - show_background_switch, - smart_positioning_switch, - custom_font_switch, - font_button, - export_format_dropdown, - } + export_format_dropdown } pub fn widget(&self) -> gtk::Box { @@ -176,4 +208,3 @@ impl MapPage { self.export_format_dropdown.set_selected(selected); } } - diff --git a/src/preferences/pages/stages.rs b/src/preferences/pages/stages.rs index 9f0685d..4bd24e1 100644 --- a/src/preferences/pages/stages.rs +++ b/src/preferences/pages/stages.rs @@ -60,25 +60,25 @@ impl StagesPage { name_header.set_xalign(0.0); header_row.append(&name_header); - let i_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_i"))); - i_header.set_width_chars(12); - i_header.set_xalign(0.0); - header_row.append(&i_header); - - let ii_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_ii"))); - ii_header.set_width_chars(12); - ii_header.set_xalign(0.0); - header_row.append(&ii_header); - - let iii_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_iii"))); - iii_header.set_width_chars(12); - iii_header.set_xalign(0.0); - header_row.append(&iii_header); - - let iv_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_iv"))); - iv_header.set_width_chars(12); - iv_header.set_xalign(0.0); - header_row.append(&iv_header); + let first_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_i"))); + first_header.set_width_chars(12); + first_header.set_xalign(0.0); + header_row.append(&first_header); + + let second_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_ii"))); + second_header.set_width_chars(12); + second_header.set_xalign(0.0); + header_row.append(&second_header); + + let third_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_iii"))); + third_header.set_width_chars(12); + third_header.set_xalign(0.0); + header_row.append(&third_header); + + let fourth_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_iv"))); + fourth_header.set_width_chars(12); + fourth_header.set_xalign(0.0); + header_row.append(&fourth_header); // Spacer for delete button column let spacer = gtk::Box::new(gtk::Orientation::Horizontal, 0); @@ -172,12 +172,12 @@ impl StagesPage { hbox.append(&name_entry); // Stage I entry - let i_entry = gtk::Entry::new(); - i_entry.set_text(&stage.i); - i_entry.set_width_chars(12); + let first_entry = gtk::Entry::new(); + first_entry.set_text(&stage.i); + first_entry.set_width_chars(12); { let sender = self.sender.clone(); - i_entry.connect_changed(move |entry| { + first_entry.connect_changed(move |entry| { sender.emit(PreferencesInput::SetCustomStageLabel( id, StageLabel::I, @@ -185,15 +185,15 @@ impl StagesPage { )); }); } - hbox.append(&i_entry); + hbox.append(&first_entry); // Stage II entry - let ii_entry = gtk::Entry::new(); - ii_entry.set_text(&stage.ii); - ii_entry.set_width_chars(12); + let second_entry = gtk::Entry::new(); + second_entry.set_text(&stage.ii); + second_entry.set_width_chars(12); { let sender = self.sender.clone(); - ii_entry.connect_changed(move |entry| { + second_entry.connect_changed(move |entry| { sender.emit(PreferencesInput::SetCustomStageLabel( id, StageLabel::Ii, @@ -201,15 +201,15 @@ impl StagesPage { )); }); } - hbox.append(&ii_entry); + hbox.append(&second_entry); // Stage III entry - let iii_entry = gtk::Entry::new(); - iii_entry.set_text(&stage.iii); - iii_entry.set_width_chars(12); + let third_entry = gtk::Entry::new(); + third_entry.set_text(&stage.iii); + third_entry.set_width_chars(12); { let sender = self.sender.clone(); - iii_entry.connect_changed(move |entry| { + third_entry.connect_changed(move |entry| { sender.emit(PreferencesInput::SetCustomStageLabel( id, StageLabel::Iii, @@ -217,15 +217,15 @@ impl StagesPage { )); }); } - hbox.append(&iii_entry); + hbox.append(&third_entry); // Stage IV entry - let iv_entry = gtk::Entry::new(); - iv_entry.set_text(&stage.iv); - iv_entry.set_width_chars(12); + let fourth_entry = gtk::Entry::new(); + fourth_entry.set_text(&stage.iv); + fourth_entry.set_width_chars(12); { let sender = self.sender.clone(); - iv_entry.connect_changed(move |entry| { + fourth_entry.connect_changed(move |entry| { sender.emit(PreferencesInput::SetCustomStageLabel( id, StageLabel::Iv, @@ -233,7 +233,7 @@ impl StagesPage { )); }); } - hbox.append(&iv_entry); + hbox.append(&fourth_entry); // Delete button let delete_button = gtk::Button::from_icon_name("list-remove-symbolic"); diff --git a/src/preferences/pages/templates.rs b/src/preferences/pages/templates.rs index acc679f..1760085 100644 --- a/src/preferences/pages/templates.rs +++ b/src/preferences/pages/templates.rs @@ -78,9 +78,9 @@ impl TemplatesPage { { let sender = sender.clone(); add_button.connect_clicked(move |_| { - sender.emit(PreferencesInput::AddTemplate( - tr!("dialog.template.default_label"), - )); + sender.emit(PreferencesInput::AddTemplate(tr!( + "dialog.template.default_label" + ))); }); } button_box.append(&add_button); @@ -226,7 +226,7 @@ impl TemplatesPage { self.list_box.connect_row_selected(move |_, row| { if let Some(row) = row { - let index = row.index() as usize; + let index: usize = row.index().try_into().unwrap_or(0); if let Some(template) = templates.get(index) { *selected_id.borrow_mut() = Some(template.id); editor_buffer.set_text(&template.content); @@ -251,7 +251,8 @@ impl TemplatesPage { default_button.set_tooltip_text(Some(&tr!("preferences.templates.help.default"))); } else { default_button.set_icon_name("radio-symbolic"); - default_button.set_tooltip_text(Some(&tr!("preferences.templates.help.set_as_default"))); + default_button + .set_tooltip_text(Some(&tr!("preferences.templates.help.set_as_default"))); } default_button.add_css_class("flat"); { @@ -271,7 +272,10 @@ impl TemplatesPage { let sender = self.sender.clone(); let id = template.id; name_entry.connect_changed(move |entry| { - sender.emit(PreferencesInput::SetTemplateName(id, entry.text().to_string())); + sender.emit(PreferencesInput::SetTemplateName( + id, + entry.text().to_string(), + )); }); } hbox.append(&name_entry); diff --git a/src/preferences/window.rs b/src/preferences/window.rs index 2118056..0997716 100644 --- a/src/preferences/window.rs +++ b/src/preferences/window.rs @@ -143,9 +143,9 @@ impl SimpleComponent for PreferencesWindow { root: Self::Root, sender: ComponentSender, ) -> ComponentParts { - let general_page = general::GeneralPage::new(sender.input_sender().clone()); - let editor_page = editor::EditorPage::new(&preferences, sender.input_sender().clone()); - let map_page = map::MapPage::new(&preferences, sender.input_sender().clone()); + let general_page = general::GeneralPage::new(&sender.input_sender().clone()); + let editor_page = editor::EditorPage::new(&preferences, &sender.input_sender().clone()); + let map_page = map::MapPage::new(&preferences, &sender.input_sender().clone()); let stages_page = stages::StagesPage::new(&preferences, sender.input_sender().clone()); let templates_page = templates::TemplatesPage::new(&preferences, sender.input_sender().clone()); @@ -167,7 +167,6 @@ impl SimpleComponent for PreferencesWindow { fn update(&mut self, message: Self::Input, sender: ComponentSender) { match message { - // General page actions PreferencesInput::Export => { general::show_export_dialog(sender.input_sender(), &self.window); } @@ -188,8 +187,6 @@ impl SimpleComponent for PreferencesWindow { self.sync_ui_from_preferences(); self.save_and_notify(&sender); } - - // Map preferences PreferencesInput::SetShowMapBackground(v) => { self.preferences.show_map_background = v; self.save_and_notify(&sender); @@ -210,8 +207,6 @@ impl SimpleComponent for PreferencesWindow { self.preferences.use_smart_label_positioning = v; self.save_and_notify(&sender); } - - // Editor preferences PreferencesInput::SetUseCustomEditorFont(v) => { self.preferences.use_custom_editor_font = v; self.save_and_notify(&sender); @@ -228,88 +223,29 @@ impl SimpleComponent for PreferencesWindow { self.preferences.soft_wrap_lines = v; self.save_and_notify(&sender); } - - // Templates - PreferencesInput::AddTemplate(name) => { - let template = super::models::Template::new(name, String::new(), false); - self.preferences.map_templates.push(template); - self.templates_page.refresh(&self.preferences); - self.save_and_notify(&sender); - } - PreferencesInput::RemoveTemplate(id) => { - self.preferences.map_templates.retain(|t| t.id != id); - self.templates_page.refresh(&self.preferences); - self.save_and_notify(&sender); - } + PreferencesInput::AddTemplate(name) => self.handle_add_template(name, &sender), + PreferencesInput::RemoveTemplate(id) => self.handle_remove_template(id, &sender), PreferencesInput::SetTemplateContent(id, content) => { - if let Some(template) = self - .preferences - .map_templates - .iter_mut() - .find(|t| t.id == id) - { - template.content = content; - self.save_and_notify(&sender); - } + self.handle_set_template_content(id, content, &sender); } PreferencesInput::SetTemplateName(id, name) => { - if let Some(template) = self - .preferences - .map_templates - .iter_mut() - .find(|t| t.id == id) - { - template.name = name; - self.templates_page.refresh(&self.preferences); - self.save_and_notify(&sender); - } + self.handle_set_template_name(id, name, &sender); } PreferencesInput::SetDefaultTemplate(id) => { self.preferences.set_default_template(id); self.templates_page.refresh(&self.preferences); self.save_and_notify(&sender); } - - // Custom stages - PreferencesInput::AddCustomStage => { - let stage = super::models::CustomStage::placeholder_default(); - self.preferences.custom_stages.push(stage); - self.stages_page.refresh(&self.preferences); - self.save_and_notify(&sender); - } + PreferencesInput::AddCustomStage => self.handle_add_custom_stage(&sender), PreferencesInput::RemoveCustomStage(id) => { - self.preferences.custom_stages.retain(|s| s.id != id); - self.stages_page.refresh(&self.preferences); - self.save_and_notify(&sender); + self.handle_remove_custom_stage(id, &sender); } PreferencesInput::SetCustomStageName(id, name) => { - if let Some(stage) = self - .preferences - .custom_stages - .iter_mut() - .find(|s| s.id == id) - { - stage.name = name; - self.save_and_notify(&sender); - } + self.handle_set_custom_stage_name(id, name, &sender); } PreferencesInput::SetCustomStageLabel(id, label, value) => { - if let Some(stage) = self - .preferences - .custom_stages - .iter_mut() - .find(|s| s.id == id) - { - match label { - StageLabel::I => stage.stage.i = value, - StageLabel::Ii => stage.stage.ii = value, - StageLabel::Iii => stage.stage.iii = value, - StageLabel::Iv => stage.stage.iv = value, - } - self.save_and_notify(&sender); - } + self.handle_set_custom_stage_label(id, label, value, &sender); } - PreferencesInput::Close => { sender.output(PreferencesOutput::Closed).ok(); } @@ -333,4 +269,105 @@ impl PreferencesWindow { self.stages_page.refresh(&self.preferences); self.templates_page.refresh(&self.preferences); } + + fn handle_add_template(&mut self, name: String, sender: &ComponentSender) { + let template = super::models::Template::new(name, String::new(), false); + self.preferences.map_templates.push(template); + self.templates_page.refresh(&self.preferences); + self.save_and_notify(sender); + } + + fn handle_remove_template(&mut self, id: uuid::Uuid, sender: &ComponentSender) { + self.preferences.map_templates.retain(|t| t.id != id); + self.templates_page.refresh(&self.preferences); + self.save_and_notify(sender); + } + + fn handle_set_template_content( + &mut self, + id: uuid::Uuid, + content: String, + sender: &ComponentSender, + ) { + if let Some(template) = self + .preferences + .map_templates + .iter_mut() + .find(|t| t.id == id) + { + template.content = content; + self.save_and_notify(sender); + } + } + + fn handle_set_template_name( + &mut self, + id: uuid::Uuid, + name: String, + sender: &ComponentSender, + ) { + if let Some(template) = self + .preferences + .map_templates + .iter_mut() + .find(|t| t.id == id) + { + template.name = name; + self.templates_page.refresh(&self.preferences); + self.save_and_notify(sender); + } + } + + fn handle_add_custom_stage(&mut self, sender: &ComponentSender) { + let stage = super::models::CustomStage::placeholder_default(); + self.preferences.custom_stages.push(stage); + self.stages_page.refresh(&self.preferences); + self.save_and_notify(sender); + } + + fn handle_remove_custom_stage(&mut self, id: uuid::Uuid, sender: &ComponentSender) { + self.preferences.custom_stages.retain(|s| s.id != id); + self.stages_page.refresh(&self.preferences); + self.save_and_notify(sender); + } + + fn handle_set_custom_stage_name( + &mut self, + id: uuid::Uuid, + name: String, + sender: &ComponentSender, + ) { + if let Some(stage) = self + .preferences + .custom_stages + .iter_mut() + .find(|s| s.id == id) + { + stage.name = name; + self.save_and_notify(sender); + } + } + + fn handle_set_custom_stage_label( + &mut self, + id: uuid::Uuid, + label: StageLabel, + value: String, + sender: &ComponentSender, + ) { + if let Some(stage) = self + .preferences + .custom_stages + .iter_mut() + .find(|s| s.id == id) + { + match label { + StageLabel::I => stage.stage.i = value, + StageLabel::Ii => stage.stage.ii = value, + StageLabel::Iii => stage.stage.iii = value, + StageLabel::Iv => stage.stage.iv = value, + } + self.save_and_notify(sender); + } + } } -- cgit