From 4623c9ff1eea873b242a12a68d0db116f8164c1d Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Thu, 26 Mar 2026 18:04:00 +0000 Subject: [PATCH 01/48] feat(libmsa): funcs for constant filtering --- libmsa/src/error.rs | 3 + libmsa/src/filter.rs | 146 +++++++++++++++++++++++++++++++++++--- libmsa/src/metrics.rs | 84 ++++++++++++++++++++++ libmsa/src/translation.rs | 2 +- 4 files changed, 226 insertions(+), 9 deletions(-) diff --git a/libmsa/src/error.rs b/libmsa/src/error.rs index 8123a94..84fed4f 100644 --- a/libmsa/src/error.rs +++ b/libmsa/src/error.rs @@ -57,6 +57,9 @@ pub enum AlignmentError { /// A gap-filter threshold was outside the supported finite range. #[error("invalid gap fraction: {0} (expected a finite value in 0.0..=1.0)")] InvalidGapFraction(f32), + /// A constant-filter threshold was outside the supported finite range. + #[error("invalid constant fraction: {0} (expected a finite value in 0.0..=1.0)")] + InvalidConstantFraction(f32), /// A regex row-name filter could not be compiled. #[error("invalid regex '{pattern}'")] InvalidRegex { diff --git a/libmsa/src/filter.rs b/libmsa/src/filter.rs index cdf6284..7c4d179 100644 --- a/libmsa/src/filter.rs +++ b/libmsa/src/filter.rs @@ -16,13 +16,15 @@ use crate::projection::Projection; /// 1. Regex - rows not matching [`Self::with_row_regex`] are removed. /// 2. Exclusion - explicit excludes ([`Self::without_rows`]) are removed last. /// -/// Column filters ([`Self::with_max_gap_fraction`]) run over the final row set. +/// Column filters ([`Self::with_max_gap_fraction`], [`Self::with_min_constant_fraction`]) run +/// over the final row set. #[derive(Debug, Clone)] pub struct FilterBuilder<'a> { source: &'a Alignment, row_exclude_sets: Vec>, row_name_regex: Option, max_gap_fraction: Option, + min_constant_fraction: Option, } impl<'a> FilterBuilder<'a> { @@ -49,6 +51,12 @@ impl<'a> FilterBuilder<'a> { self } + /// Keeps only columns whose dominant counted symbol fraction is below `threshold`. + pub fn with_min_constant_fraction(mut self, threshold: f32) -> Self { + self.min_constant_fraction = Some(threshold); + self + } + /// Resolves all filters and builds a new [`Alignment`] pub fn apply(self) -> Result { let row_count = self.source.row_count(); @@ -60,6 +68,9 @@ impl<'a> FilterBuilder<'a> { if let Some(max_gap_fraction) = self.max_gap_fraction { validate_gap_fraction(max_gap_fraction)?; } + if let Some(min_constant_fraction) = self.min_constant_fraction { + validate_constant_fraction(min_constant_fraction)?; + } let mut row_ids: Vec = (0..row_count).collect(); if let Some(pattern) = &self.row_name_regex { @@ -80,20 +91,31 @@ impl<'a> FilterBuilder<'a> { row_ids.retain(|&row_id| membership[row_id]); let mut column_ids: Vec = (0..column_count).collect(); - if let Some(max_gap_fraction) = self.max_gap_fraction { + if self.max_gap_fraction.is_some() || self.min_constant_fraction.is_some() { let temp_rows = Projection::Filtered(Arc::from(row_ids.as_slice())); - let gap_fractions = metrics::counted_columns_range( + let columns = metrics::counted_columns_range( &self.source.data, &temp_rows, &self.source.columns, 0..column_count, - ) - .map(|columns| metrics::gap_fraction_from_columns(&columns))?; + )?; column_ids.retain(|&column_id| { - gap_fractions - .get(column_id) - .is_none_or(|(_, gap_fraction)| *gap_fraction <= max_gap_fraction) + columns.get(column_id).is_none_or(|column| { + let gap_ok = self.max_gap_fraction.is_none_or(|max_gap_fraction| { + metrics::gap_fraction_from_counts(&column.counts) <= max_gap_fraction + }); + let constant_ok = + self.min_constant_fraction + .is_none_or(|min_constant_fraction| { + metrics::max_counted_symbol_fraction_from_counts( + &column.counts, + self.source.active_type(), + ) + .is_none_or(|fraction| fraction < min_constant_fraction) + }); + gap_ok && constant_ok + }) }); } @@ -126,6 +148,7 @@ impl<'a> FilterBuilder<'a> { row_exclude_sets: Vec::new(), row_name_regex: None, max_gap_fraction: None, + min_constant_fraction: None, } } } @@ -161,6 +184,14 @@ fn validate_gap_fraction(threshold: f32) -> Result<(), AlignmentError> { Err(AlignmentError::InvalidGapFraction(threshold)) } +fn validate_constant_fraction(threshold: f32) -> Result<(), AlignmentError> { + if threshold.is_finite() && (0.0..=1.0).contains(&threshold) { + return Ok(()); + } + + Err(AlignmentError::InvalidConstantFraction(threshold)) +} + #[cfg(test)] mod filter_builder_tests { use crate::{ @@ -225,6 +256,36 @@ mod filter_builder_tests { assert_eq!(first_ids, second_ids); } + #[test] + fn constant_filter_is_order_insensitive() { + let alignment = dna_alignment(&[ + ("ref", b"AN-"), + ("keep-a", b"AAA"), + ("keep-b", b"AAA"), + ("drop", b"NT-"), + ]); + + let first = alignment + .filter() + .unwrap() + .without_rows([0]) + .with_min_constant_fraction(1.0) + .apply() + .unwrap(); + let second = alignment + .filter() + .unwrap() + .with_min_constant_fraction(1.0) + .without_rows([0]) + .apply() + .unwrap(); + + assert_eq!( + first.absolute_column_ids().collect::>(), + second.absolute_column_ids().collect::>() + ); + } + #[test] fn filter_supports_regex_and_index_filters() { let alignment = generic_alignment(&[ @@ -284,6 +345,18 @@ mod filter_builder_tests { assert_eq!(err, AlignmentError::InvalidGapFraction(1.5)); } + #[test] + fn invalid_constant_fraction_returns_error() { + let err = generic_alignment(&[("sample-1", b"AC")]) + .filter() + .unwrap() + .with_min_constant_fraction(1.5) + .apply() + .unwrap_err(); + + assert_eq!(err, AlignmentError::InvalidConstantFraction(1.5)); + } + #[test] fn gap_fraction_filter_uses_filtered_rows() { let alignment = dna_alignment(&[("ref", b"A"), ("s1", b"A"), ("s2", b"A"), ("s3", b"-")]); @@ -299,6 +372,63 @@ mod filter_builder_tests { assert_eq!(col_ids, vec![0]); } + #[test] + fn constant_filter_hides_fully_constant_dna_columns() { + let alignment = dna_alignment(&[("s1", b"AN"), ("s2", b"AC"), ("s3", b"AT")]); + let filtered = alignment + .filter() + .unwrap() + .with_min_constant_fraction(1.0) + .apply() + .unwrap(); + + assert_eq!(filtered.absolute_column_ids().collect::>(), vec![1]); + } + + #[test] + fn constant_filter_uses_filtered_rows() { + let alignment = dna_alignment(&[("ref", b"T"), ("s1", b"A"), ("s2", b"A"), ("s3", b"T")]); + let filtered = alignment + .filter() + .unwrap() + .without_rows([0, 3]) + .with_min_constant_fraction(1.0) + .apply() + .unwrap(); + + assert!(filtered.absolute_column_ids().next().is_none()); + } + + #[test] + fn constant_filter_keeps_columns_with_only_ignored_symbols() { + let alignment = dna_alignment(&[("s1", b"N-"), ("s2", b"-N"), ("s3", b"NN")]); + let filtered = alignment + .filter() + .unwrap() + .with_min_constant_fraction(1.0) + .apply() + .unwrap(); + + assert_eq!( + filtered.absolute_column_ids().collect::>(), + vec![0, 1] + ); + } + + #[test] + fn gap_and_constant_filters_can_be_combined() { + let alignment = dna_alignment(&[("s1", b"AA-"), ("s2", b"AA-"), ("s3", b"ATC")]); + let filtered = alignment + .filter() + .unwrap() + .with_max_gap_fraction(0.5) + .with_min_constant_fraction(0.9) + .apply() + .unwrap(); + + assert_eq!(filtered.absolute_column_ids().collect::>(), vec![1]); + } + #[test] fn column_summaries_positions_empty_returns_empty() { let alignment = generic_alignment(&[("s1", b"A-"), ("s2", b"--")]); diff --git a/libmsa/src/metrics.rs b/libmsa/src/metrics.rs index 1e8466c..716adb0 100644 --- a/libmsa/src/metrics.rs +++ b/libmsa/src/metrics.rs @@ -1,6 +1,7 @@ use rand::seq::IndexedRandom; use std::{num::NonZeroU8, ops::Range}; +use crate::AlignmentType; use crate::data::AlignmentData; use crate::error::AlignmentError; use crate::model::Alignment; @@ -405,6 +406,29 @@ pub(crate) fn gap_fraction_from_counts(counts: &[u32; 256]) -> f32 { } } +pub(crate) fn max_counted_symbol_fraction_from_counts( + counts: &[u32; 256], + kind: AlignmentType, +) -> Option { + let mut counted_total = 0u32; + let mut max_count = 0u32; + + for (symbol, &count) in counts.iter().enumerate() { + if count == 0 { + continue; + } + + if is_ignored_constant_symbol(symbol as u8, kind) { + continue; + } + + counted_total += count; + max_count = max_count.max(count); + } + + (counted_total != 0).then_some(max_count as f32 / counted_total as f32) +} + fn consensus_from_counts( counts: &[u32; 256], method: ConsensusMethod, @@ -481,6 +505,19 @@ fn conservation_from_counts(counts: &[u32; 256], max_entropy: f64) -> f32 { (conservation * (1.0 - gap_fraction)) as f32 } +#[inline] +const fn is_ignored_constant_symbol(byte: u8, kind: AlignmentType) -> bool { + if is_gap_byte(byte) { + return true; + } + + match kind { + AlignmentType::Dna => matches!(byte, b'N' | b'n'), + AlignmentType::Protein => matches!(byte, b'X' | b'x'), + AlignmentType::Generic => false, + } +} + fn column_byte_counts(data: &AlignmentData, rows: &Projection, abs_col: usize) -> [u32; 256] { let mut counts = [0u32; 256]; @@ -718,6 +755,53 @@ mod conservation_count_tests { } } +#[cfg(test)] +mod constant_fraction_count_tests { + use crate::AlignmentType; + + use super::max_counted_symbol_fraction_from_counts; + + fn counts_for(symbols: &[u8]) -> [u32; 256] { + let mut counts = [0u32; 256]; + for &s in symbols { + counts[usize::from(s)] += 1; + } + counts + } + + #[test] + fn dna_constant_fraction_ignores_gaps_and_ns() { + let counts = counts_for(b"AANn--T"); + let fraction = max_counted_symbol_fraction_from_counts(&counts, AlignmentType::Dna); + + assert_eq!(fraction, Some(2.0 / 3.0)); + } + + #[test] + fn protein_constant_fraction_ignores_gaps_and_xs() { + let counts = counts_for(b"MMXx--K"); + let fraction = max_counted_symbol_fraction_from_counts(&counts, AlignmentType::Protein); + + assert_eq!(fraction, Some(2.0 / 3.0)); + } + + #[test] + fn generic_constant_fraction_counts_n() { + let counts = counts_for(b"NN-A"); + let fraction = max_counted_symbol_fraction_from_counts(&counts, AlignmentType::Generic); + + assert_eq!(fraction, Some(2.0 / 3.0)); + } + + #[test] + fn constant_fraction_returns_none_when_all_symbols_are_ignored() { + let counts = counts_for(b"-Nn"); + let fraction = max_counted_symbol_fraction_from_counts(&counts, AlignmentType::Dna); + + assert_eq!(fraction, None); + } +} + #[cfg(test)] mod tests { use crate::{Alignment, AlignmentError, AlignmentType, ConsensusMethod, RawSequence}; diff --git a/libmsa/src/translation.rs b/libmsa/src/translation.rs index a7fbfcc..6ebd5e9 100644 --- a/libmsa/src/translation.rs +++ b/libmsa/src/translation.rs @@ -430,7 +430,7 @@ pub(crate) fn normalise_nucleotide(byte: u8) -> Option { } } -pub(crate) fn translate_sequence( +pub fn translate_sequence( sequence: &[u8], frame: ReadingFrame, table: &TranslationTable, From f96b7cb2e9440665390ede213731f369899f5993 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Thu, 26 Mar 2026 19:24:00 +0000 Subject: [PATCH 02/48] feat(salti): add constant filter --- salti/src/app.rs | 50 +++++++++++++- salti/src/command.rs | 1 + salti/src/core/model.rs | 46 ++++++++++++- .../command_palette/command_definitions.rs | 14 +++- .../command_palette/command_runners.rs | 68 ++++++++++++++----- salti/src/ui/alignment_pane.rs | 42 ++++++++++-- salti/src/ui/frame.rs | 57 +++++++++++++++- 7 files changed, 245 insertions(+), 33 deletions(-) diff --git a/salti/src/app.rs b/salti/src/app.rs index fa4bd5c..2b01c65 100644 --- a/salti/src/app.rs +++ b/salti/src/app.rs @@ -447,6 +447,17 @@ impl App { self.on_view_rebuilt(); return Ok(()); } + Command::SetConstantFilter(min_constant_fraction) => { + let alignment = self.alignment_mut()?; + if min_constant_fraction.is_some() && alignment.translation().is_some() { + return Err(format_err!( + "filter-constant is unavailable while translation is active" + )); + } + alignment.set_constant_filter(min_constant_fraction)?; + self.on_view_rebuilt(); + return Ok(()); + } Command::ClearFilter => { self.alignment_mut()?.clear_filter()?; self.on_view_rebuilt(); @@ -462,7 +473,7 @@ impl App { let alignment = self.alignment_mut()?; if alignment.translation().is_none() && alignment.filter().has_column_filter() { return Err(format_err!( - "translation is unavailable while filter-gaps is active" + "translation is unavailable while a column filter is active" )); } alignment.toggle_translation_view()?; @@ -845,6 +856,24 @@ mod tests { ); } + #[tokio::test(flavor = "current_thread")] + async fn filter_constant_shows_notification_when_translation_is_active() { + let mut app = + app_with_alignment(vec![raw("row1", b"ATGAAATTT"), raw("row2", b"ATGAAATTT")]); + app.execute_commands([Command::ToggleTranslationView]); + app.execute_commands([Command::SetConstantFilter(Some(0.9))]); + + let notification = app + .ui + .notification + .as_ref() + .expect("notification should be created"); + assert_eq!( + notification.message, + "filter-constant is unavailable while translation is active" + ); + } + #[tokio::test(flavor = "current_thread")] async fn translation_shows_notification_when_gap_filter_is_active() { let mut app = app_with_alignment(vec![raw("row1", b"ATG---"), raw("row2", b"ATG---")]); @@ -858,7 +887,24 @@ mod tests { .expect("notification should be created"); assert_eq!( notification.message, - "translation is unavailable while filter-gaps is active" + "translation is unavailable while a column filter is active" + ); + } + + #[tokio::test(flavor = "current_thread")] + async fn translation_shows_notification_when_constant_filter_is_active() { + let mut app = app_with_alignment(vec![raw("row1", b"ATGAAA"), raw("row2", b"ATGAAA")]); + app.execute_commands([Command::SetConstantFilter(Some(1.0))]); + app.execute_commands([Command::ToggleTranslationView]); + + let notification = app + .ui + .notification + .as_ref() + .expect("notification should be created"); + assert_eq!( + notification.message, + "translation is unavailable while a column filter is active" ); } diff --git a/salti/src/command.rs b/salti/src/command.rs index 64dc32b..cc315d4 100644 --- a/salti/src/command.rs +++ b/salti/src/command.rs @@ -24,6 +24,7 @@ pub enum Command { JumpToEnd, SetFilter(String), SetGapFilter(Option), + SetConstantFilter(Option), ClearFilter, PinSequence(usize), UnpinSequence(usize), diff --git a/salti/src/core/model.rs b/salti/src/core/model.rs index c882239..70f68f9 100644 --- a/salti/src/core/model.rs +++ b/salti/src/core/model.rs @@ -118,6 +118,7 @@ impl RowPresentationState { pub struct FilterState { pattern: Option, max_gap_fraction: Option, + min_constant_fraction: Option, } impl FilterState { @@ -129,12 +130,18 @@ impl FilterState { self.max_gap_fraction } + pub fn min_constant_fraction(&self) -> Option { + self.min_constant_fraction + } + pub fn has_column_filter(&self) -> bool { - self.max_gap_fraction.is_some() + self.max_gap_fraction.is_some() || self.min_constant_fraction.is_some() } pub fn is_active(&self) -> bool { - self.pattern.is_some() || self.max_gap_fraction.is_some() + self.pattern.is_some() + || self.max_gap_fraction.is_some() + || self.min_constant_fraction.is_some() } } @@ -243,9 +250,23 @@ impl AlignmentModel { Ok(()) } + pub fn set_constant_filter( + &mut self, + min_constant_fraction: Option, + ) -> Result<(), libmsa::AlignmentError> { + let previous = self.filter.min_constant_fraction; + self.filter.min_constant_fraction = min_constant_fraction; + if let Err(error) = self.derive_view_from_intent() { + self.filter.min_constant_fraction = previous; + return Err(error); + } + Ok(()) + } + pub fn clear_filter(&mut self) -> Result<(), libmsa::AlignmentError> { self.filter.pattern = None; self.filter.max_gap_fraction = None; + self.filter.min_constant_fraction = None; self.derive_view_from_intent() } @@ -365,6 +386,9 @@ impl AlignmentModel { if let Some(max_gap_fraction) = self.filter.max_gap_fraction() { builder = builder.with_max_gap_fraction(max_gap_fraction); } + if let Some(min_constant_fraction) = self.filter.min_constant_fraction() { + builder = builder.with_min_constant_fraction(min_constant_fraction); + } self.view = builder.apply()?; Ok(()) } @@ -655,7 +679,21 @@ mod tests { } #[test] - fn clear_filter_removes_both_filters() { + fn set_constant_filter_applies_column_filter() { + let mut model = alignment_model(vec![ + raw("alpha", b"AN-T"), + raw("beta", b"A--T"), + raw("gamma", b"ATGT"), + ]); + + model.set_constant_filter(Some(1.0)).unwrap(); + + assert_eq!(model.filter().min_constant_fraction(), Some(1.0)); + assert_eq!(model.view().column_count(), 2); + } + + #[test] + fn clear_filter_removes_all_filters() { let mut model = alignment_model(vec![ raw("alpha", b"A--T"), raw("beta", b"A--T"), @@ -663,11 +701,13 @@ mod tests { ]); model.set_filter("alpha|beta".to_string()).unwrap(); model.set_gap_filter(Some(0.0)).unwrap(); + model.set_constant_filter(Some(1.0)).unwrap(); model.clear_filter().unwrap(); assert_eq!(model.filter().pattern(), None); assert_eq!(model.filter().max_gap_fraction(), None); + assert_eq!(model.filter().min_constant_fraction(), None); assert_eq!(model.view().row_count(), 3); assert_eq!(model.view().column_count(), 4); } diff --git a/salti/src/overlay/command_palette/command_definitions.rs b/salti/src/overlay/command_palette/command_definitions.rs index d49b63d..79070c8 100644 --- a/salti/src/overlay/command_palette/command_definitions.rs +++ b/salti/src/overlay/command_palette/command_definitions.rs @@ -1,8 +1,8 @@ use super::command_runners::{ run_check_update, run_clear_filter, run_clear_reference, run_consensus_method, run_diff_mode, - run_filter_gaps, run_filter_rows, run_jump_position, run_jump_sequence, run_load_alignment, - run_pin_sequence, run_quit, run_set_active_type, run_set_reference, run_theme, - run_toggle_translation, run_translation_frame, run_unpin_sequence, + run_filter_constant, run_filter_gaps, run_filter_rows, run_jump_position, run_jump_sequence, + run_load_alignment, run_pin_sequence, run_quit, run_set_active_type, run_set_reference, + run_theme, run_toggle_translation, run_translation_frame, run_unpin_sequence, }; use super::command_spec::{PaletteCommand, StaticCommand, TypableCommand}; use super::completers; @@ -75,6 +75,14 @@ pub(super) const COMMAND_SPECS: &[PaletteCommand] = &[ static_candidates: &["0", "5", "10", "25", "50"], run: run_filter_gaps, }), + PaletteCommand::Typable(TypableCommand { + name: "filter-constant", + help_text: "Hide columns when a counted symbol reaches the given percentage. Gaps and type-specific unknowns are ignored. Use 0 to disable it.", + aliases: &[], + completer: None, + static_candidates: &["0", "70", "90", "95", "100"], + run: run_filter_constant, + }), PaletteCommand::Typable(TypableCommand { name: "set-reference", help_text: "Set the reference sequence used for diffs.", diff --git a/salti/src/overlay/command_palette/command_runners.rs b/salti/src/overlay/command_palette/command_runners.rs index 0e576ac..2695232 100644 --- a/salti/src/overlay/command_palette/command_runners.rs +++ b/salti/src/overlay/command_palette/command_runners.rs @@ -74,27 +74,36 @@ fn next_visible_column_index(visible_columns: &[usize], absolute_target: usize) } } +fn parse_percentage_argument(arguments: &str) -> anyhow::Result> { + let value = require_argument(arguments)?; + let Ok(percent) = value.parse::() else { + return Err(format_err!( + "Invalid argument: expected a percentage in 0..=100", + )); + }; + if !percent.is_finite() || !(0.0..=100.0).contains(&percent) { + return Err(format_err!( + "Invalid argument: expected a percentage in 0..=100", + )); + } + + Ok((percent != 0.0).then_some(percent / 100.0)) +} + pub(super) fn run_filter_gaps(_: &CommandPaletteState, arguments: &str) -> anyhow::Result { run_command("filter-gaps", arguments, || { - let value = require_argument(arguments)?; - let Ok(percent) = value.parse::() else { - return Err(format_err!( - "Invalid argument: expected a percentage in 0..=100", - )); - }; - if !percent.is_finite() || !(0.0..=100.0).contains(&percent) { - return Err(format_err!( - "Invalid argument: expected a percentage in 0..=100", - )); - } - - let max_gap_fraction = if percent == 0.0 { - None - } else { - Some(percent / 100.0) - }; + Ok(Command::SetGapFilter(parse_percentage_argument(arguments)?)) + }) +} - Ok(Command::SetGapFilter(max_gap_fraction)) +pub(super) fn run_filter_constant( + _: &CommandPaletteState, + arguments: &str, +) -> anyhow::Result { + run_command("filter-constant", arguments, || { + Ok(Command::SetConstantFilter(parse_percentage_argument( + arguments, + )?)) }) } @@ -375,6 +384,29 @@ mod tests { ); } + #[test] + fn filter_constant_parses_percentage_into_constant_fraction() { + let state = palette_state_with_columns(Vec::new()); + + let action = run_filter_constant(&state, "90").expect("percentage should parse"); + + assert!(matches!( + action, + Command::SetConstantFilter(Some(value)) + if (value - 0.9).abs() < f32::EPSILON + )); + } + + #[test] + fn filter_constant_zero_clears_the_constant_filter() { + let state = palette_state_with_columns(Vec::new()); + + let action = + run_filter_constant(&state, "0").expect("zero should disable the constant filter"); + + assert_eq!(action, Command::SetConstantFilter(None)); + } + #[test] fn set_active_type_accepts_alignment_type_name() { let state = palette_state_with_columns(Vec::new()); diff --git a/salti/src/ui/alignment_pane.rs b/salti/src/ui/alignment_pane.rs index f8b3ed9..ad49745 100644 --- a/salti/src/ui/alignment_pane.rs +++ b/salti/src/ui/alignment_pane.rs @@ -286,19 +286,30 @@ fn add_number_to_ruler( centre_pos: usize, number: usize, theme: &ThemeState, -) { +) -> bool { let number_string = number.to_string(); let number_length = number_string.len(); let ruler_width = number_line.len(); let start_idx = centre_pos .saturating_sub(number_length / 2) .min(ruler_width.saturating_sub(number_length)); + let left_padding = start_idx.saturating_sub(1); + let right_padding = (start_idx + number_length + 1).min(ruler_width); + + if number_line[left_padding..right_padding] + .iter() + .any(|span| span.content.as_ref() != " ") + { + return false; + } for (offset, digit) in number_string.chars().enumerate() { if let Some(cell) = number_line.get_mut(start_idx + offset) { *cell = digit.to_string().set_style(theme.styles.accent); } } + + true } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -381,6 +392,22 @@ fn dense_break_spans(breaks: &[(usize, BreakMarker)], width: usize) -> Vec<(usiz spans } +fn run_start_positions(absolute_columns: &[usize]) -> Vec { + let mut starts = Vec::new(); + if absolute_columns.is_empty() { + return starts; + } + + starts.push(0); + for (index, pair) in absolute_columns.windows(2).enumerate() { + if pair[1] != pair[0] + 1 { + starts.push(index + 1); + } + } + + starts +} + fn build_ruler( absolute_columns: &[usize], filtered_leading: bool, @@ -394,6 +421,9 @@ fn build_ruler( let mut number_line = vec![Span::raw(" "); width]; let mut marker_line = vec![Span::raw(" "); width]; + let breaks = break_positions(absolute_columns, filtered_leading, filtered_trailing); + let fragmented_view = !breaks.is_empty(); + let run_starts = fragmented_view.then(|| run_start_positions(absolute_columns)); for (index, marker_span) in marker_line.iter_mut().enumerate() { let display_pos = absolute_columns[index] + 1; @@ -405,13 +435,17 @@ fn build_ruler( ".".set_style(theme.styles.text_dim) }; - if is_major_tick || display_pos == 1 { - add_number_to_ruler(&mut number_line, index, display_pos, theme); + let should_label = if let Some(run_starts) = &run_starts { + run_starts.contains(&index) + } else { + is_major_tick || display_pos == 1 + }; + if should_label { + let _ = add_number_to_ruler(&mut number_line, index, display_pos, theme); } } } - let breaks = break_positions(absolute_columns, filtered_leading, filtered_trailing); let dense_spans = dense_break_spans(&breaks, width); for (position, marker) in breaks { diff --git a/salti/src/ui/frame.rs b/salti/src/ui/frame.rs index 71e72d6..8345210 100644 --- a/salti/src/ui/frame.rs +++ b/salti/src/ui/frame.rs @@ -15,8 +15,8 @@ use ratatui::widgets::Paragraph; /// maximum displayed character count for a selected sequence name in the status bar before truncation const STATUS_BAR_SELECTED_NAME_MAX_CHARS: usize = 25; -fn format_gap_percent(max_gap_fraction: f32) -> String { - let mut text = format!("{:.2}", max_gap_fraction * 100.0); +fn format_percent(fraction: f32) -> String { + let mut text = format!("{:.2}", fraction * 100.0); while text.ends_with('0') { text.pop(); } @@ -40,8 +40,16 @@ fn build_bottom_status_bar(alignment: Option<&AlignmentModel>, ui: &UiState) -> if let Some(max_gap_fraction) = alignment.filter().max_gap_fraction() { filter_text.push_str(&format!( " [gaps: <= {}%]", - format_gap_percent(max_gap_fraction) + format_percent(max_gap_fraction) )); + } + if let Some(min_constant_fraction) = alignment.filter().min_constant_fraction() { + filter_text.push_str(&format!( + " [constant: >= {}%]", + format_percent(min_constant_fraction) + )); + } + if alignment.filter().has_column_filter() { let visible_cols = alignment.view().column_count(); counts.push_str(&format!(" ({visible_cols} cols)")); } @@ -240,6 +248,49 @@ mod tests { ); } + #[test] + fn bottom_status_bar_formats_constant_filter_summary() { + let alignment = libmsa::Alignment::new(vec![ + raw("alpha", b"AN-T"), + raw("beta", b"A--T"), + raw("gamma", b"ATGT"), + ]) + .expect("alignment should be valid"); + let mut alignment = AlignmentModel::new(alignment).expect("alignment model should build"); + alignment + .set_constant_filter(Some(1.0)) + .expect("constant filter should apply"); + let ui = ui_state(); + + assert_eq!( + status_text(&build_bottom_status_bar(Some(&alignment), &ui)), + "Filters: [constant: >= 100%] (3 rows) (2 cols)" + ); + } + + #[test] + fn bottom_status_bar_formats_combined_column_filter_summary() { + let alignment = libmsa::Alignment::new(vec![ + raw("alpha", b"AN-T"), + raw("beta", b"A--T"), + raw("gamma", b"ATGT"), + ]) + .expect("alignment should be valid"); + let mut alignment = AlignmentModel::new(alignment).expect("alignment model should build"); + alignment + .set_gap_filter(Some(0.5)) + .expect("gap filter should apply"); + alignment + .set_constant_filter(Some(1.0)) + .expect("constant filter should apply"); + let ui = ui_state(); + + assert_eq!( + status_text(&build_bottom_status_bar(Some(&alignment), &ui)), + "Filters: [gaps: <= 50%] [constant: >= 100%] (3 rows) (2 cols)" + ); + } + #[test] fn top_status_bar_shows_alignment_length() { let alignment = libmsa::Alignment::new(vec![ From c64f9afeedc21859b1370b043af5c363cc0071b7 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sun, 29 Mar 2026 18:51:17 +0100 Subject: [PATCH 03/48] refactor: simplify translation + codon representation --- libmsa/src/translation.rs | 26 ++++ salti/src/core/codon.rs | 234 +++++++++++++++++++++++++++++++++ salti/src/core/mod.rs | 1 + salti/src/core/model.rs | 39 ++---- salti/src/core/viewport.rs | 19 ++- salti/src/input/mouse.rs | 14 +- salti/src/ui/alignment_pane.rs | 192 +++++++++++++-------------- salti/src/ui/consensus_pane.rs | 80 +++++------ salti/src/ui/rows.rs | 122 ++++------------- salti/src/ui/selection.rs | 55 ++++---- salti/src/ui/ui_state.rs | 8 ++ 11 files changed, 473 insertions(+), 317 deletions(-) create mode 100644 salti/src/core/codon.rs diff --git a/libmsa/src/translation.rs b/libmsa/src/translation.rs index 6ebd5e9..7502f75 100644 --- a/libmsa/src/translation.rs +++ b/libmsa/src/translation.rs @@ -60,6 +60,15 @@ impl ReadingFrame { ((nucleotide_length - 1 - offset) / 3) + 1 } + + /// Returns the number of complete three-nucleotide codons for this frame. + /// + /// Unlike [`translated_length`](Self::translated_length), this excludes the + /// incomplete terminal codon when the remaining nucleotides after the frame + /// offset are not divisible by three. + pub const fn complete_codons(self, nucleotide_len: usize) -> usize { + nucleotide_len.saturating_sub(self.offset()) / 3 + } } impl std::fmt::Display for ReadingFrame { @@ -712,6 +721,23 @@ mod reading_frame_tests { assert_eq!(ReadingFrame::Frame2.translated_length(2), 1); assert_eq!(ReadingFrame::Frame3.translated_length(2), 0); } + + #[test] + fn complete_codons_excludes_incomplete_terminal() { + // 9 nucleotides, frame 1: 9 / 3 = 3 complete codons. + assert_eq!(ReadingFrame::Frame1.complete_codons(9), 3); + // 10 nucleotides, frame 1: 10 / 3 = 3 (drops the leftover). + assert_eq!(ReadingFrame::Frame1.complete_codons(10), 3); + // translated_length would give 4 here (includes the incomplete). + assert_eq!(ReadingFrame::Frame1.translated_length(10), 4); + + // Frame 2, 9 nucleotides: (9 - 1) / 3 = 2 complete codons. + assert_eq!(ReadingFrame::Frame2.complete_codons(9), 2); + // Frame 3, 2 nucleotides: (2 - 2) / 3 = 0. + assert_eq!(ReadingFrame::Frame3.complete_codons(2), 0); + // Edge: empty sequence. + assert_eq!(ReadingFrame::Frame1.complete_codons(0), 0); + } } #[cfg(test)] diff --git a/salti/src/core/codon.rs b/salti/src/core/codon.rs new file mode 100644 index 0000000..be2bca3 --- /dev/null +++ b/salti/src/core/codon.rs @@ -0,0 +1,234 @@ +use std::ops::Range; + +use libmsa::ReadingFrame; + +/// A single codon visible in the current viewport. +/// +/// All fields use absolute nucleotide column coordinates except `protein_col` +/// which is a protein-space index. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct VisibleCodon { + /// Protein-space column index for this codon. + pub protein_col: usize, + /// Absolute nucleotide column where the codon begins. + pub nuc_start: usize, + /// Absolute nucleotide column that displays the amino-acid letter + /// (the centre cell of the three-wide codon span). + pub centre: usize, +} + +/// Context for the translation visual overlay. +/// +/// Computed once per render frame from the active reading frame and the +/// alignment's nucleotide column count, then threaded through the rendering +/// pipeline. All methods operate in nucleotide-space viewport coordinates. +#[derive(Debug, Clone, Copy)] +pub struct TranslationOverlay { + /// Active reading frame for the overlay. + pub frame: ReadingFrame, + /// Total nucleotide columns in the current alignment view. + pub nucleotide_len: usize, +} + +impl TranslationOverlay { + /// Protein column range overlapping a nucleotide viewport range. + pub fn visible_protein_range(&self, nuc_range: &Range) -> Option> { + visible_protein_range(nuc_range, self.frame, self.nucleotide_len) + } + + /// Iterator of [`VisibleCodon`]s for a nucleotide viewport range. + pub fn visible_codons(&self, nuc_range: &Range) -> impl Iterator { + visible_codons(nuc_range, self.frame, self.nucleotide_len) + } + + /// The nucleotide range `[start..start+3)` for an absolute nucleotide + /// column's enclosing codon. Returns `None` for incomplete codons or + /// columns before the frame offset. + pub fn codon_span(&self, absolute_col: usize) -> Option> { + codon_span_for_absolute_column(absolute_col, self.frame, self.nucleotide_len) + } +} + +/// A window into a pre-translated byte slice, offset by `start` in +/// protein-column space. +/// +/// Used for diff-against and consensus rendering in translation mode. +#[derive(Debug, Clone, Copy)] +pub struct TranslatedByteRange<'a> { + start: usize, + bytes: &'a [u8], +} + +impl<'a> TranslatedByteRange<'a> { + /// Creates a translated byte window starting at `start` in protein space. + pub const fn new(start: usize, bytes: &'a [u8]) -> Self { + Self { start, bytes } + } + + /// Returns the byte at `protein_col`, if it lies within this window. + pub fn byte_at(self, protein_col: usize) -> Option { + let offset = protein_col.checked_sub(self.start)?; + self.bytes.get(offset).copied() + } +} + +/// Translated bytes used for diff rendering. +pub type TranslatedDiffRange<'a> = TranslatedByteRange<'a>; + +/// Number of complete three-nucleotide codons. Delegates to +/// [`ReadingFrame::complete_codons`]. +pub const fn complete_protein_len(frame: ReadingFrame, nucleotide_len: usize) -> usize { + frame.complete_codons(nucleotide_len) +} + +/// Protein column range overlapping a nucleotide viewport range. +/// +/// Returns `None` when no complete codons are visible. +pub fn visible_protein_range( + visible_nuc_range: &Range, + frame: ReadingFrame, + nucleotide_len: usize, +) -> Option> { + let last_visible_col = visible_nuc_range.end.checked_sub(1)?; + if last_visible_col < frame.offset() { + return None; + } + + let protein_len = complete_protein_len(frame, nucleotide_len); + if protein_len == 0 { + return None; + } + + let start = visible_nuc_range.start.saturating_sub(frame.offset()) / 3; + let end = ((last_visible_col - frame.offset()) / 3 + 1).min(protein_len); + + (start < end).then_some(start..end) +} + +/// Iterator of [`VisibleCodon`]s for a nucleotide viewport range. +/// +/// Only complete codons are yielded. +pub fn visible_codons( + visible_nuc_range: &Range, + frame: ReadingFrame, + nucleotide_len: usize, +) -> impl Iterator { + visible_protein_range(visible_nuc_range, frame, nucleotide_len) + .into_iter() + .flatten() + .map(move |protein_col| { + let nuc_start = nuc_start(protein_col, frame); + VisibleCodon { + protein_col, + nuc_start, + centre: nuc_start + 1, + } + }) +} + +/// The nucleotide range `[start..start+3)` for an absolute nucleotide +/// column's enclosing codon. +/// +/// Returns `None` when the column lies before the frame offset or +/// the codon extends past the alignment width (incomplete terminal codon). +pub fn codon_span_for_absolute_column( + absolute_col: usize, + frame: ReadingFrame, + nucleotide_len: usize, +) -> Option> { + let offset = frame.offset(); + if absolute_col < offset { + return None; + } + + let codon_start = offset + ((absolute_col - offset) / 3) * 3; + let codon_end = codon_start + 3; + (codon_end <= nucleotide_len).then_some(codon_start..codon_end) +} + +/// First nucleotide index of a protein column: +/// `frame.offset() + protein_col * 3`. +pub fn nuc_start(protein_col: usize, frame: ReadingFrame) -> usize { + frame.offset() + protein_col * 3 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn visible_protein_range_includes_complete_codons_overlapping_window() { + let range = visible_protein_range(&(1..8), ReadingFrame::Frame1, 9); + assert_eq!(range, Some(0..3)); + + let range = visible_protein_range(&(0..2), ReadingFrame::Frame3, 9); + assert!(range.is_none()); + } + + #[test] + fn codon_span_maps_any_column_in_the_same_codon() { + let frame = ReadingFrame::Frame1; + + assert_eq!(codon_span_for_absolute_column(0, frame, 9), Some(0..3)); + assert_eq!(codon_span_for_absolute_column(1, frame, 9), Some(0..3)); + assert_eq!(codon_span_for_absolute_column(2, frame, 9), Some(0..3)); + assert_eq!(codon_span_for_absolute_column(3, frame, 9), Some(3..6)); + } + + #[test] + fn codon_span_returns_none_for_partial_frame_edges() { + let frame = ReadingFrame::Frame2; + + assert_eq!(codon_span_for_absolute_column(0, frame, 9), None); + assert_eq!(codon_span_for_absolute_column(8, frame, 9), None); + } + + #[test] + fn nuc_start_is_frame_offset_plus_triple() { + assert_eq!(nuc_start(0, ReadingFrame::Frame1), 0); + assert_eq!(nuc_start(1, ReadingFrame::Frame1), 3); + assert_eq!(nuc_start(0, ReadingFrame::Frame2), 1); + assert_eq!(nuc_start(1, ReadingFrame::Frame2), 4); + assert_eq!(nuc_start(0, ReadingFrame::Frame3), 2); + } + + #[test] + fn visible_codons_yields_correct_codons() { + let codons: Vec = visible_codons(&(0..9), ReadingFrame::Frame1, 9).collect(); + assert_eq!(codons.len(), 3); + assert_eq!( + codons[0], + VisibleCodon { + protein_col: 0, + nuc_start: 0, + centre: 1, + } + ); + assert_eq!( + codons[1], + VisibleCodon { + protein_col: 1, + nuc_start: 3, + centre: 4, + } + ); + assert_eq!( + codons[2], + VisibleCodon { + protein_col: 2, + nuc_start: 6, + centre: 7, + } + ); + } + + #[test] + fn translated_byte_range_resolves_offset() { + let range = TranslatedByteRange::new(2, b"MKF"); + assert_eq!(range.byte_at(2), Some(b'M')); + assert_eq!(range.byte_at(3), Some(b'K')); + assert_eq!(range.byte_at(4), Some(b'F')); + assert_eq!(range.byte_at(1), None); + assert_eq!(range.byte_at(5), None); + } +} diff --git a/salti/src/core/mod.rs b/salti/src/core/mod.rs index 33ce714..5397e7d 100644 --- a/salti/src/core/mod.rs +++ b/salti/src/core/mod.rs @@ -1,3 +1,4 @@ +pub(crate) mod codon; pub mod model; pub mod parser; pub mod search; diff --git a/salti/src/core/model.rs b/salti/src/core/model.rs index 70f68f9..0422bd7 100644 --- a/salti/src/core/model.rs +++ b/salti/src/core/model.rs @@ -1,5 +1,7 @@ use std::{fmt, ops::Range, str::FromStr}; +use crate::core::codon::{TranslationOverlay, complete_protein_len, visible_protein_range}; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum StatsView { Raw, @@ -332,6 +334,15 @@ impl AlignmentModel { self.view.translated(frame).ok() } + /// Returns translation-space viewport metadata for the active frame. + pub(crate) fn translation_overlay(&self) -> Option { + let frame = self.translation()?; + Some(TranslationOverlay { + frame, + nucleotide_len: self.view().column_count(), + }) + } + pub fn stats_context(&self, visible_col_range: Range) -> Option { if let Some(frame) = self.translation() { let nucleotide_len = self.view().column_count(); @@ -404,34 +415,6 @@ fn validate_row_id(abs_row: usize, row_count: usize) -> Result<(), libmsa::Align }) } -const fn complete_protein_len(frame: libmsa::ReadingFrame, nucleotide_len: usize) -> usize { - nucleotide_len.saturating_sub(frame.offset()) / 3 -} - -fn visible_protein_range( - visible_nucleotide_range: &Range, - frame: libmsa::ReadingFrame, - nucleotide_len: usize, -) -> Option> { - let last_visible_col = visible_nucleotide_range.end.checked_sub(1)?; - if last_visible_col < frame.offset() { - return None; - } - - let protein_len = complete_protein_len(frame, nucleotide_len); - if protein_len == 0 { - return None; - } - - let start = visible_nucleotide_range - .start - .saturating_sub(frame.offset()) - / 3; - let end = ((last_visible_col - frame.offset()) / 3 + 1).min(protein_len); - - (start < end).then_some(start..end) -} - #[cfg(test)] mod tests { use super::{AlignmentModel, DiffMode, RowPresentationState, StatsContext, StatsView}; diff --git a/salti/src/core/viewport.rs b/salti/src/core/viewport.rs index b4b069e..127319f 100644 --- a/salti/src/core/viewport.rs +++ b/salti/src/core/viewport.rs @@ -1,7 +1,7 @@ use std::ops::Range; -// this is essentially the scroll position in each axis -// i.e the top-left of the visible area +// This is effectively the scroll position in each axis. +// It is the top-left of the visible area. #[derive(Debug, Clone, Copy, Default)] pub struct ViewportOffsets { pub rows: usize, @@ -9,8 +9,8 @@ pub struct ViewportOffsets { pub names: usize, } -// this is how much is visible on each axis. -// this is affected by terminal size/layout etc. +// This is how much is visible on each axis. +// It is affected by terminal size and layout. #[derive(Debug, Clone, Default)] struct ViewportDims { rows: usize, @@ -18,8 +18,8 @@ struct ViewportDims { name_width: usize, } -// maximum bounds of the data. -// this is the full size of the alignment and name data, independent of the terminal. +// Maximum bounds of the data. +// This is the full size of the alignment and name data, independent of the terminal. #[derive(Debug, Clone, Default)] struct ViewportMax { rows: usize, @@ -34,10 +34,17 @@ pub struct Viewport { max: ViewportMax, } +/// Viewport window expressed in visible-row and visible-column coordinates. +/// +/// Visible coordinates map to absolute coordinates via +/// [`libmsa::Alignment::absolute_row_id`] and [`libmsa::Alignment::absolute_column_id`]. #[derive(Debug, Clone)] pub struct ViewportWindow { + /// Visible row indices into the current filtered view. pub row_range: Range, + /// Visible column indices into the current filtered view. pub col_range: Range, + /// Visible name-column indices for the sequence ID pane. pub name_range: Range, } diff --git a/salti/src/input/mouse.rs b/salti/src/input/mouse.rs index 9dc06c6..a151266 100644 --- a/salti/src/input/mouse.rs +++ b/salti/src/input/mouse.rs @@ -6,13 +6,20 @@ use crate::input::route::{MouseRoute, route_mouse}; use crate::overlay::minimap::MinimapState; use crate::overlay::overlay_state::ActiveOverlay; use crate::ui::layout::{AppLayout, FrameLayout}; -use crate::ui::selection::{codon_span_for_absolute_column, selection_point_crosshair}; +use crate::ui::selection::selection_point_crosshair; use crate::ui::ui_state::{MouseSelection, UiState}; +/// Snapshot of a mouse click position in absolute coordinates. +/// +/// In translation mode, `column` and `end_column` span the full codon +/// (three nucleotide columns). In raw mode they are identical. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) struct MouseAnchor { + /// Absolute row index. sequence_id: usize, + /// Absolute column of the codon/cell start. column: usize, + /// Absolute column of the codon/cell end (inclusive). end_column: usize, } @@ -194,15 +201,14 @@ fn anchor_from_crosshair( sequence_id: usize, column: usize, ) -> Option { - let Some(frame) = alignment.translation() else { + let Some(overlay) = alignment.translation_overlay() else { return Some(MouseAnchor { sequence_id, column, end_column: column, }); }; - let codon_span = - codon_span_for_absolute_column(column, frame, alignment.view().column_count())?; + let codon_span = overlay.codon_span(column)?; Some(MouseAnchor { sequence_id, column: codon_span.start, diff --git a/salti/src/ui/alignment_pane.rs b/salti/src/ui/alignment_pane.rs index ad49745..90db1ba 100644 --- a/salti/src/ui/alignment_pane.rs +++ b/salti/src/ui/alignment_pane.rs @@ -1,25 +1,24 @@ +use ratatui::Frame; +use ratatui::layout::Rect; +use ratatui::macros::vertical; +use ratatui::style::Styled; +use ratatui::symbols::merge::MergeStrategy; +use ratatui::text::{Line, Span}; +use ratatui::widgets::{Block, Paragraph}; + use crate::{ core::{ + codon::TranslatedDiffRange, model::{AlignmentModel, DiffMode}, stats_cache::ColumnStatsCache, viewport::{Viewport, ViewportWindow}, }, ui::{ - layout::{AppLayout, RULER_HEIGHT_ROWS, pinned_section_layout}, - rows::{ - RowRenderMode, TranslatedDiffRange, format_row_spans, format_translated_row_spans, - visible_bytes, visible_protein_range, - }, + layout::{AppLayout, PinnedSectionLayout, RULER_HEIGHT_ROWS, pinned_section_layout}, + rows::{RowRenderMode, format_row_spans, format_translated_row_spans, visible_bytes}, ui_state::ThemeState, }, }; -use ratatui::Frame; -use ratatui::layout::Rect; -use ratatui::macros::vertical; -use ratatui::style::Styled; -use ratatui::symbols::merge::MergeStrategy; -use ratatui::text::{Line, Span}; -use ratatui::widgets::{Block, Paragraph}; const SCROLLBAR_THUMB_WIDTH: usize = 3; const SCROLLBAR_THUMB_MIN_WIDTH: usize = 1; @@ -58,6 +57,44 @@ fn translated_diff_range<'a>( } } +fn emit_band_rows( + lines: &mut Vec>, + alignment: &AlignmentModel, + window: &ViewportWindow, + band_layout: &PinnedSectionLayout, + area_width: u16, + theme: &ThemeState, + render_row: &mut dyn FnMut(usize) -> Option>, +) { + for &absolute_row in alignment + .rows() + .pinned() + .iter() + .take(band_layout.pinned_rendered) + { + if let Some(line) = render_row(absolute_row) { + lines.push(line); + } + } + + if band_layout.divider_height == 1 { + lines.push(Line::from( + "─" + .repeat(area_width as usize) + .set_style(theme.styles.border), + )); + } + + for relative_row in window.row_range.clone() { + let Some(absolute_row) = alignment.view().absolute_row_id(relative_row) else { + continue; + }; + if let Some(line) = render_row(absolute_row) { + lines.push(line); + } + } +} + fn build_sequence_row_lines( alignment: &AlignmentModel, window: &ViewportWindow, @@ -70,31 +107,26 @@ fn build_sequence_row_lines( band_layout.pinned_rendered + band_layout.divider_height + window.row_range.len(), ); - if let Some(translated) = alignment.translated_view() { - let frame = alignment - .translation() - .expect("translated view requires an active frame"); - let nucleotide_len = alignment.view().column_count(); - let protein_range = visible_protein_range(&window.col_range, frame, nucleotide_len); + if let Some(overlay) = alignment.translation_overlay() + && let Some(translated) = alignment.translated_view() + { + let protein_range = overlay.visible_protein_range(&window.col_range); let reference_bytes: Option> = protein_range.clone().and_then(|protein_range| { alignment .rows() .reference() .and_then(|abs_row| translated.project_absolute_row(abs_row)) - .map(|sequence| { - sequence - .bytes_range(protein_range) - .expect("visible protein range must fit the translated view") - .map(|(_, byte)| byte) - .collect() + .and_then(|sequence| { + let bytes = sequence.bytes_range(protein_range).ok()?; + Some(bytes.map(|(_, byte)| byte).collect()) }) }); let consensus_bytes: Option> = protein_range.clone().and_then(|protein_range| { protein_range .clone() - .map(|protein_col| { + .map(|protein_col: usize| { metrics - .translated_summary_at(frame, protein_col) + .translated_summary_at(overlay.frame, protein_col) .map(|summary| summary.consensus.unwrap_or(b' ')) }) .collect() @@ -108,51 +140,25 @@ fn build_sequence_row_lines( ) }); - for &absolute_row in alignment - .rows() - .pinned() - .iter() - .take(band_layout.pinned_rendered) - { - let Some(sequence) = translated.project_absolute_row(absolute_row) else { - continue; - }; - let spans = format_translated_row_spans( - sequence, - &window.col_range, - nucleotide_len, - frame, - &theme.theme.sequence, - diff_against, - ); - lines.push(Line::from(spans)); - } - - if band_layout.divider_height == 1 { - lines.push(Line::from( - "─" - .repeat(area.width as usize) - .set_style(theme.styles.border), - )); - } - - for relative_row in window.row_range.clone() { - let Some(absolute_row) = alignment.view().absolute_row_id(relative_row) else { - continue; - }; - let Some(sequence) = translated.sequence_by_absolute(absolute_row) else { - continue; - }; - let spans = format_translated_row_spans( - sequence, - &window.col_range, - nucleotide_len, - frame, - &theme.theme.sequence, - diff_against, - ); - lines.push(Line::from(spans)); - } + emit_band_rows( + &mut lines, + alignment, + window, + &band_layout, + area.width, + theme, + &mut |absolute_row| { + let sequence = translated.project_absolute_row(absolute_row)?; + let spans = format_translated_row_spans( + sequence, + &window.col_range, + &overlay, + &theme.theme.sequence, + diff_against, + ); + Some(Line::from(spans)) + }, + ); return lines; } @@ -177,36 +183,20 @@ fn build_sequence_row_lines( consensus_bytes.as_deref(), ); - for &absolute_row in alignment - .rows() - .pinned() - .iter() - .take(band_layout.pinned_rendered) - { - let Some(projected_row) = alignment.view().project_absolute_row(absolute_row) else { - continue; - }; - let bytes = visible_bytes(projected_row, &window.col_range); - let spans = format_row_spans(&bytes, &theme.theme.sequence, render_mode); - lines.push(Line::from(spans)); - } - - if band_layout.divider_height == 1 { - lines.push(Line::from( - "─" - .repeat(area.width as usize) - .set_style(theme.styles.border), - )); - } - - for relative_row in window.row_range.clone() { - let Some(sequence) = alignment.view().sequence(relative_row) else { - continue; - }; - let bytes = visible_bytes(sequence, &window.col_range); - let spans = format_row_spans(&bytes, &theme.theme.sequence, render_mode); - lines.push(Line::from(spans)); - } + emit_band_rows( + &mut lines, + alignment, + window, + &band_layout, + area.width, + theme, + &mut |absolute_row| { + let projected_row = alignment.view().project_absolute_row(absolute_row)?; + let bytes = visible_bytes(projected_row, &window.col_range); + let spans = format_row_spans(&bytes, &theme.theme.sequence, render_mode); + Some(Line::from(spans)) + }, + ); lines } diff --git a/salti/src/ui/consensus_pane.rs b/salti/src/ui/consensus_pane.rs index 848f1dc..9c0544f 100644 --- a/salti/src/ui/consensus_pane.rs +++ b/salti/src/ui/consensus_pane.rs @@ -1,21 +1,26 @@ +use ratatui::Frame; +use ratatui::layout::Rect; +use ratatui::style::{Styled, Stylize}; +use ratatui::symbols::merge::MergeStrategy; +use ratatui::text::Line; +use ratatui::widgets::{Block, Paragraph}; + use crate::{ - core::{model::AlignmentModel, stats_cache::ColumnStatsCache, viewport::ViewportWindow}, + core::{ + codon::{TranslatedByteRange, TranslationOverlay, nuc_start}, + model::AlignmentModel, + stats_cache::ColumnStatsCache, + viewport::ViewportWindow, + }, ui::{ layout::AppLayout, rows::{ - RowRenderMode, TranslatedByteRange, format_row_spans, - format_translated_byte_range_spans, format_translated_row_spans, visible_bytes, - visible_protein_range, + RowRenderMode, format_row_spans, format_translated_byte_range_spans, + format_translated_row_spans, visible_bytes, }, ui_state::ThemeState, }, }; -use ratatui::Frame; -use ratatui::layout::Rect; -use ratatui::style::{Styled, Stylize}; -use ratatui::symbols::merge::MergeStrategy; -use ratatui::text::Line; -use ratatui::widgets::{Block, Paragraph}; const CONSERVATION_SPARK_STRS: [&str; 8] = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]; @@ -36,16 +41,13 @@ fn blank_line(width: usize) -> Line<'static> { fn translated_reference_line( alignment: &AlignmentModel, + overlay: &TranslationOverlay, window: &ViewportWindow, theme: &ThemeState, ) -> Line<'static> { let Some(translated) = alignment.translated_view() else { return Line::from("No reference selected".fg(theme.theme.text_dim).italic()); }; - let frame = alignment - .translation() - .expect("translated view requires an active frame"); - let nucleotide_len = alignment.view().column_count(); alignment.rows().reference().map_or_else( || Line::from("No reference selected".fg(theme.theme.text_dim).italic()), @@ -56,8 +58,7 @@ fn translated_reference_line( let spans = format_translated_row_spans( sequence, &window.col_range, - nucleotide_len, - frame, + overlay, &theme.theme.sequence, None, ); @@ -67,28 +68,20 @@ fn translated_reference_line( } fn translated_consensus_line( - alignment: &AlignmentModel, + overlay: &TranslationOverlay, window: &ViewportWindow, metrics: &ColumnStatsCache, theme: &ThemeState, ) -> Line<'static> { - let Some(_translated) = alignment.translated_view() else { - return Line::from("Calculating consensus...".fg(theme.theme.text_dim).italic()); - }; - let frame = alignment - .translation() - .expect("translated view requires an active frame"); - let nucleotide_len = alignment.view().column_count(); - let Some(protein_range) = visible_protein_range(&window.col_range, frame, nucleotide_len) - else { + let Some(protein_range) = overlay.visible_protein_range(&window.col_range) else { return blank_line(window.col_range.len()); }; let consensus_bytes: Option> = protein_range .clone() - .map(|protein_col| { + .map(|protein_col: usize| { metrics - .translated_summary_at(frame, protein_col) + .translated_summary_at(overlay.frame, protein_col) .map(|summary| summary.consensus.unwrap_or(b' ')) }) .collect(); @@ -98,8 +91,7 @@ fn translated_consensus_line( let spans = format_translated_byte_range_spans( TranslatedByteRange::new(protein_range.start, &consensus_bytes), &window.col_range, - nucleotide_len, - frame, + overlay, &theme.theme.sequence, None, ); @@ -107,29 +99,20 @@ fn translated_consensus_line( } fn translated_conservation_line( - alignment: &AlignmentModel, + overlay: &TranslationOverlay, window: &ViewportWindow, metrics: &ColumnStatsCache, theme: &ThemeState, ) -> Line<'static> { - let Some(frame) = alignment.translation() else { - return Line::from( - "Calculating conservation..." - .fg(theme.theme.text_dim) - .italic(), - ); - }; - let nucleotide_len = alignment.view().column_count(); let width = window.col_range.len(); let mut spans = vec![ratatui::text::Span::styled(" ", theme.styles.accent_alt); width]; - let Some(protein_range) = visible_protein_range(&window.col_range, frame, nucleotide_len) - else { + let Some(protein_range) = overlay.visible_protein_range(&window.col_range) else { return Line::from(spans); }; for protein_col in protein_range { - let Some(summary) = metrics.translated_summary_at(frame, protein_col) else { + let Some(summary) = metrics.translated_summary_at(overlay.frame, protein_col) else { return Line::from( "Calculating conservation..." .fg(theme.theme.text_dim) @@ -140,9 +123,9 @@ fn translated_conservation_line( .conservation .filter(|value| value.is_finite()) .map_or(" ", conservation_to_spark); - let nuc_start = frame.offset() + protein_col * 3; + let codon_nuc_start = nuc_start(protein_col, overlay.frame); - for absolute_col in nuc_start..=nuc_start + 2 { + for absolute_col in codon_nuc_start..=codon_nuc_start + 2 { let Some(window_offset) = absolute_col.checked_sub(window.col_range.start) else { continue; }; @@ -163,11 +146,11 @@ fn consensus_alignment_lines( metrics: &ColumnStatsCache, theme: &ThemeState, ) -> Vec> { - if alignment.translation().is_some() { + if let Some(overlay) = alignment.translation_overlay() { return vec![ - translated_reference_line(alignment, window, theme), - translated_consensus_line(alignment, window, metrics, theme), - translated_conservation_line(alignment, window, metrics, theme), + translated_reference_line(alignment, &overlay, window, theme), + translated_consensus_line(&overlay, window, metrics, theme), + translated_conservation_line(&overlay, window, metrics, theme), ]; } @@ -357,7 +340,6 @@ mod tests { gap_fraction: 0.0, }) .collect(); - let view = view; let generation = cache.generation; let chunk_idx = 0; let stored = cache.store(StatsJobResult { diff --git a/salti/src/ui/rows.rs b/salti/src/ui/rows.rs index 18d07f3..f3ef5bd 100644 --- a/salti/src/ui/rows.rs +++ b/salti/src/ui/rows.rs @@ -1,9 +1,11 @@ use std::ops::Range; -use crate::config::theme::SequenceTheme; use ratatui::style::Stylize; use ratatui::text::Span; +use crate::config::theme::SequenceTheme; +use crate::core::codon::{TranslatedByteRange, TranslatedDiffRange, TranslationOverlay}; + /// Lookup table that maps each byte value (`0-255`) to a str for display. /// /// All printable ASCII bytes map to themselves. @@ -33,32 +35,6 @@ pub struct RowRenderMode<'a> { pub diff_against: Option<&'a [u8]>, } -#[derive(Debug, Clone, Copy)] -pub struct TranslatedByteRange<'a> { - start: usize, - bytes: &'a [u8], -} - -impl<'a> TranslatedByteRange<'a> { - pub fn new(start: usize, bytes: &'a [u8]) -> Self { - Self { start, bytes } - } - - fn byte_at(self, protein_col: usize) -> Option { - let offset = protein_col.checked_sub(self.start)?; - self.bytes.get(offset).copied() - } -} - -pub type TranslatedDiffRange<'a> = TranslatedByteRange<'a>; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct VisibleCodon { - protein_col: usize, - nuc_start: usize, - centre: usize, -} - #[inline] fn span_for_sequence_byte( sequence_byte: u8, @@ -124,64 +100,16 @@ pub fn format_row_spans( } } -fn complete_protein_len(frame: libmsa::ReadingFrame, nucleotide_len: usize) -> usize { - nucleotide_len.saturating_sub(frame.offset()) / 3 -} - -pub fn visible_protein_range( - visible_nucleotide_range: &Range, - frame: libmsa::ReadingFrame, - nucleotide_len: usize, -) -> Option> { - let last_visible_col = visible_nucleotide_range.end.checked_sub(1)?; - if last_visible_col < frame.offset() { - return None; - } - - let protein_len = complete_protein_len(frame, nucleotide_len); - if protein_len == 0 { - return None; - } - - let start = visible_nucleotide_range - .start - .saturating_sub(frame.offset()) - / 3; - let end = ((last_visible_col - frame.offset()) / 3 + 1).min(protein_len); - - (start < end).then_some(start..end) -} - -fn visible_codons( - visible_nucleotide_range: &Range, - frame: libmsa::ReadingFrame, - nucleotide_len: usize, -) -> impl Iterator { - visible_protein_range(visible_nucleotide_range, frame, nucleotide_len) - .into_iter() - .flatten() - .map(move |protein_col| { - let nuc_start = frame.offset() + protein_col * 3; - VisibleCodon { - protein_col, - nuc_start, - centre: nuc_start + 1, - } - }) -} - pub fn format_translated_row_spans( sequence: libmsa::TranslatedSequenceView<'_>, visible_nucleotide_range: &Range, - nucleotide_len: usize, - frame: libmsa::ReadingFrame, + overlay: &TranslationOverlay, sequence_theme: &SequenceTheme, diff_against: Option>, ) -> Vec> { format_translated_spans( visible_nucleotide_range, - nucleotide_len, - frame, + overlay, sequence_theme, diff_against, |protein_col| sequence.byte_at(protein_col), @@ -191,15 +119,13 @@ pub fn format_translated_row_spans( pub fn format_translated_byte_range_spans( bytes: TranslatedByteRange<'_>, visible_nucleotide_range: &Range, - nucleotide_len: usize, - frame: libmsa::ReadingFrame, + overlay: &TranslationOverlay, sequence_theme: &SequenceTheme, diff_against: Option>, ) -> Vec> { format_translated_spans( visible_nucleotide_range, - nucleotide_len, - frame, + overlay, sequence_theme, diff_against, |protein_col| bytes.byte_at(protein_col), @@ -208,8 +134,7 @@ pub fn format_translated_byte_range_spans( fn format_translated_spans( visible_nucleotide_range: &Range, - nucleotide_len: usize, - frame: libmsa::ReadingFrame, + overlay: &TranslationOverlay, sequence_theme: &SequenceTheme, diff_against: Option>, mut byte_at: impl FnMut(usize) -> Option, @@ -217,8 +142,10 @@ fn format_translated_spans( let width = visible_nucleotide_range.len(); let mut spans = vec![Span::raw(" "); width]; - for codon in visible_codons(visible_nucleotide_range, frame, nucleotide_len) { - let residue = byte_at(codon.protein_col).expect("visible codon must resolve"); + for codon in overlay.visible_codons(visible_nucleotide_range) { + let Some(residue) = byte_at(codon.protein_col) else { + continue; + }; let translated_style = sequence_theme.style_for(residue, libmsa::AlignmentType::Protein); let diff_matches = diff_against.and_then(|diff| diff.byte_at(codon.protein_col)) == Some(residue); @@ -265,6 +192,7 @@ pub fn visible_bytes(sequence: libmsa::SequenceView<'_>, col_range: &Range libmsa::RawSequence { libmsa::RawSequence { @@ -277,13 +205,11 @@ mod tests { spans.iter().map(|span| span.content.as_ref()).collect() } - #[test] - fn visible_protein_range_includes_complete_codons_overlapping_window() { - let range = visible_protein_range(&(1..8), libmsa::ReadingFrame::Frame1, 9); - assert_eq!(range, Some(0..3)); - - let range = visible_protein_range(&(0..2), libmsa::ReadingFrame::Frame3, 9); - assert!(range.is_none()); + fn overlay(frame: libmsa::ReadingFrame, nucleotide_len: usize) -> TranslationOverlay { + TranslationOverlay { + frame, + nucleotide_len, + } } #[test] @@ -299,8 +225,7 @@ mod tests { let spans = format_translated_row_spans( sequence, &(0..9), - 9, - libmsa::ReadingFrame::Frame1, + &overlay(libmsa::ReadingFrame::Frame1, 9), &crate::config::theme::EVERFOREST_DARK.sequence, None, ); @@ -323,8 +248,7 @@ mod tests { let spans = format_translated_row_spans( sequence, &(0..9), - 9, - libmsa::ReadingFrame::Frame1, + &overlay(libmsa::ReadingFrame::Frame1, 9), &crate::config::theme::EVERFOREST_DARK.sequence, Some(diff_against), ); @@ -346,8 +270,7 @@ mod tests { let spans = format_translated_row_spans( sequence, &(0..9), - 9, - libmsa::ReadingFrame::Frame1, + &overlay(libmsa::ReadingFrame::Frame1, 9), &crate::config::theme::EVERFOREST_DARK.sequence, Some(diff_against), ); @@ -371,8 +294,7 @@ mod tests { let spans = format_translated_row_spans( sequence, &(0..9), - 9, - libmsa::ReadingFrame::Frame2, + &overlay(libmsa::ReadingFrame::Frame2, 9), &crate::config::theme::EVERFOREST_DARK.sequence, None, ); diff --git a/salti/src/ui/selection.rs b/salti/src/ui/selection.rs index 394de6a..56f6fe0 100644 --- a/salti/src/ui/selection.rs +++ b/salti/src/ui/selection.rs @@ -3,25 +3,14 @@ use std::ops::Range; use ratatui::layout::Rect; use crate::{ - core::{Viewport, model::AlignmentModel}, + core::{Viewport, codon::TranslationOverlay, model::AlignmentModel}, ui::{layout::pinned_section_layout, ui_state::MouseSelection}, }; -pub fn codon_span_for_absolute_column( - absolute_col: usize, - frame: libmsa::ReadingFrame, - nucleotide_len: usize, -) -> Option> { - let offset = frame.offset(); - if absolute_col < offset { - return None; - } - - let codon_start = offset + ((absolute_col - offset) / 3) * 3; - let codon_end = codon_start + 3; - (codon_end <= nucleotide_len).then_some(codon_start..codon_end) -} - +/// Maps a screen-space mouse position to `(absolute_row, absolute_column)`. +/// +/// Returns `None` when the click falls outside `sequence_rows_area`, on the +/// pinned-row divider, or beyond the alignment bounds. pub fn selection_point_crosshair( alignment: &AlignmentModel, viewport: &Viewport, @@ -68,15 +57,21 @@ pub fn selection_row_bounds(selection: MouseSelection) -> (usize, usize) { (start.min(end), start.max(end)) } +/// Converts a selection (absolute columns) to a visible-column range clipped +/// to `visible_col_range`. In translation mode, expands to full codon +/// boundaries. Returns `None` when the selection does not overlap the viewport. pub fn selection_visible_col_range( selection: MouseSelection, alignment: &AlignmentModel, visible_col_range: &Range, ) -> Option> { - match alignment.translation() { - Some(frame) => { - translated_selection_visible_col_range(selection, alignment, visible_col_range, frame) - } + match alignment.translation_overlay() { + Some(overlay) => translated_selection_visible_col_range( + selection, + alignment, + visible_col_range, + &overlay, + ), None => raw_selection_visible_col_range(selection, alignment, visible_col_range), } } @@ -112,12 +107,11 @@ fn translated_selection_visible_col_range( selection: MouseSelection, alignment: &AlignmentModel, visible_col_range: &Range, - frame: libmsa::ReadingFrame, + overlay: &TranslationOverlay, ) -> Option> { let selection_start = selection.column.min(selection.end_column); let selection_end = selection.column.max(selection.end_column) + 1; let view = alignment.view(); - let nucleotide_len = view.column_count(); let mut rel_start: Option = None; let mut rel_end: Option = None; @@ -127,7 +121,7 @@ fn translated_selection_visible_col_range( let Some(abs) = view.absolute_column_id(rel) else { continue; }; - let Some(codon_span) = codon_span_for_absolute_column(abs, frame, nucleotide_len) else { + let Some(codon_span) = overlay.codon_span(abs) else { continue; }; if previous_codon_start == Some(codon_span.start) { @@ -141,13 +135,15 @@ fn translated_selection_visible_col_range( let clipped_start = codon_span.start.max(visible_col_range.start); let clipped_end = codon_span.end.min(visible_col_range.end); - let start = view - .relative_column_id(clipped_start) - .expect("translated mode requires a full visible column set"); - let end = view + let Some(start) = view.relative_column_id(clipped_start) else { + continue; + }; + let Some(end) = view .relative_column_id(clipped_end - 1) - .expect("translated mode requires a full visible column set") - + 1; + .map(|relative_col| relative_col + 1) + else { + continue; + }; rel_start = Some(rel_start.map_or(start, |current| current.min(start))); rel_end = Some(rel_end.map_or(end, |current| current.max(end))); } @@ -159,6 +155,7 @@ fn translated_selection_visible_col_range( mod tests { use super::*; use crate::core::Viewport; + use crate::core::codon::codon_span_for_absolute_column; use crate::core::model::AlignmentModel; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { diff --git a/salti/src/ui/ui_state.rs b/salti/src/ui/ui_state.rs index 7a9dcad..4392c96 100644 --- a/salti/src/ui/ui_state.rs +++ b/salti/src/ui/ui_state.rs @@ -45,11 +45,19 @@ impl From for MetaState { } } +/// Mouse selection stored in absolute row and absolute column coordinates. +/// +/// These survive filter and view changes because they refer to the underlying +/// alignment data, not the current projection. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct MouseSelection { + /// Absolute row index of the selection anchor. pub sequence_id: usize, + /// Absolute column index of the selection anchor. pub column: usize, + /// Absolute row index of the selection end-point. pub end_sequence_id: usize, + /// Absolute column index of the selection end-point. pub end_column: usize, } From fe5261bcd36d1bdb55c4d04d1bcf57b5d4747c17 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Tue, 31 Mar 2026 20:41:00 +0100 Subject: [PATCH 04/48] refactor: I AINT GONNA NEED IT --- libmsa/src/data.rs | 76 ++++++-------- libmsa/src/lib.rs | 10 +- libmsa/src/model.rs | 211 ++++++++++++++++----------------------- libmsa/src/projection.rs | 8 -- 4 files changed, 120 insertions(+), 185 deletions(-) diff --git a/libmsa/src/data.rs b/libmsa/src/data.rs index b09f960..f0747e5 100644 --- a/libmsa/src/data.rs +++ b/libmsa/src/data.rs @@ -1,31 +1,32 @@ use crate::error::AlignmentError; -/// Stores a raw sequence, before it has been validated into a [`Sequence`]. +/// Stores a raw sequence before it has been validated into an internal row. #[derive(Debug, Clone, PartialEq, Eq)] pub struct RawSequence { pub id: String, pub sequence: Vec, } -/// Represents a validated sequence in an alignment. -/// -/// A `Sequence` will always have a non-empty sequence of bytes, -/// and all sequences in an alignment will have the same length #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Sequence { - id: String, - sequence: Box<[u8]>, +pub(crate) struct Sequence { + pub(crate) id: String, + pub(crate) sequence: Box<[u8]>, } -impl Sequence { - /// Returns the identifier (FASTA header). - pub fn id(&self) -> &str { - &self.id - } +impl TryFrom for Sequence { + type Error = AlignmentError; + + fn try_from(raw_sequence: RawSequence) -> Result { + if raw_sequence.sequence.is_empty() { + return Err(AlignmentError::EmptySequence { + id: raw_sequence.id, + }); + } - /// Returns sequence in bytes. - pub fn sequence(&self) -> &[u8] { - &self.sequence + Ok(Self { + id: raw_sequence.id, + sequence: raw_sequence.sequence.into_boxed_slice(), + }) } } @@ -36,49 +37,32 @@ pub(crate) struct AlignmentData { } impl AlignmentData { - pub(crate) fn from_raw(sequences: Vec) -> Result { - let mut raw_iter = sequences.into_iter(); - let Some(first) = raw_iter.next() else { + pub(crate) fn new(sequences: Vec) -> Result { + let mut sequences = sequences.into_iter(); + let Some(first) = sequences.next() else { return Err(AlignmentError::Empty); }; - if first.sequence.is_empty() { - return Err(AlignmentError::EmptySequence { id: first.id }); - } - - let width = first.sequence.len(); - let first = Sequence { - id: first.id, - sequence: first.sequence.into_boxed_slice(), - }; - - let mut normalised = Vec::with_capacity(1 + raw_iter.len()); + let length = first.sequence.len(); + let mut normalised = Vec::with_capacity(1 + sequences.len()); normalised.push(first); - let normalised = raw_iter.try_fold(normalised, |mut normalised, raw| { - if raw.sequence.is_empty() { - return Err(AlignmentError::EmptySequence { id: raw.id }); - } - - let actual = raw.sequence.len(); - if actual != width { + for sequence in sequences { + let actual = sequence.sequence.len(); + if actual != length { return Err(AlignmentError::LengthMismatch { - expected: width, + expected: length, actual, - id: raw.id, + id: sequence.id, }); } - normalised.push(Sequence { - id: raw.id, - sequence: raw.sequence.into_boxed_slice(), - }); - Ok(normalised) - })?; + normalised.push(sequence); + } Ok(Self { sequences: normalised, - length: width, + length, }) } } diff --git a/libmsa/src/lib.rs b/libmsa/src/lib.rs index 74d6a74..42a0620 100644 --- a/libmsa/src/lib.rs +++ b/libmsa/src/lib.rs @@ -1,20 +1,20 @@ -pub mod alignment_type; +mod alignment_type; mod data; pub mod detection; -pub mod error; +mod error; mod filter; mod metrics; mod model; mod projection; -pub mod translation; +mod translation; pub use alignment_type::AlignmentType; -pub use data::{RawSequence, Sequence}; +pub use data::RawSequence; pub use detection::DetectionOptions; pub use error::AlignmentError; pub use filter::FilterBuilder; pub use metrics::{ColumnSummary, ConsensusMethod}; -pub use model::{Alignment, SequenceView}; +pub use model::{Alignment, RowView}; pub use translation::{ ReadingFrame, TranslatedAlignment, TranslatedSequenceView, TranslationTable, }; diff --git a/libmsa/src/model.rs b/libmsa/src/model.rs index 1aba548..a2d3bf8 100644 --- a/libmsa/src/model.rs +++ b/libmsa/src/model.rs @@ -24,22 +24,6 @@ pub struct Alignment { pub(crate) columns: Projection, } -/// A borrowed view of one sequence row within an [`Alignment`]. -/// -/// `SequenceView` does not own sequence data. Instead, it exposes a single row -/// from an alignment together with that alignment's current column projection -/// and active kind. This means its column-based accessors operate on the -/// visible columns of the parent alignment rather than the full -/// underlying sequence. -#[derive(Debug, Clone, Copy)] -pub struct SequenceView<'a> { - absolute_row_id: usize, - id: &'a str, - data: &'a [u8], - columns: &'a Projection, -} - -// constructors impl Alignment { /// Creates an alignment from raw sequences and detects its kind using the default detection options. /// @@ -54,7 +38,7 @@ impl Alignment { /// /// [`AlignmentError::LengthMismatch`] if the sequences in `seqs` do not all have the same length. pub fn new(seqs: impl IntoIterator) -> Result { - Self::new_with(seqs, DetectionOptions::default()) + Self::new_with_detection_options(seqs, DetectionOptions::default()) } /// Creates an alignment from raw sequences and detects its kind using the supplied detection options. @@ -69,12 +53,13 @@ impl Alignment { /// [`AlignmentError::EmptySequence`] if any sequence in `seqs` has an empty sequence. /// /// [`AlignmentError::LengthMismatch`] if the sequences in `seqs` do not all have the same length. - pub fn new_with( + pub fn new_with_detection_options( seqs: impl IntoIterator, options: DetectionOptions, ) -> Result { - let data = AlignmentData::from_raw(seqs.into_iter().collect())?; - let detected = detect_alignment_type(&data, options, &mut rand::rng()); + let data = data_from_raw_sequences(seqs)?; + let mut rng = StdRng::seed_from_u64(DETECTION_SEED); + let detected = detect_alignment_type(&data, options, &mut rng); Ok(Self::from_data(data, detected)) } @@ -90,17 +75,38 @@ impl Alignment { /// [`AlignmentError::EmptySequence`] if any sequence in `seqs` has an empty sequence. /// /// [`AlignmentError::LengthMismatch`] if the sequences in `seqs` do not all have the same length. - pub fn new_with_type( + pub(crate) fn new_with_type( seqs: impl IntoIterator, kind: AlignmentType, ) -> Result { - let data = AlignmentData::from_raw(seqs.into_iter().collect())?; + let data = data_from_raw_sequences(seqs)?; Ok(Self::from_data(data, kind)) } -} -// getter methods -impl Alignment { + pub(crate) fn from_data(data: AlignmentData, alignment_type: AlignmentType) -> Self { + let rows = Projection::Full { + len: data.sequences.len(), + }; + let columns = Projection::Full { len: data.length }; + Self { + data: Arc::new(data), + detected_type: alignment_type, + active_type: alignment_type, + rows, + columns, + } + } + + pub(crate) fn with_projections(&self, rows: Projection, columns: Projection) -> Self { + Self { + data: Arc::clone(&self.data), + detected_type: self.detected_type, + active_type: self.active_type, + rows, + columns, + } + } + /// Returns the number of visible sequences. /// /// This is the length of the alignment's current row projection. For a filtered alignment, it @@ -126,7 +132,7 @@ impl Alignment { .sequences .get(abs_row) .expect("selected row must exist") - .id() + .id .chars() .count() }) @@ -134,43 +140,43 @@ impl Alignment { .unwrap_or(0) } - /// Returns a [`SequenceView`] for the visible sequence at `relative_row`. + /// Returns a [`RowView`] for the visible sequence at `relative_row`. /// /// The row index is relative to this alignment's current row projection, so `0` refers to the first /// visible sequence rather than the first sequence in the underlying data. The returned - /// [`SequenceView`] also uses this alignment's current column projection and active kind. + /// [`RowView`] also uses this alignment's current column projection and active kind. /// /// Returns `None` if `relative_row` does not refer to a visible row. - pub fn sequence(&self, relative_row: usize) -> Option> { + pub fn sequence(&self, relative_row: usize) -> Option> { let abs_row = self.rows.absolute(relative_row)?; let seq = self.data.sequences.get(abs_row)?; - Some(SequenceView { + Some(RowView { absolute_row_id: abs_row, - id: seq.id(), - data: seq.sequence(), + id: &seq.id, + data: &seq.sequence, columns: &self.columns, }) } - /// Returns a [`SequenceView`] for the visible sequence at `absolute_row`. + /// Returns a [`RowView`] for the visible sequence at `absolute_row`. /// /// The row index refers to the underlying alignment data rather than this alignment's current row - /// projection. The returned [`SequenceView`] is produced only if that absolute row is still visible + /// projection. The returned [`RowView`] is produced only if that absolute row is still visible /// in this alignment, and it uses this alignment's current column projection and active kind. /// /// Returns `None` if `absolute_row` is out of bounds or refers to a row that is not visible. - pub fn sequence_by_absolute(&self, absolute_row: usize) -> Option> { + pub(crate) fn sequence_by_absolute(&self, absolute_row: usize) -> Option> { self.rows.relative(absolute_row)?; let seq = self.data.sequences.get(absolute_row)?; - Some(SequenceView { + Some(RowView { absolute_row_id: absolute_row, - id: seq.id(), - data: seq.sequence(), + id: &seq.id, + data: &seq.sequence, columns: &self.columns, }) } - /// Returns a [`SequenceView`] for the absolute row but projected + /// Returns a [`RowView`] for the absolute row but projected /// through this alignment's current column projection. /// /// Unlike [`sequence_by_absolute`], this method does not require `abs_row` @@ -178,19 +184,16 @@ impl Alignment { /// /// Returns `None` only when `abs_row` is out of bounds for the underlying /// alignment data. - pub fn project_absolute_row(&self, abs_row: usize) -> Option> { + pub fn project_absolute_row(&self, abs_row: usize) -> Option> { let seq = self.data.sequences.get(abs_row)?; - Some(SequenceView { + Some(RowView { absolute_row_id: abs_row, - id: seq.id(), - data: seq.sequence(), + id: &seq.id, + data: &seq.sequence, columns: &self.columns, }) } -} -// coordinate functions -impl Alignment { /// Returns the absolute row index for `relative`, or `None` if `relative` is not visible. pub fn absolute_row_id(&self, relative: usize) -> Option { self.rows.absolute(relative) @@ -202,7 +205,7 @@ impl Alignment { } /// Returns an iterator over the visible rows absolute index. - pub fn absolute_row_ids(&self) -> impl ExactSizeIterator + '_ { + pub(crate) fn absolute_row_ids(&self) -> impl ExactSizeIterator + '_ { self.rows.iter() } @@ -220,14 +223,6 @@ impl Alignment { pub fn relative_column_id(&self, absolute: usize) -> Option { self.columns.relative(absolute) } -} - -// type and overrides -impl Alignment { - /// Returns the type that was assigned when this alignment was created. - pub fn detected_type(&self) -> AlignmentType { - self.detected_type - } /// Returns the type currently used to interpret this alignment. pub fn active_type(&self) -> AlignmentType { @@ -239,14 +234,6 @@ impl Alignment { self.active_type = alignment_type; } - /// Clears any active type override and restores the detected type. - pub fn clear_override_type(&mut self) { - self.active_type = self.detected_type; - } -} - -// operations -impl Alignment { /// Creates a lazy translated view over this alignment with a specific translation table. /// /// # Errors @@ -298,6 +285,7 @@ impl Alignment { kind: self.active_type, }); } + Ok(FilterBuilder::new(self)) } @@ -307,7 +295,22 @@ impl Alignment { } } -impl<'a> SequenceView<'a> { +/// A borrowed view of one sequence row within an [`Alignment`]. +/// +/// `RowView` does not own sequence data. Instead, it exposes a single row +/// from an alignment together with that alignment's current column projection +/// and active kind. This means its column-based accessors operate on the +/// visible columns of the parent alignment rather than the full +/// underlying sequence. +#[derive(Debug, Clone, Copy)] +pub struct RowView<'a> { + absolute_row_id: usize, + id: &'a str, + data: &'a [u8], + columns: &'a Projection, +} + +impl<'a> RowView<'a> { /// Returns the absolute row index of this sequence. pub fn absolute_row_id(&self) -> usize { self.absolute_row_id @@ -326,11 +329,6 @@ impl<'a> SequenceView<'a> { self.columns.len() } - /// Returns `true` when there are no visible columns. - pub fn is_empty(&self) -> bool { - self.columns.is_empty() - } - /// Returns the byte at `relative_col`, or `None` if the column is out of bounds. /// /// The column index is relative to this view's column projection. @@ -371,36 +369,14 @@ impl<'a> SequenceView<'a> { } } -impl Alignment { - pub(crate) fn from_data(data: AlignmentData, alignment_type: AlignmentType) -> Self { - let rows = Projection::Full { - len: data.sequences.len(), - }; - let columns = Projection::Full { len: data.length }; - Self { - data: Arc::new(data), - detected_type: alignment_type, - active_type: alignment_type, - rows, - columns, - } - } - - pub(crate) fn from_selection( - data: Arc, - detected_kind: AlignmentType, - active_kind: AlignmentType, - rows: Projection, - columns: Projection, - ) -> Self { - Self { - data, - detected_type: detected_kind, - active_type: active_kind, - rows, - columns, - } - } +fn data_from_raw_sequences( + sequences: impl IntoIterator, +) -> Result { + let sequences = sequences + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?; + AlignmentData::new(sequences) } #[cfg(test)] @@ -420,7 +396,7 @@ mod alignment_construction_tests { let alignment = Alignment::new(vec![raw("seq-1", b"ACGT"), raw("seq-2", b"TGCA")]).unwrap(); assert_eq!(alignment.column_count(), 4); assert_eq!(alignment.row_count(), 2); - assert_eq!(alignment.detected_type(), AlignmentType::Dna); + assert_eq!(alignment.active_type(), AlignmentType::Dna); } #[test] @@ -430,7 +406,6 @@ mod alignment_construction_tests { AlignmentType::Protein, ) .unwrap(); - assert_eq!(alignment.detected_type(), AlignmentType::Protein); assert_eq!(alignment.active_type(), AlignmentType::Protein); } @@ -447,16 +422,12 @@ mod alignment_construction_tests { } #[test] - fn override_type_methods_work() { + fn override_type_method_updates_active_type() { let mut alignment = Alignment::new(vec![raw("seq-1", b"ACGT"), raw("seq-2", b"TGCA")]).unwrap(); alignment.set_override_type(AlignmentType::Protein); - assert_eq!(alignment.detected_type(), AlignmentType::Dna); assert_eq!(alignment.active_type(), AlignmentType::Protein); - - alignment.clear_override_type(); - assert_eq!(alignment.active_type(), AlignmentType::Dna); } #[test] @@ -525,10 +496,7 @@ mod alignment_access_tests { #[should_panic(expected = "selected row must exist")] fn max_id_len_panics_for_invalid_row_projection() { let alignment = Alignment::new(vec![raw("s1", b"AC")]).unwrap(); - let filtered = Alignment::from_selection( - alignment.data.clone(), - alignment.detected_type(), - alignment.active_type(), + let filtered = alignment.with_projections( Projection::Filtered(Arc::from(vec![1usize])), Projection::Full { len: alignment.column_count(), @@ -542,7 +510,7 @@ mod alignment_access_tests { fn sequence_by_absolute_full() { let alignment = Alignment::new(vec![raw("s1", b"AC"), raw("s2", b"TG")]).unwrap(); let sv = alignment.sequence_by_absolute(1).unwrap(); - assert_eq!(sv.id(), "s2"); + assert_eq!(sv.id, "s2"); assert!(alignment.sequence_by_absolute(2).is_none()); } @@ -574,10 +542,7 @@ mod alignment_access_tests { #[test] fn indexed_bytes_range_filtered() { let alignment = Alignment::new(vec![raw("s1", b"ACGT")]).unwrap(); - let filtered = Alignment::from_selection( - alignment.data.clone(), - alignment.detected_type(), - alignment.active_type(), + let filtered = alignment.with_projections( Projection::Full { len: alignment.row_count(), }, @@ -634,7 +599,7 @@ mod alignment_projection_tests { (base, filtered) } - fn indexed_bytes(view: SequenceView<'_>) -> Vec<(usize, u8)> { + fn indexed_bytes(view: RowView<'_>) -> Vec<(usize, u8)> { view.indexed_bytes_range(0..view.len()).unwrap().collect() } @@ -662,10 +627,7 @@ mod alignment_projection_tests { raw("s3", b"AAAA"), ]) .unwrap(); - let filtered = Alignment::from_selection( - alignment.data.clone(), - alignment.detected_type(), - alignment.active_type(), + let filtered = alignment.with_projections( Projection::Filtered(Arc::from(vec![0, 2])), Projection::Filtered(Arc::from(vec![1, 3])), ); @@ -714,7 +676,7 @@ mod alignment_projection_tests { assert!(filtered.sequence_by_absolute(1).is_none()); let sv = filtered.project_absolute_row(1).unwrap(); - assert_eq!(sv.id(), "s2"); + assert_eq!(sv.id, "s2"); assert_eq!(sv.absolute_row_id(), 1); } @@ -726,7 +688,7 @@ mod alignment_projection_tests { let via_sba = filtered.sequence_by_absolute(abs).unwrap(); let via_proj = filtered.project_absolute_row(abs).unwrap(); - assert_eq!(via_sba.id(), via_proj.id()); + assert_eq!(via_sba.id, via_proj.id); assert_eq!(via_sba.absolute_row_id(), via_proj.absolute_row_id()); assert_eq!(via_sba.len(), via_proj.len()); assert_eq!(indexed_bytes(via_sba), indexed_bytes(via_proj)); @@ -736,10 +698,7 @@ mod alignment_projection_tests { #[test] fn column_projection_applied_to_excluded_row() { let base = Alignment::new(vec![raw("visible", b"ACGT"), raw("excluded", b"TTCA")]).unwrap(); - let col_filtered = Alignment::from_selection( - base.data.clone(), - base.detected_type(), - base.active_type(), + let col_filtered = base.with_projections( Projection::Filtered(Arc::from(vec![0usize])), Projection::Filtered(Arc::from(vec![0usize, 2])), ); diff --git a/libmsa/src/projection.rs b/libmsa/src/projection.rs index c71d776..5ed3d5a 100644 --- a/libmsa/src/projection.rs +++ b/libmsa/src/projection.rs @@ -19,10 +19,6 @@ impl Projection { } } - pub(crate) fn is_empty(&self) -> bool { - self.len() == 0 - } - pub(crate) fn absolute(&self, relative: usize) -> Option { match self { Self::Full { len } => (relative < *len).then_some(relative), @@ -77,7 +73,6 @@ mod tests { fn full_projection_basics() { let proj = Projection::Full { len: 5 }; assert_eq!(proj.len(), 5); - assert!(!proj.is_empty()); assert!(proj.is_full()); assert_eq!(proj.absolute(0), Some(0)); assert_eq!(proj.absolute(4), Some(4)); @@ -88,7 +83,6 @@ mod tests { fn filtered_projection_basics() { let proj = Projection::Filtered(Arc::from([1, 3, 7].as_slice())); assert_eq!(proj.len(), 3); - assert!(!proj.is_empty()); assert!(!proj.is_full()); assert_eq!(proj.absolute(0), Some(1)); assert_eq!(proj.absolute(1), Some(3)); @@ -99,11 +93,9 @@ mod tests { #[test] fn empty_projections() { let full = Projection::Full { len: 0 }; - assert!(full.is_empty()); assert_eq!(full.iter().count(), 0); let filtered = Projection::Filtered(Arc::from([].as_slice())); - assert!(filtered.is_empty()); assert_eq!(filtered.iter().count(), 0); } #[test] From 43fb112c412415f2dcca25921e36894483f5f9ea Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Tue, 31 Mar 2026 21:11:00 +0100 Subject: [PATCH 05/48] feat(libmsa): make file detection deterministic --- libmsa/src/detection.rs | 20 ++++++++++++-------- libmsa/src/model.rs | 4 ++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/libmsa/src/detection.rs b/libmsa/src/detection.rs index 62937b6..edfd6e7 100644 --- a/libmsa/src/detection.rs +++ b/libmsa/src/detection.rs @@ -6,19 +6,18 @@ use crate::alignment_type::AlignmentType; use crate::data::AlignmentData; use crate::error::AlignmentError; -// cant be zero const DEFAULT_SAMPLE_SIZE: usize = 100; const DEFAULT_CLASSIFICATION_THRESHOLD: f32 = 0.5; -const NUCLEOTIDE_BYTES: &[u8] = b"ACGTURYSWKMBDHVN-."; -const PROTEIN_BYTES: &[u8] = b"DEFHIKLMNPQRSVWYX-."; +const NUCLEOTIDE_BYTES: &[u8] = b"ACGTURYSWKMBDHVN-"; +const PROTEIN_BYTES: &[u8] = b"DEFHIKLMNPQRSVWYX-"; /// Options that control alignment type detection. #[derive(Debug, Clone, Copy, PartialEq)] pub struct DetectionOptions { /// The maximum number of sequences to sample when classifying an alignment. sample_size: NonZeroUsize, - /// The minimum fraction of observed non-gap symbols that must match a - /// before that classification is accepted. + /// The minimum fraction of observed non-gap symbols that must match before + /// that classification is accepted. classification_threshold: f32, } @@ -71,8 +70,8 @@ pub(crate) fn detect_alignment_type( let (protein_count, nucleotide_count, total_count) = alignment .sequences .choose_multiple(rng, options.sample_size()) - .flat_map(|sequence| sequence.sequence().iter().copied()) - .filter(|byte| !matches!(byte, b'-' | b'.')) + .flat_map(|sequence| sequence.sequence.iter().copied()) + .filter(|byte| !matches!(byte, b'-')) .map(|byte| byte.to_ascii_uppercase()) .fold( (0usize, 0usize, 0usize), @@ -124,7 +123,12 @@ mod detect_alignment_type_tests { } fn make_data(rows: &[(&str, &[u8])]) -> AlignmentData { - AlignmentData::from_raw(rows.iter().map(|(id, seq)| raw(id, seq)).collect()).unwrap() + let sequences = rows + .iter() + .map(|(id, seq)| raw(id, seq).try_into()) + .collect::, _>>() + .unwrap(); + AlignmentData::new(sequences).unwrap() } fn detect_with_seed( diff --git a/libmsa/src/model.rs b/libmsa/src/model.rs index a2d3bf8..7f2368b 100644 --- a/libmsa/src/model.rs +++ b/libmsa/src/model.rs @@ -1,6 +1,8 @@ use std::ops::Range; use std::sync::Arc; +use rand::{SeedableRng, rngs::StdRng}; + use crate::alignment_type::AlignmentType; use crate::data::{AlignmentData, RawSequence}; use crate::detection::{DetectionOptions, detect_alignment_type}; @@ -9,6 +11,8 @@ use crate::filter::FilterBuilder; use crate::projection::Projection; use crate::translation::{ReadingFrame, TranslatedAlignment, TranslationTable}; +const DETECTION_SEED: u64 = u64::from_be_bytes(*b"REDRIGHT"); + /// A multiple sequence alignment. /// /// `Alignment` stores a set of equal-length sequences together with From d754c45f3bee5f385ed04334a9bd92248699b55e Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Tue, 31 Mar 2026 21:51:00 +0100 Subject: [PATCH 06/48] refactor(libmsa): I AINT GONNA NEED IT --- libmsa/src/metrics.rs | 415 ++---------------------------------------- 1 file changed, 17 insertions(+), 398 deletions(-) diff --git a/libmsa/src/metrics.rs b/libmsa/src/metrics.rs index 716adb0..a7cfc6a 100644 --- a/libmsa/src/metrics.rs +++ b/libmsa/src/metrics.rs @@ -8,6 +8,14 @@ use crate::model::Alignment; use crate::projection::Projection; use crate::translation::{ReadingFrame, TranslationTable, translated_byte_at}; +/// Calculated values for a single alignment column. +#[derive(Debug, Clone, PartialEq)] +pub struct ColumnSummary { + pub position: usize, + pub consensus: Option, + pub conservation: Option, +} + /// Selects how consensus bytes are chosen for alignment columns. /// /// Different methods vary in whether gap characters are considered when @@ -52,127 +60,7 @@ impl std::str::FromStr for ConsensusMethod { } } -/// Calculated values for a single alignment column. -#[derive(Debug, Clone, PartialEq)] -pub struct ColumnSummary { - pub position: usize, - pub consensus: Option, - pub conservation: Option, - pub gap_fraction: f32, -} - -pub(crate) struct CountedColumn { - pub position: usize, - pub counts: [u32; 256], -} - -// alignment metrics impl Alignment { - /// Returns the consensus byte for each requested relative column. - /// - /// Each position is resolved against the alignment's current column projection. - /// The returned vector keeps the requested relative positions and contains one - /// consensus byte for each visible column named in `positions`. - /// - /// # Errors - /// - /// [`AlignmentError::ColumnOutOfBounds`] if any value in `positions` is not a - /// valid index in the current column projection. - pub fn consensus_positions( - &self, - positions: &[usize], - method: ConsensusMethod, - ) -> Result)>, AlignmentError> { - let columns = counted_columns_positions(&self.data, &self.rows, &self.columns, positions)?; - let mut rng = rand::rng(); - Ok(consensus_from_columns(&columns, method, &mut rng)) - } - - /// Returns the conservation score for each requested relative column. - /// - /// Each position is resolved against the alignment's current column projection. - /// The returned vector keeps the requested relative positions and contains one - /// conservation score for each visible column named in `positions`. - /// - /// # Errors - /// - /// [`AlignmentError::ColumnOutOfBounds`] if any value in `positions` is not a - /// valid index in the current column projection. - /// - /// [`AlignmentError::ConservationUndefined`] if the active alignment kind does not - /// define a conservation alphabet size. - pub fn conservation_positions( - &self, - positions: &[usize], - ) -> Result, AlignmentError> { - let columns = counted_columns_positions(&self.data, &self.rows, &self.columns, positions)?; - conservation_from_columns(&columns, self.active_type().conservation_alphabet_size()) - } - - /// Returns the gap fraction for each requested relative column. - /// - /// Each position is resolved against the alignment's current column projection. - /// The returned vector keeps the requested relative positions and contains one - /// gap fraction for each visible column named in `positions`. - /// - /// # Errors - /// - /// [`AlignmentError::ColumnOutOfBounds`] if any value in `positions` is not a - /// valid index in the current column projection. - pub fn gap_fraction_positions( - &self, - positions: &[usize], - ) -> Result, AlignmentError> { - let columns = counted_columns_positions(&self.data, &self.rows, &self.columns, positions)?; - Ok(gap_fraction_from_columns(&columns)) - } - - /// Returns the gap fraction for each relative column in `range`. - /// - /// Each position is resolved against the alignment's current column projection. - /// The returned vector keeps the requested relative positions and contains one - /// gap fraction for each visible column in `range`. - /// - /// # Errors - /// - /// [`AlignmentError::EmptyRange`] if `range` is empty. - /// - /// [`AlignmentError::ColumnOutOfBounds`] if `range.end` is greater than the - /// current column projection width. - pub fn gap_fraction_range( - &self, - range: Range, - ) -> Result, AlignmentError> { - let columns = counted_columns_range(&self.data, &self.rows, &self.columns, range)?; - Ok(gap_fraction_from_columns(&columns)) - } - - /// Returns a derived summary for each requested relative column. - /// - /// Each position is resolved against the alignment's current column projection. - /// The returned vector keeps the requested relative positions and contains a - /// [`ColumnSummary`] with consensus, gap fraction, and conservation when that - /// measure is defined for the active alignment kind. - /// - /// # Errors - /// - /// [`AlignmentError::ColumnOutOfBounds`] if any value in `positions` is not a - /// valid index in the current column projection. - pub fn column_summaries_positions( - &self, - positions: &[usize], - method: ConsensusMethod, - ) -> Result, AlignmentError> { - let columns = counted_columns_positions(&self.data, &self.rows, &self.columns, positions)?; - let mut rng = rand::rng(); - Ok(summaries_from_columns( - &columns, - method, - self.active_type().conservation_alphabet_size(), - &mut rng, - )) - } - /// Returns a derived summary for each column in `range`. /// /// Each position is resolved against the alignment's current column projection. @@ -206,29 +94,9 @@ impl Alignment { } } -pub(crate) fn counted_columns_positions( - data: &AlignmentData, - rows: &Projection, - columns: &Projection, - relative_positions: &[usize], -) -> Result, AlignmentError> { - relative_positions - .iter() - .copied() - .map(|rel_col| { - let abs_col = columns - .absolute(rel_col) - .ok_or(AlignmentError::ColumnOutOfBounds { - index: rel_col, - length: columns.len(), - })?; - - Ok(CountedColumn { - position: rel_col, - counts: column_byte_counts(data, rows, abs_col), - }) - }) - .collect() +pub(crate) struct CountedColumn { + pub position: usize, + pub counts: [u32; 256], } pub(crate) fn counted_columns_range( @@ -243,7 +111,7 @@ pub(crate) fn counted_columns_range( if range.end > columns.len() { return Err(AlignmentError::ColumnOutOfBounds { - index: range.end, + index: range.end - 1, length: columns.len(), }); } @@ -262,34 +130,6 @@ pub(crate) fn counted_columns_range( .collect()) } -pub(crate) fn counted_translated_columns_positions( - data: &AlignmentData, - rows: &Projection, - positions: &[usize], - frame: ReadingFrame, - table: &TranslationTable, -) -> Result, AlignmentError> { - let translated_len = frame.translated_length(data.length); - - positions - .iter() - .copied() - .map(|protein_col| { - if protein_col >= translated_len { - return Err(AlignmentError::ColumnOutOfBounds { - index: protein_col, - length: translated_len, - }); - } - - Ok(CountedColumn { - position: protein_col, - counts: translated_column_byte_counts(data, rows, protein_col, frame, table), - }) - }) - .collect() -} - pub(crate) fn counted_translated_columns_range( data: &AlignmentData, rows: &Projection, @@ -304,7 +144,7 @@ pub(crate) fn counted_translated_columns_range( let translated_len = frame.translated_length(data.length); if range.end > translated_len { return Err(AlignmentError::ColumnOutOfBounds { - index: range.end, + index: range.end - 1, length: translated_len, }); } @@ -317,48 +157,6 @@ pub(crate) fn counted_translated_columns_range( .collect()) } -pub(crate) fn consensus_from_columns( - columns: &[CountedColumn], - method: ConsensusMethod, - rng: &mut impl rand::Rng, -) -> Vec<(usize, Option)> { - columns - .iter() - .map(|column| { - ( - column.position, - consensus_from_counts(&column.counts, method, rng), - ) - }) - .collect() -} - -pub(crate) fn conservation_from_columns( - columns: &[CountedColumn], - alphabet_size: Option, -) -> Result, AlignmentError> { - let max_entropy = alphabet_size - .map(|value| f64::from(value.get()).log2()) - .ok_or(AlignmentError::ConservationUndefined)?; - - Ok(columns - .iter() - .map(|column| { - ( - column.position, - conservation_from_counts(&column.counts, max_entropy), - ) - }) - .collect()) -} - -pub(crate) fn gap_fraction_from_columns(columns: &[CountedColumn]) -> Vec<(usize, f32)> { - columns - .iter() - .map(|column| (column.position, gap_fraction_from_counts(&column.counts))) - .collect() -} - #[inline] const fn is_gap_byte(byte: u8) -> bool { matches!(byte, b'-') @@ -379,7 +177,6 @@ pub(crate) fn summaries_from_columns( consensus: consensus_from_counts(&column.counts, method, rng), conservation: max_entropy .map(|max_entropy| conservation_from_counts(&column.counts, max_entropy)), - gap_fraction: gap_fraction_from_counts(&column.counts), }) .collect() } @@ -526,7 +323,7 @@ fn column_byte_counts(data: &AlignmentData, rows: &Projection, abs_col: usize) - .sequences .get(abs_row) .expect("selected row must exist"); - counts[usize::from(sequence.sequence()[abs_col])] += 1; + counts[usize::from(sequence.sequence[abs_col])] += 1; } counts @@ -546,7 +343,7 @@ fn translated_column_byte_counts( .sequences .get(abs_row) .expect("selected row must exist"); - let byte = translated_byte_at(sequence.sequence(), protein_col, frame, table) + let byte = translated_byte_at(&sequence.sequence, protein_col, frame, table) .expect("validated translated range"); counts[usize::from(byte)] += 1; } @@ -623,7 +420,7 @@ mod derived_column_tests { use rand::{SeedableRng, rngs::StdRng}; - use super::{ConsensusMethod, CountedColumn, consensus_from_columns, summaries_from_columns}; + use super::{ConsensusMethod, CountedColumn, summaries_from_columns}; fn counted_column(position: usize, symbols: &[u8]) -> CountedColumn { let mut counts = [0u32; 256]; @@ -634,33 +431,6 @@ mod derived_column_tests { CountedColumn { position, counts } } - #[test] - fn consensus_from_columns_returns_known_consensus() { - let columns = vec![counted_column(2, b"AAAA"), counted_column(4, b"CCCC")]; - let mut rng = StdRng::seed_from_u64(6); - - assert_eq!( - consensus_from_columns(&columns, ConsensusMethod::MajorityNonGap, &mut rng), - vec![(2, Some(b'A')), (4, Some(b'C'))] - ); - } - - #[test] - fn consensus_from_columns_respects_gap_handling() { - let columns = vec![counted_column(1, b"--A")]; - let mut majority_rng = StdRng::seed_from_u64(7); - let mut nongap_rng = StdRng::seed_from_u64(7); - - assert_eq!( - consensus_from_columns(&columns, ConsensusMethod::Majority, &mut majority_rng), - vec![(1, Some(b'-'))] - ); - assert_eq!( - consensus_from_columns(&columns, ConsensusMethod::MajorityNonGap, &mut nongap_rng,), - vec![(1, Some(b'A'))] - ); - } - #[test] fn summaries_from_columns_return_none_for_all_gap_column() { let columns = vec![counted_column(3, b"---")]; @@ -676,7 +446,6 @@ mod derived_column_tests { assert_eq!(summaries[0].position, 3); assert_eq!(summaries[0].consensus, None); assert_eq!(summaries[0].conservation, Some(0.0)); - assert_eq!(summaries[0].gap_fraction, 1.0); } #[test] @@ -694,11 +463,9 @@ mod derived_column_tests { assert_eq!(summaries[0].position, 0); assert_eq!(summaries[0].consensus, Some(b'A')); assert_eq!(summaries[0].conservation, Some(1.0)); - assert_eq!(summaries[0].gap_fraction, 0.0); assert_eq!(summaries[1].position, 1); assert_eq!(summaries[1].consensus, None); assert_eq!(summaries[1].conservation, Some(0.0)); - assert_eq!(summaries[1].gap_fraction, 1.0); } } @@ -804,7 +571,7 @@ mod constant_fraction_count_tests { #[cfg(test)] mod tests { - use crate::{Alignment, AlignmentError, AlignmentType, ConsensusMethod, RawSequence}; + use crate::{Alignment, AlignmentType, ConsensusMethod, RawSequence}; fn raw(id: &str, sequence: &[u8]) -> RawSequence { RawSequence { @@ -813,80 +580,6 @@ mod tests { } } - #[test] - fn consensus_positions_returns_single_column() { - let alignment = Alignment::new_with_type( - vec![raw("s1", b"ACGT"), raw("s2", b"ACGT")], - AlignmentType::Dna, - ) - .unwrap(); - - assert_eq!( - alignment - .consensus_positions(&[1], ConsensusMethod::MajorityNonGap) - .unwrap(), - vec![(1, Some(b'C'))] - ); - } - - #[test] - fn consensus_positions_returns_correct_positions() { - let alignment = Alignment::new_with_type( - vec![raw("s1", b"ACGT"), raw("s2", b"ACGT")], - AlignmentType::Dna, - ) - .unwrap(); - - assert_eq!( - alignment - .consensus_positions(&[1, 2], ConsensusMethod::MajorityNonGap) - .unwrap(), - vec![(1, Some(b'C')), (2, Some(b'G'))] - ); - } - - #[test] - fn translated_consensus_range_returns_protein_positions() { - let alignment = Alignment::new_with_type( - vec![raw("s1", b"ATGAAA"), raw("s2", b"ATGAAG")], - AlignmentType::Dna, - ) - .unwrap(); - - assert_eq!( - alignment - .translated(crate::ReadingFrame::Frame1) - .unwrap() - .consensus_range(0..2, ConsensusMethod::MajorityNonGap) - .unwrap(), - vec![(0, Some(b'M')), (1, Some(b'K'))] - ); - } - - #[test] - fn translated_column_summaries_positions_return_protein_metrics() { - let alignment = Alignment::new_with_type( - vec![raw("s1", b"GCT"), raw("s2", b"GCC")], - AlignmentType::Dna, - ) - .unwrap(); - - let raw_summary = alignment - .column_summaries_positions(&[2], ConsensusMethod::MajorityNonGap) - .unwrap(); - let translated_summary = alignment - .translated(crate::ReadingFrame::Frame1) - .unwrap() - .column_summaries_positions(&[0], ConsensusMethod::MajorityNonGap) - .unwrap(); - - assert_eq!(translated_summary.len(), 1); - assert_eq!(translated_summary[0].position, 0); - assert_eq!(translated_summary[0].consensus, Some(b'A')); - assert_eq!(translated_summary[0].conservation, Some(1.0)); - assert!(raw_summary[0].conservation.unwrap() < 1.0); - } - #[test] fn column_summaries_range_returns_requested_positions() { let alignment = @@ -903,78 +596,4 @@ mod tests { vec![0, 1] ); } - - #[test] - fn conservation_positions_returns_score() { - let alignment = - Alignment::new_with_type(vec![raw("s1", b"A"), raw("s2", b"A")], AlignmentType::Dna) - .unwrap(); - - assert_eq!( - alignment.conservation_positions(&[0]).unwrap(), - vec![(0, 1.0)] - ); - } - - #[test] - fn gap_fraction_range_returns_requested_positions() { - let alignment = - Alignment::new_with_type(vec![raw("s1", b"A-"), raw("s2", b"--")], AlignmentType::Dna) - .unwrap(); - - assert_eq!( - alignment.gap_fraction_range(0..2).unwrap(), - vec![(0, 0.5), (1, 1.0)] - ); - } - - #[test] - fn conservation_positions_is_undefined_for_generic() { - let alignment = Alignment::new_with_type( - vec![raw("s1", b"A"), raw("s2", b"A")], - AlignmentType::Generic, - ) - .unwrap(); - - assert_eq!( - alignment.conservation_positions(&[0]), - Err(AlignmentError::ConservationUndefined) - ); - } - - #[test] - fn gap_fraction_positions_returns_values() { - let alignment = Alignment::new_with_type( - vec![raw("s1", b"A-"), raw("s2", b"--"), raw("s3", b"AA")], - AlignmentType::Dna, - ) - .unwrap(); - - let fractions = alignment.gap_fraction_positions(&[0, 1]).unwrap(); - assert!((fractions[0].1 - (1.0 / 3.0)).abs() < f32::EPSILON); - assert!((fractions[1].1 - (2.0 / 3.0)).abs() < f32::EPSILON); - } - - #[test] - fn column_summaries_positions_returns_all_metrics() { - let alignment = Alignment::new_with_type( - vec![raw("s1", b"A-"), raw("s2", b"--"), raw("s3", b"AA")], - AlignmentType::Dna, - ) - .unwrap(); - - let summaries = alignment - .column_summaries_positions(&[0, 1], ConsensusMethod::MajorityNonGap) - .unwrap(); - - assert_eq!(summaries.len(), 2); - assert_eq!(summaries[0].position, 0); - assert_eq!(summaries[0].consensus, Some(b'A')); - assert!(summaries[0].conservation.is_some()); - assert!((summaries[0].gap_fraction - (1.0 / 3.0)).abs() < f32::EPSILON); - assert_eq!(summaries[1].position, 1); - assert_eq!(summaries[1].consensus, Some(b'A')); - assert!(summaries[1].conservation.is_some()); - assert!((summaries[1].gap_fraction - (2.0 / 3.0)).abs() < f32::EPSILON); - } } From 1dcdfbea0f510b2f4dd9e12ad6d3aa70a11356af Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 1 Apr 2026 18:36:00 +0100 Subject: [PATCH 07/48] feat(libmsa): parallelise column counting with rayon --- Cargo.lock | 1 + libmsa/Cargo.toml | 1 + libmsa/src/filter.rs | 157 ++++++++++++++---------------------------- libmsa/src/metrics.rs | 3 + 4 files changed, 55 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc7702d..f5de70e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1425,6 +1425,7 @@ name = "libmsa" version = "0.1.0" dependencies = [ "rand 0.9.2", + "rayon", "regex", "thiserror 2.0.18", ] diff --git a/libmsa/Cargo.toml b/libmsa/Cargo.toml index 3af67e8..30ae242 100644 --- a/libmsa/Cargo.toml +++ b/libmsa/Cargo.toml @@ -12,5 +12,6 @@ categories = ["command-line-utilities", "science"] [dependencies] rand = "0.9" +rayon = "1.11" regex = "1.12.3" thiserror = "2.0.18" diff --git a/libmsa/src/filter.rs b/libmsa/src/filter.rs index 7c4d179..ce0a368 100644 --- a/libmsa/src/filter.rs +++ b/libmsa/src/filter.rs @@ -1,6 +1,7 @@ use std::borrow::Borrow; use std::sync::Arc; +use rayon::prelude::*; use regex::Regex; use crate::error::AlignmentError; @@ -28,6 +29,16 @@ pub struct FilterBuilder<'a> { } impl<'a> FilterBuilder<'a> { + pub(crate) fn new(source: &'a Alignment) -> Self { + Self { + source, + row_exclude_sets: Vec::new(), + row_name_regex: None, + max_gap_fraction: None, + min_constant_fraction: None, + } + } + /// Excludes the supplied rows from the filtered view. pub fn without_rows(mut self, row_ids: I) -> Self where @@ -57,7 +68,7 @@ impl<'a> FilterBuilder<'a> { self } - /// Resolves all filters and builds a new [`Alignment`] + /// Resolves all filters and builds a new [`Alignment`]. pub fn apply(self) -> Result { let row_count = self.source.row_count(); let column_count = self.source.column_count(); @@ -92,31 +103,35 @@ impl<'a> FilterBuilder<'a> { let mut column_ids: Vec = (0..column_count).collect(); if self.max_gap_fraction.is_some() || self.min_constant_fraction.is_some() { - let temp_rows = Projection::Filtered(Arc::from(row_ids.as_slice())); - let columns = metrics::counted_columns_range( - &self.source.data, - &temp_rows, - &self.source.columns, - 0..column_count, - )?; - - column_ids.retain(|&column_id| { - columns.get(column_id).is_none_or(|column| { - let gap_ok = self.max_gap_fraction.is_none_or(|max_gap_fraction| { - metrics::gap_fraction_from_counts(&column.counts) <= max_gap_fraction + let data = &self.source.data; + let active_type = self.source.active_type(); + let max_gap_fraction = self.max_gap_fraction; + let min_constant_fraction = self.min_constant_fraction; + + column_ids = (0..column_count) + .into_par_iter() + .filter_map(|abs_col| { + let mut counts = [0u32; 256]; + + for &abs_row in &row_ids { + let sequence = data + .sequences + .get(abs_row) + .expect("selected row must exist"); + counts[usize::from(sequence.sequence[abs_col])] += 1; + } + + let gap_ok = max_gap_fraction.is_none_or(|threshold| { + metrics::gap_fraction_from_counts(&counts) <= threshold }); - let constant_ok = - self.min_constant_fraction - .is_none_or(|min_constant_fraction| { - metrics::max_counted_symbol_fraction_from_counts( - &column.counts, - self.source.active_type(), - ) - .is_none_or(|fraction| fraction < min_constant_fraction) - }); - gap_ok && constant_ok + let constant_ok = min_constant_fraction.is_none_or(|threshold| { + metrics::max_counted_symbol_fraction_from_counts(&counts, active_type) + .is_none_or(|fraction| fraction < threshold) + }); + + (gap_ok && constant_ok).then_some(abs_col) }) - }); + .collect(); } let rows_proj = if row_ids.len() == row_count { @@ -131,35 +146,10 @@ impl<'a> FilterBuilder<'a> { Projection::Filtered(Arc::from(column_ids)) }; - Ok(Alignment::from_selection( - Arc::clone(&self.source.data), - self.source.detected_type(), - self.source.active_type(), - rows_proj, - cols_proj, - )) + Ok(self.source.with_projections(rows_proj, cols_proj)) } } -impl<'a> FilterBuilder<'a> { - pub(crate) fn new(source: &'a Alignment) -> Self { - Self { - source, - row_exclude_sets: Vec::new(), - row_name_regex: None, - max_gap_fraction: None, - min_constant_fraction: None, - } - } -} - -fn compile_regex(pattern: &str) -> Result { - Regex::new(pattern).map_err(|error| AlignmentError::InvalidRegex { - pattern: pattern.to_string(), - source: error, - }) -} - fn validate_row_ids(row_ids: &[usize], row_count: usize) -> Result<(), AlignmentError> { let mut seen = vec![false; row_count]; for &row_id in row_ids { @@ -173,6 +163,7 @@ fn validate_row_ids(row_ids: &[usize], row_count: usize) -> Result<(), Alignment return Err(AlignmentError::DuplicateRowIndex { index: row_id }); } } + Ok(()) } @@ -192,11 +183,16 @@ fn validate_constant_fraction(threshold: f32) -> Result<(), AlignmentError> { Err(AlignmentError::InvalidConstantFraction(threshold)) } +fn compile_regex(pattern: &str) -> Result { + Regex::new(pattern).map_err(|error| AlignmentError::InvalidRegex { + pattern: pattern.to_string(), + source: error, + }) +} + #[cfg(test)] mod filter_builder_tests { - use crate::{ - Alignment, AlignmentError, AlignmentType, ColumnSummary, ConsensusMethod, RawSequence, - }; + use crate::{Alignment, AlignmentError, AlignmentType, RawSequence}; fn raw(id: &str, sequence: &[u8]) -> RawSequence { RawSequence { @@ -429,18 +425,6 @@ mod filter_builder_tests { assert_eq!(filtered.absolute_column_ids().collect::>(), vec![1]); } - #[test] - fn column_summaries_positions_empty_returns_empty() { - let alignment = generic_alignment(&[("s1", b"A-"), ("s2", b"--")]); - - assert_eq!( - alignment - .column_summaries_positions(&[], ConsensusMethod::MajorityNonGap) - .unwrap(), - Vec::::new() - ); - } - #[test] fn filtered_alignment_rejects_chained_filter() { let alignment = dna_alignment(&[("s1", b"AC"), ("s2", b"TG")]); @@ -463,7 +447,7 @@ mod filter_builder_tests { #[cfg(test)] mod filtered_alignment_behaviour_tests { - use crate::{Alignment, AlignmentType, ConsensusMethod, RawSequence}; + use crate::{Alignment, AlignmentType, RawSequence}; fn raw(id: &str, sequence: &[u8]) -> RawSequence { RawSequence { @@ -472,16 +456,6 @@ mod filtered_alignment_behaviour_tests { } } - fn dna_alignment(rows: &[(&str, &[u8])]) -> Alignment { - Alignment::new_with_type( - rows.iter() - .map(|(id, seq)| raw(id, seq)) - .collect::>(), - AlignmentType::Dna, - ) - .unwrap() - } - fn generic_alignment(rows: &[(&str, &[u8])]) -> Alignment { Alignment::new_with_type( rows.iter() @@ -513,35 +487,4 @@ mod filtered_alignment_behaviour_tests { ); assert_eq!(filtered.sequence_by_absolute(2).unwrap().id(), "s2"); } - - #[test] - fn filter_consensus_uses_selected_rows() { - let alignment = - generic_alignment(&[("ref", b"TA"), ("s1", b"AC"), ("s2", b"AC"), ("s3", b"TC")]); - - let filtered = alignment - .filter() - .unwrap() - .without_rows([0]) - .apply() - .unwrap(); - let consensus = filtered - .consensus_positions(&[0, 1], ConsensusMethod::MajorityNonGap) - .unwrap(); - - assert_eq!(consensus, vec![(0, Some(b'A')), (1, Some(b'C'))]); - } - - #[test] - fn filter_conservation_uses_selected_rows() { - let alignment = dna_alignment(&[("s1", b"A"), ("s2", b"-"), ("s3", b"A")]); - let filtered = alignment - .filter() - .unwrap() - .without_rows([1]) - .apply() - .unwrap(); - - assert_eq!(filtered.conservation_positions(&[0]), Ok(vec![(0, 1.0)])); - } } diff --git a/libmsa/src/metrics.rs b/libmsa/src/metrics.rs index a7cfc6a..d12328f 100644 --- a/libmsa/src/metrics.rs +++ b/libmsa/src/metrics.rs @@ -1,4 +1,5 @@ use rand::seq::IndexedRandom; +use rayon::prelude::*; use std::{num::NonZeroU8, ops::Range}; use crate::AlignmentType; @@ -117,6 +118,7 @@ pub(crate) fn counted_columns_range( } Ok(range + .into_par_iter() .map(|rel_col| CountedColumn { position: rel_col, counts: column_byte_counts( @@ -150,6 +152,7 @@ pub(crate) fn counted_translated_columns_range( } Ok(range + .into_par_iter() .map(|protein_col| CountedColumn { position: protein_col, counts: translated_column_byte_counts(data, rows, protein_col, frame, table), From 100c01537209f62528562fb6f1e1256bb3ed6ef1 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 1 Apr 2026 20:17:00 +0100 Subject: [PATCH 08/48] feat(libmsa): big speed up of translation through various optimisations 12.1 seconds -> 1.86 seconds for a 10000x300000 alignment --- libmsa/src/translation.rs | 243 +++++++++++++------------------------- 1 file changed, 81 insertions(+), 162 deletions(-) diff --git a/libmsa/src/translation.rs b/libmsa/src/translation.rs index 7502f75..8f0359e 100644 --- a/libmsa/src/translation.rs +++ b/libmsa/src/translation.rs @@ -1,14 +1,34 @@ use std::ops::Range; +use rayon::prelude::*; + use crate::Alignment; use crate::alignment_type::AlignmentType; -use crate::data::{AlignmentData, RawSequence}; use crate::error::AlignmentError; use crate::metrics::{ - ColumnSummary, ConsensusMethod, counted_translated_columns_positions, - counted_translated_columns_range, summaries_from_columns, + ColumnSummary, ConsensusMethod, counted_translated_columns_range, summaries_from_columns, }; +const NUCLEOTIDE_INDEX_TABLE: [u8; 256] = build_nucleotide_index_table(); + +const fn build_nucleotide_index_table() -> [u8; 256] { + // 4 is invalid, only maps valid nts to 0-3 + let mut table = [4; 256]; + + table[b'A' as usize] = 0; + table[b'a' as usize] = 0; + table[b'T' as usize] = 1; + table[b't' as usize] = 1; + table[b'U' as usize] = 1; + table[b'u' as usize] = 1; + table[b'C' as usize] = 2; + table[b'c' as usize] = 2; + table[b'G' as usize] = 3; + table[b'g' as usize] = 3; + + table +} + /// Reading frames for translating. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ReadingFrame { @@ -169,22 +189,6 @@ impl<'a> TranslatedAlignment<'a> { self.translated_column_count } - /// Returns the translated view for one visible row by absolute row id. - /// - /// The row id is resolved against the source alignment's current row - /// projection, not against the translated view itself. Returns `None` when - /// the row is not visible in the source alignment. - pub fn sequence_by_absolute(&self, absolute_row: usize) -> Option> { - let _relative = self.source.relative_row_id(absolute_row)?; - let sequence = self.source.data.sequences.get(absolute_row)?; - Some(TranslatedSequenceView { - data: sequence.sequence(), - frame: self.frame, - table: self.table, - translated_len: self.translated_column_count, - }) - } - /// Returns a [`TranslatedSequenceView`] for the absolute row but projected /// through this alignment's current column projection. /// @@ -197,7 +201,7 @@ impl<'a> TranslatedAlignment<'a> { pub fn project_absolute_row(&self, abs_row: usize) -> Option> { let sequence = self.source.data.sequences.get(abs_row)?; Some(TranslatedSequenceView { - data: sequence.sequence(), + data: &sequence.sequence, frame: self.frame, table: self.table, translated_len: self.translated_column_count, @@ -216,57 +220,26 @@ impl<'a> TranslatedAlignment<'a> { /// Returns any [`AlignmentError`] encountered while materialising the /// translated rows into a concrete alignment. pub fn to_alignment(&self) -> Result { - let translated = self - .source - .absolute_row_ids() - .map(|absolute_row| { + let absolute_rows = self.source.absolute_row_ids().collect::>(); + + let translated = absolute_rows + .par_iter() + .map(|&absolute_row| { let sequence = self.source.data.sequences.get(absolute_row).ok_or( AlignmentError::RowOutOfBounds { index: absolute_row, row_count: self.source.data.sequences.len(), }, )?; - Ok(RawSequence { - id: sequence.id().to_string(), - sequence: translate_sequence(sequence.sequence(), self.frame, &self.table), + + Ok(crate::RawSequence { + id: sequence.id.to_string(), + sequence: translate_sequence(&sequence.sequence, self.frame, &self.table), }) }) .collect::, _>>()?; - let data = AlignmentData::from_raw(translated)?; - Ok(Alignment::from_data(data, AlignmentType::Protein)) - } - - /// Returns a summary for each requested protein column. - /// - /// The returned positions use protein-column coordinates from the translated - /// view. Consensus, conservation, and gap fraction are calculated from the - /// visible rows in the source alignment with this view's reading frame and - /// translation table. - /// - /// # Errors - /// - /// [`AlignmentError::ColumnOutOfBounds`] if any value in `positions` is not a - /// valid protein-column index in the translated view. - pub fn column_summaries_positions( - &self, - positions: &[usize], - method: ConsensusMethod, - ) -> Result, AlignmentError> { - let columns = counted_translated_columns_positions( - &self.source.data, - &self.source.rows, - positions, - self.frame, - &self.table, - )?; - let mut rng = rand::rng(); - Ok(summaries_from_columns( - &columns, - method, - AlignmentType::Protein.conservation_alphabet_size(), - &mut rng, - )) + Alignment::new_with_type(translated, AlignmentType::Protein) } /// Returns summary for each protein column in `range`. @@ -303,32 +276,6 @@ impl<'a> TranslatedAlignment<'a> { )) } - /// Returns the translated consensus byte for each protein column in `range`. - /// - /// The returned positions use protein-column coordinates from the translated - /// view. Consensus is calculated from the visible rows in the source alignment - /// with this view's reading frame and translation table. - /// - /// # Errors - /// - /// [`AlignmentError::EmptyRange`] if `range` is empty. - /// - /// [`AlignmentError::ColumnOutOfBounds`] if `range.end` is greater than - /// the translated width of this view. - pub fn consensus_range( - &self, - range: Range, - method: ConsensusMethod, - ) -> Result)>, AlignmentError> { - let summaries = self.column_summaries_range(range, method)?; - Ok(summaries - .into_iter() - .map(|summary| (summary.position, summary.consensus)) - .collect()) - } -} - -impl<'a> TranslatedAlignment<'a> { pub(crate) fn new( source: &'a Alignment, frame: ReadingFrame, @@ -439,34 +386,32 @@ pub(crate) fn normalise_nucleotide(byte: u8) -> Option { } } -pub fn translate_sequence( - sequence: &[u8], - frame: ReadingFrame, - table: &TranslationTable, -) -> Vec { - let mut translated = Vec::with_capacity(translated_length(sequence.len(), frame)); - - for codon_start in (frame.offset()..sequence.len()).step_by(3) { - let codon = [ - sequence - .get(codon_start) - .and_then(|&byte| normalise_nucleotide(byte)), - sequence - .get(codon_start + 1) - .and_then(|&byte| normalise_nucleotide(byte)), - sequence - .get(codon_start + 2) - .and_then(|&byte| normalise_nucleotide(byte)), - ]; +fn translate_sequence(sequence: &[u8], frame: ReadingFrame, table: &TranslationTable) -> Vec { + let offset = frame.offset(); + if sequence.len() <= offset { + return Vec::new(); + } - let amino_acid = match codon { - [Some(first), Some(second), Some(third)] => { - table.translate_codon([first, second, third]) - } - _ => b'X', + let translated_len = translated_length(sequence.len(), frame); + let complete_codons = frame.complete_codons(sequence.len()); + let complete_end = offset + (complete_codons * 3); + + let mut translated = vec![0; translated_len]; + + for (protein_col, codon) in sequence[offset..complete_end].chunks_exact(3).enumerate() { + let first = nucleotide_index(codon[0]); + let second = nucleotide_index(codon[1]); + let third = nucleotide_index(codon[2]); + + translated[protein_col] = if first == 4 || second == 4 || third == 4 { + b'X' + } else { + table.codons[first as usize][second as usize][third as usize] }; + } - translated.push(amino_acid); + if complete_codons < translated_len { + translated[complete_codons] = b'X'; } translated @@ -502,13 +447,15 @@ pub(crate) fn translated_length(sequence_len: usize, frame: ReadingFrame) -> usi frame.translated_length(sequence_len) } +#[inline] +fn nucleotide_index(base: u8) -> u8 { + NUCLEOTIDE_INDEX_TABLE[base as usize] +} + fn index_nucleotide(base: u8) -> Option { - match base { - b'A' => Some(0), - b'T' => Some(1), - b'C' => Some(2), - b'G' => Some(3), - _ => None, + match nucleotide_index(base) { + 4 => None, + index => Some(index as usize), } } @@ -765,9 +712,9 @@ mod translated_alignment_tests { let frame2 = alignment.translated(ReadingFrame::Frame2).unwrap(); let frame3 = alignment.translated(ReadingFrame::Frame3).unwrap(); - let frame1_sequence = frame1.sequence_by_absolute(0).unwrap(); - let frame2_sequence = frame2.sequence_by_absolute(0).unwrap(); - let frame3_sequence = frame3.sequence_by_absolute(0).unwrap(); + let frame1_sequence = frame1.project_absolute_row(0).unwrap(); + let frame2_sequence = frame2.project_absolute_row(0).unwrap(); + let frame3_sequence = frame3.project_absolute_row(0).unwrap(); assert_eq!(frame1_sequence.byte_at(0), Some(b'M')); assert_eq!(frame1_sequence.byte_at(1), Some(b'P')); @@ -804,30 +751,6 @@ mod translated_alignment_tests { ); } - #[test] - fn translated_sequence_by_absolute_returns_visible_row() { - let alignment = Alignment::new_with_type( - vec![ - raw("s1", b"ATGAAA"), - raw("s2", b"TTTCCC"), - raw("s3", b"GGGAAA"), - ], - AlignmentType::Dna, - ) - .unwrap(); - let filtered = alignment - .filter() - .unwrap() - .without_rows([1]) - .apply() - .unwrap(); - let translated = filtered.translated(ReadingFrame::Frame1).unwrap(); - - let sequence = translated.sequence_by_absolute(2).unwrap(); - assert_eq!(sequence.byte_at(0), Some(b'G')); - assert!(translated.sequence_by_absolute(1).is_none()); - } - #[test] fn translated_alignment_builds_protein_alignment() { let alignment = Alignment::new_with_type( @@ -920,9 +843,6 @@ mod translated_alignment_tests { let translated = filtered.translated(ReadingFrame::Frame1).unwrap(); let materialised = translated.to_alignment().unwrap(); - assert!(translated.sequence_by_absolute(1).is_some()); - assert!(translated.sequence_by_absolute(0).is_none()); - assert!(translated.sequence_by_absolute(2).is_none()); assert_eq!( materialised .sequence(0) @@ -967,7 +887,7 @@ mod translated_alignment_tests { } #[test] - fn translated_alignment_custom_table_is_used_for_consensus() { + fn translated_alignment_custom_table_is_used_for_summaries() { let alignment = Alignment::new_with_type( vec![ raw("s1", b"ATGAAA"), @@ -1009,13 +929,11 @@ mod translated_alignment_tests { let translated = alignment .translated_with(ReadingFrame::Frame1, custom) .unwrap(); + let summaries = translated + .column_summaries_range(0..1, ConsensusMethod::MajorityNonGap) + .unwrap(); - assert_eq!( - translated - .consensus_range(0..1, ConsensusMethod::MajorityNonGap) - .unwrap(), - vec![(0, Some(b'Z'))] - ); + assert_eq!(summaries[0].consensus, Some(b'Z')); } #[test] @@ -1037,7 +955,6 @@ mod translated_alignment_tests { .unwrap(); let translated = filtered.translated(ReadingFrame::Frame1).unwrap(); - assert!(translated.sequence_by_absolute(1).is_none()); assert_eq!( translated_bytes(translated.project_absolute_row(1).unwrap(), 2), vec![(0, b'F'), (1, b'P')] @@ -1053,12 +970,14 @@ mod translated_alignment_tests { .unwrap(); let translated = alignment.translated(ReadingFrame::Frame1).unwrap(); - for abs_row in 0..2 { - assert_eq!( - translated_bytes(translated.sequence_by_absolute(abs_row).unwrap(), 2), - translated_bytes(translated.project_absolute_row(abs_row).unwrap(), 2) - ); - } + assert_eq!( + translated_bytes(translated.project_absolute_row(0).unwrap(), 2), + vec![(0, b'M'), (1, b'K')] + ); + assert_eq!( + translated_bytes(translated.project_absolute_row(1).unwrap(), 2), + vec![(0, b'F'), (1, b'P')] + ); } #[test] From 1c2b8e649645faaae11c2e754771e1f38b3e8948 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sat, 4 Apr 2026 10:03:00 +0100 Subject: [PATCH 09/48] feat(salti): add reload as protein functionality Adds a hot to key to quickly switch a nt to a protein alignment alongisde command `reload-as-protein` --- salti/src/command.rs | 1 + salti/src/config/keybindings.rs | 24 +++++++++++++ .../command_palette/command_definitions.rs | 13 +++++-- .../command_palette/command_runners.rs | 36 +++++++++++++++++++ salti/src/overlay/command_palette/input.rs | 34 ++++++++++-------- 5 files changed, 92 insertions(+), 16 deletions(-) diff --git a/salti/src/command.rs b/salti/src/command.rs index cc315d4..9a5d21f 100644 --- a/salti/src/command.rs +++ b/salti/src/command.rs @@ -35,4 +35,5 @@ pub enum Command { SetTranslationFrame(libmsa::ReadingFrame), SetDiffMode(DiffMode), ToggleTranslationView, + ReloadAsProtein { frame: Option }, } diff --git a/salti/src/config/keybindings.rs b/salti/src/config/keybindings.rs index c613242..f9b889d 100644 --- a/salti/src/config/keybindings.rs +++ b/salti/src/config/keybindings.rs @@ -29,6 +29,30 @@ const KEY_BINDINGS: &[Binding] = &[ action: Command::ToggleTranslationView, help: "Toggle NT to AA translation view", }, + Binding { + code: KeyCode::Char('T'), + modifiers: KeyModifiers::SHIFT, + action: Command::ReloadAsProtein { frame: None }, + help: "Reload alignment as protein", + }, + Binding { + code: KeyCode::Char('1'), + modifiers: KeyModifiers::ALT, + action: Command::SetTranslationFrame(libmsa::ReadingFrame::Frame1), + help: "Set translation frame 1", + }, + Binding { + code: KeyCode::Char('2'), + modifiers: KeyModifiers::ALT, + action: Command::SetTranslationFrame(libmsa::ReadingFrame::Frame2), + help: "Set translation frame 2", + }, + Binding { + code: KeyCode::Char('3'), + modifiers: KeyModifiers::ALT, + action: Command::SetTranslationFrame(libmsa::ReadingFrame::Frame3), + help: "Set translation frame 3", + }, Binding { code: KeyCode::Char('m'), modifiers: KeyModifiers::NONE, diff --git a/salti/src/overlay/command_palette/command_definitions.rs b/salti/src/overlay/command_palette/command_definitions.rs index 79070c8..3e24ee9 100644 --- a/salti/src/overlay/command_palette/command_definitions.rs +++ b/salti/src/overlay/command_palette/command_definitions.rs @@ -1,8 +1,9 @@ use super::command_runners::{ run_check_update, run_clear_filter, run_clear_reference, run_consensus_method, run_diff_mode, run_filter_constant, run_filter_gaps, run_filter_rows, run_jump_position, run_jump_sequence, - run_load_alignment, run_pin_sequence, run_quit, run_set_active_type, run_set_reference, - run_theme, run_toggle_translation, run_translation_frame, run_unpin_sequence, + run_load_alignment, run_pin_sequence, run_quit, run_reload_as_protein, run_set_active_type, + run_set_reference, run_theme, run_toggle_translation, run_translation_frame, + run_unpin_sequence, }; use super::command_spec::{PaletteCommand, StaticCommand, TypableCommand}; use super::completers; @@ -103,6 +104,14 @@ pub(super) const COMMAND_SPECS: &[PaletteCommand] = &[ aliases: &[], run: run_toggle_translation, }), + PaletteCommand::Typable(TypableCommand { + name: "reload-as-protein", + help_text: "Toggle reloading the DNA alignment as protein. Optionally pass a frame.", + aliases: &[], + completer: None, + static_candidates: &["1", "2", "3"], + run: run_reload_as_protein, + }), PaletteCommand::Static(StaticCommand { name: "check-update", help_text: "Check crates.io for a newer salti version.", diff --git a/salti/src/overlay/command_palette/command_runners.rs b/salti/src/overlay/command_palette/command_runners.rs index 2695232..85cd81f 100644 --- a/salti/src/overlay/command_palette/command_runners.rs +++ b/salti/src/overlay/command_palette/command_runners.rs @@ -65,6 +65,27 @@ pub(super) fn run_toggle_translation( }) } +pub(super) fn run_reload_as_protein( + state: &CommandPaletteState, + arguments: &str, +) -> anyhow::Result { + run_command("reload-as-protein", arguments, || { + let frame = match parse_argument(arguments) { + Some(arg) => Some( + arg.parse() + .map_err(|_| format_err!("Invalid argument for reload-as-protein: {arg}"))?, + ), + None => None, + }; + if state.active_type != libmsa::AlignmentType::Dna && !state.is_reloaded_as_protein { + return Err(format_err!( + "reload-as-protein is only available for DNA alignments", + )); + } + Ok(Command::ReloadAsProtein { frame }) + }) +} + fn next_visible_column_index(visible_columns: &[usize], absolute_target: usize) -> Option { match visible_columns.binary_search(&absolute_target) { Ok(visible_index) => Some(visible_index), @@ -309,6 +330,7 @@ mod tests { Vec::new(), Vec::new(), libmsa::AlignmentType::Dna, + false, visible_columns, ) } @@ -432,4 +454,18 @@ mod tests { "Invalid argument for set-sequence-type: rna" ); } + + #[test] + fn reload_as_protein_accepts_optional_frame() { + let state = palette_state_with_columns(Vec::new()); + + let action = run_reload_as_protein(&state, "2").expect("frame should parse"); + + assert_eq!( + action, + Command::ReloadAsProtein { + frame: Some(libmsa::ReadingFrame::Frame2), + } + ); + } } diff --git a/salti/src/overlay/command_palette/input.rs b/salti/src/overlay/command_palette/input.rs index c227b56..7586946 100644 --- a/salti/src/overlay/command_palette/input.rs +++ b/salti/src/overlay/command_palette/input.rs @@ -35,6 +35,7 @@ pub struct CommandPaletteState { pub(super) selectable_sequences: Vec, pub(super) pinned_sequences: Vec, pub(super) active_type: AlignmentType, + pub(super) is_reloaded_as_protein: bool, pub(super) visible_columns: Vec, } impl CommandPaletteState { @@ -43,6 +44,7 @@ impl CommandPaletteState { Vec::new(), Vec::new(), libmsa::AlignmentType::Generic, + false, Vec::new(), ) } @@ -84,6 +86,7 @@ impl CommandPaletteState { selectable_sequences, pinned_sequences, alignment.base().active_type(), + alignment.is_reloaded_as_protein(), alignment.view().absolute_column_ids().collect(), ) } @@ -92,6 +95,7 @@ impl CommandPaletteState { selectable_sequences: Vec, pinned_sequences: Vec, active_type: AlignmentType, + is_reloaded_as_protein: bool, visible_columns: Vec, ) -> Self { let mut command_list = SearchableList::new(FilterMode::Fuzzy, None); @@ -107,6 +111,7 @@ impl CommandPaletteState { selectable_sequences, pinned_sequences, active_type, + is_reloaded_as_protein, visible_columns, } } @@ -386,6 +391,20 @@ impl CommandPaletteState { } } +fn display_command_names() -> Vec { + COMMAND_SPECS + .iter() + .map(|spec| spec.name().to_string()) + .collect() +} + +fn resolve_command(name: &str) -> Option { + COMMAND_SPECS + .iter() + .copied() + .find(|spec| spec.name() == name || spec.aliases().contains(&name)) +} + #[cfg(test)] mod tests { use super::*; @@ -400,6 +419,7 @@ mod tests { Vec::new(), Vec::new(), libmsa::AlignmentType::Dna, + false, vec![0, 3, 4], ); palette.command_input = "jump-position 2".to_string(); @@ -441,17 +461,3 @@ mod tests { ); } } - -fn display_command_names() -> Vec { - COMMAND_SPECS - .iter() - .map(|spec| spec.name().to_string()) - .collect() -} - -fn resolve_command(name: &str) -> Option { - COMMAND_SPECS - .iter() - .copied() - .find(|spec| spec.name() == name || spec.aliases().contains(&name)) -} From a51d8595e2ade1bcf0e8a41a0f3008cc528b6967 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sat, 4 Apr 2026 11:49:00 +0100 Subject: [PATCH 10/48] feat(salti): fixup translation to more central handling and finish reload-as-protein view handling --- salti/src/app.rs | 233 ++++++++++++++++---- salti/src/core/model.rs | 458 ++++++++++++++++++++++++++++------------ 2 files changed, 514 insertions(+), 177 deletions(-) diff --git a/salti/src/app.rs b/salti/src/app.rs index 2b01c65..38f4587 100644 --- a/salti/src/app.rs +++ b/salti/src/app.rs @@ -57,6 +57,7 @@ pub(crate) struct App { layout_area: Rect, frame_layout: FrameLayout, app_layout: AppLayout, + reloaded_nucleotide_phase: usize, } impl App { @@ -77,6 +78,7 @@ impl App { layout_area, frame_layout, app_layout, + reloaded_nucleotide_phase: 0, } } @@ -480,10 +482,23 @@ impl App { self.invalidate_all_stats(); return Ok(()); } + Command::ReloadAsProtein { frame } => { + let viewport_target = self.reload_as_protein_viewport_target(frame); + self.alignment_mut()?.toggle_reload_as_protein(frame)?; + self.clear_mouse_selection(); + self.on_view_rebuilt(); + self.jump_to_reloaded_viewport_target(viewport_target); + return Ok(()); + } Command::SetTranslationFrame(frame) => { let alignment = self.alignment_mut()?; let was_enabled = alignment.translation().is_some(); + let was_reloaded = alignment.is_reloaded_as_protein(); alignment.set_translation_frame(frame)?; + if was_reloaded { + self.on_view_rebuilt(); + return Ok(()); + } if was_enabled { self.invalidate_translated_stats(); } @@ -518,6 +533,45 @@ impl App { self.invalidate_all_stats(); } + fn reload_as_protein_viewport_target( + &mut self, + frame: Option, + ) -> Option { + let alignment = self.alignment.as_ref()?; + let frame = frame.unwrap_or(alignment.translation_frame()); + let relative_col = self.ui.viewport.window().col_range.start; + let absolute_col = alignment.view().absolute_column_id(relative_col)?; + + if alignment.is_reloaded_as_protein() { + let nucleotide_col = absolute_col + .checked_mul(3) + .and_then(|scaled| frame.offset().checked_add(scaled))? + .saturating_add(self.reloaded_nucleotide_phase); + return Some(nucleotide_col); + } + + self.reloaded_nucleotide_phase = match absolute_col.checked_sub(frame.offset()) { + Some(offset_col) => offset_col % 3, + None => 0, + }; + Some(frame.protein_col(absolute_col).unwrap_or(0)) + } + + fn jump_to_reloaded_viewport_target(&mut self, target_absolute_col: Option) { + let Some(target_absolute_col) = target_absolute_col else { + return; + }; + let Some(alignment) = self.alignment.as_ref() else { + return; + }; + let Some(relative_col) = + nearest_visible_relative_column(alignment.view(), target_absolute_col) + else { + return; + }; + self.ui.viewport.jump_to_position(relative_col); + } + fn clear_mouse_selection(&mut self) { self.ui.selection = None; self.mouse_tracker.clear_anchors(); @@ -704,6 +758,25 @@ impl App { } } +fn nearest_visible_relative_column( + view: &libmsa::Alignment, + target_absolute_col: usize, +) -> Option { + if let Some(relative_col) = view.relative_column_id(target_absolute_col) { + return Some(relative_col); + } + + let mut previous_relative_col = None; + for (relative_col, absolute_col) in view.absolute_column_ids().enumerate() { + if target_absolute_col <= absolute_col { + return Some(relative_col); + } + previous_relative_col = Some(relative_col); + } + + previous_relative_col +} + #[cfg(test)] mod tests { use super::*; @@ -724,8 +797,8 @@ mod tests { initial_position: 0, }; let mut app = App::new(startup); - let alignment = libmsa::Alignment::new(sequences).expect("alignment should load"); - let model = AlignmentModel::new(alignment).expect("alignment model should build"); + let alignment = libmsa::Alignment::new(sequences).unwrap(); + let model = AlignmentModel::new(alignment).unwrap(); app.stats_cache.init(model.view().column_count()); app.alignment = Some(model); app.ui.meta.loading_state = LoadingState::Loaded; @@ -749,19 +822,19 @@ mod tests { } #[test] - fn translated_click_selects_a_full_codon_span() { + fn translated_click_selects_whole_codon() { let mut app = - app_with_alignment(vec![raw("row1", b"ATGAAATTT"), raw("row2", b"ATGAAATTT")]); + app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); app.alignment .as_mut() .unwrap() .set_translation_frame(libmsa::ReadingFrame::Frame1) - .expect("setting translation frame should succeed"); + .unwrap(); app.alignment .as_mut() .unwrap() .toggle_translation_view() - .expect("translation should enable"); + .unwrap(); let area = app.app_layout.alignment_pane_sequence_rows; app.handle_mouse_event(left_mouse_event( @@ -771,26 +844,26 @@ mod tests { 0, )); - let selection = app.ui.selection.expect("selection should be created"); + let selection = app.ui.selection.unwrap(); assert_eq!(selection.sequence_id, 0); assert_eq!(selection.column, 0); assert_eq!(selection.end_column, 2); } #[test] - fn translated_drag_extends_selection_in_whole_codons() { + fn translated_drag_extends_selection_in_codons() { let mut app = - app_with_alignment(vec![raw("row1", b"ATGAAATTT"), raw("row2", b"ATGAAATTT")]); + app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); app.alignment .as_mut() .unwrap() .set_translation_frame(libmsa::ReadingFrame::Frame1) - .expect("setting translation frame should succeed"); + .unwrap(); app.alignment .as_mut() .unwrap() .toggle_translation_view() - .expect("translation should enable"); + .unwrap(); let area = app.app_layout.alignment_pane_sequence_rows; app.handle_mouse_event(left_mouse_event( @@ -812,7 +885,7 @@ mod tests { 0, )); - let selection = app.ui.selection.expect("selection should be created"); + let selection = app.ui.selection.unwrap(); assert_eq!(selection.sequence_id, 0); assert_eq!(selection.column, 0); assert_eq!(selection.end_sequence_id, 0); @@ -820,9 +893,9 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn toggling_translation_preserves_the_stored_nucleotide_selection() { + async fn toggling_translation_keeps_stored_nucleotide_selection() { let mut app = - app_with_alignment(vec![raw("row1", b"ATGAAATTT"), raw("row2", b"ATGAAATTT")]); + app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); let selection = MouseSelection { sequence_id: 0, column: 4, @@ -839,17 +912,101 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn filter_gaps_shows_notification_when_translation_is_active() { + async fn reload_as_protein_clears_selection() { let mut app = - app_with_alignment(vec![raw("row1", b"ATGAAATTT"), raw("row2", b"ATGAAATTT")]); + app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); + app.ui.selection = Some(MouseSelection { + sequence_id: 0, + column: 0, + end_sequence_id: 0, + end_column: 2, + }); + + app.execute_commands([Command::ReloadAsProtein { frame: None }]); + + assert!(app.alignment.as_ref().unwrap().is_reloaded_as_protein()); + assert_eq!( + app.alignment.as_ref().unwrap().base().active_type(), + libmsa::AlignmentType::Protein + ); + assert_eq!(app.ui.selection, None); + + app.execute_commands([Command::ReloadAsProtein { frame: None }]); + + assert!(!app.alignment.as_ref().unwrap().is_reloaded_as_protein()); + assert_eq!( + app.alignment.as_ref().unwrap().base().active_type(), + libmsa::AlignmentType::Dna + ); + } + + #[tokio::test(flavor = "current_thread")] + async fn reload_as_protein_maps_nt_viewport_to_matching_aa_column() { + let sequence = vec![b'C'; 360]; + let mut app = app_with_alignment(vec![raw("seq1", &sequence)]); + app.ui.viewport.jump_to_position(200); + + app.execute_commands([Command::ReloadAsProtein { frame: None }]); + + assert_eq!(app.ui.viewport.window().col_range.start, 66); + } + + #[tokio::test(flavor = "current_thread")] + async fn reload_as_protein_maps_back_to_nt_from_current_aa_locus() { + let sequence = vec![b'C'; 360]; + let mut app = app_with_alignment(vec![raw("seq1", &sequence)]); + app.ui.viewport.jump_to_position(200); + + app.execute_commands([Command::ReloadAsProtein { frame: None }]); + app.ui.viewport.jump_to_position(70); + + app.execute_commands([Command::ReloadAsProtein { frame: None }]); + + assert_eq!(app.ui.viewport.window().col_range.start, 212); + } + + #[tokio::test(flavor = "current_thread")] + async fn set_translation_frame_retranslates_reloaded_protein_alignment() { + let mut app = app_with_alignment(vec![raw("seq1", b"ATGCCCTAA")]); + + app.execute_commands([Command::ReloadAsProtein { frame: None }]); + assert_eq!( + app.alignment + .as_ref() + .unwrap() + .base() + .sequence(0) + .unwrap() + .byte_at(0), + Some(b'M') + ); + + app.execute_commands([Command::SetTranslationFrame(libmsa::ReadingFrame::Frame2)]); + + assert_eq!( + app.alignment.as_ref().unwrap().translation_frame(), + libmsa::ReadingFrame::Frame2 + ); + assert_eq!( + app.alignment + .as_ref() + .unwrap() + .base() + .sequence(0) + .unwrap() + .byte_at(0), + Some(b'C') + ); + } + + #[tokio::test(flavor = "current_thread")] + async fn filter_gaps_shows_notification_in_translation() { + let mut app = + app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); app.execute_commands([Command::ToggleTranslationView]); app.execute_commands([Command::SetGapFilter(Some(0.25))]); - let notification = app - .ui - .notification - .as_ref() - .expect("notification should be created"); + let notification = app.ui.notification.as_ref().unwrap(); assert_eq!( notification.message, "filter-gaps is unavailable while translation is active" @@ -857,17 +1014,13 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn filter_constant_shows_notification_when_translation_is_active() { + async fn filter_constant_shows_notification_in_translation() { let mut app = - app_with_alignment(vec![raw("row1", b"ATGAAATTT"), raw("row2", b"ATGAAATTT")]); + app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); app.execute_commands([Command::ToggleTranslationView]); app.execute_commands([Command::SetConstantFilter(Some(0.9))]); - let notification = app - .ui - .notification - .as_ref() - .expect("notification should be created"); + let notification = app.ui.notification.as_ref().unwrap(); assert_eq!( notification.message, "filter-constant is unavailable while translation is active" @@ -875,16 +1028,12 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn translation_shows_notification_when_gap_filter_is_active() { - let mut app = app_with_alignment(vec![raw("row1", b"ATG---"), raw("row2", b"ATG---")]); + async fn translation_shows_notification_with_gap_filter() { + let mut app = app_with_alignment(vec![raw("seq1", b"ATG---"), raw("seq2", b"ATG---")]); app.execute_commands([Command::SetGapFilter(Some(0.0))]); app.execute_commands([Command::ToggleTranslationView]); - let notification = app - .ui - .notification - .as_ref() - .expect("notification should be created"); + let notification = app.ui.notification.as_ref().unwrap(); assert_eq!( notification.message, "translation is unavailable while a column filter is active" @@ -892,16 +1041,12 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn translation_shows_notification_when_constant_filter_is_active() { - let mut app = app_with_alignment(vec![raw("row1", b"ATGAAA"), raw("row2", b"ATGAAA")]); + async fn translation_shows_notification_with_constant_filter() { + let mut app = app_with_alignment(vec![raw("seq1", b"ATGAAA"), raw("seq2", b"ATGAAA")]); app.execute_commands([Command::SetConstantFilter(Some(1.0))]); app.execute_commands([Command::ToggleTranslationView]); - let notification = app - .ui - .notification - .as_ref() - .expect("notification should be created"); + let notification = app.ui.notification.as_ref().unwrap(); assert_eq!( notification.message, "translation is unavailable while a column filter is active" @@ -909,8 +1054,8 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn key_events_are_forwarded_to_command_execution() { - let mut app = app_with_alignment(vec![raw("row1", b"ACGT"), raw("row2", b"ACGT")]); + async fn key_events_forward_to_command_execution() { + let mut app = app_with_alignment(vec![raw("seq1", b"CATC"), raw("seq2", b"CATC")]); let key = KeyEvent::new(KeyCode::Char('q'), KeyModifiers::NONE); app.handle_key_event(key); diff --git a/salti/src/core/model.rs b/salti/src/core/model.rs index 0422bd7..079a065 100644 --- a/salti/src/core/model.rs +++ b/salti/src/core/model.rs @@ -147,13 +147,25 @@ impl FilterState { } } +#[derive(Debug, Clone)] +struct Stash { + base: libmsa::Alignment, +} + +#[derive(Debug, Clone)] +enum TranslationMode { + Off, + Overlay, + ReloadedProtein { stash: Stash }, +} + #[derive(Debug)] pub struct AlignmentModel { base: libmsa::Alignment, view: libmsa::Alignment, rows: RowPresentationState, filter: FilterState, - translation_enabled: bool, + translation_mode: TranslationMode, translation_frame: libmsa::ReadingFrame, pub diff_mode: DiffMode, pub consensus_method: libmsa::ConsensusMethod, @@ -173,7 +185,7 @@ impl AlignmentModel { base, rows: RowPresentationState::default(), filter: FilterState::default(), - translation_enabled: false, + translation_mode: TranslationMode::Off, translation_frame: libmsa::ReadingFrame::Frame1, diff_mode: DiffMode::default(), consensus_method: libmsa::ConsensusMethod::default(), @@ -197,32 +209,41 @@ impl AlignmentModel { } pub fn translation(&self) -> Option { - self.translation_enabled.then_some(self.translation_frame) + match &self.translation_mode { + TranslationMode::Overlay => Some(self.translation_frame), + TranslationMode::Off | TranslationMode::ReloadedProtein { .. } => None, + } + } + + pub fn is_reloaded_as_protein(&self) -> bool { + matches!( + &self.translation_mode, + TranslationMode::ReloadedProtein { .. } + ) } - #[cfg(test)] pub fn translation_frame(&self) -> libmsa::ReadingFrame { self.translation_frame } pub fn pin(&mut self, abs_row: usize) -> Result<(), libmsa::AlignmentError> { self.rows.pin(abs_row, self.base_row_count())?; - self.derive_view_from_intent() + self.update_current_view() } pub fn unpin(&mut self, abs_row: usize) -> Result<(), libmsa::AlignmentError> { self.rows.unpin(abs_row, self.base_row_count())?; - self.derive_view_from_intent() + self.update_current_view() } pub fn set_reference(&mut self, abs_row: usize) -> Result<(), libmsa::AlignmentError> { self.rows.set_reference(abs_row, self.base_row_count())?; - self.derive_view_from_intent() + self.update_current_view() } pub fn clear_reference(&mut self) -> Result<(), libmsa::AlignmentError> { self.rows.clear_reference(); - self.derive_view_from_intent() + self.update_current_view() } pub fn set_filter(&mut self, pattern: String) -> Result<(), libmsa::AlignmentError> { @@ -232,7 +253,7 @@ impl AlignmentModel { Some(pattern) }; let previous = std::mem::replace(&mut self.filter.pattern, next_pattern); - if let Err(error) = self.derive_view_from_intent() { + if let Err(error) = self.update_current_view() { self.filter.pattern = previous; return Err(error); } @@ -245,7 +266,7 @@ impl AlignmentModel { ) -> Result<(), libmsa::AlignmentError> { let previous = self.filter.max_gap_fraction; self.filter.max_gap_fraction = max_gap_fraction; - if let Err(error) = self.derive_view_from_intent() { + if let Err(error) = self.update_current_view() { self.filter.max_gap_fraction = previous; return Err(error); } @@ -258,7 +279,7 @@ impl AlignmentModel { ) -> Result<(), libmsa::AlignmentError> { let previous = self.filter.min_constant_fraction; self.filter.min_constant_fraction = min_constant_fraction; - if let Err(error) = self.derive_view_from_intent() { + if let Err(error) = self.update_current_view() { self.filter.min_constant_fraction = previous; return Err(error); } @@ -269,7 +290,7 @@ impl AlignmentModel { self.filter.pattern = None; self.filter.max_gap_fraction = None; self.filter.min_constant_fraction = None; - self.derive_view_from_intent() + self.update_current_view() } pub fn set_active_kind( @@ -277,10 +298,12 @@ impl AlignmentModel { kind: libmsa::AlignmentType, ) -> Result<(), libmsa::AlignmentError> { self.base.set_override_type(kind); - if kind != libmsa::AlignmentType::Dna { - self.translation_enabled = false; + if kind != libmsa::AlignmentType::Dna + && matches!(&self.translation_mode, TranslationMode::Overlay) + { + self.translation_mode = TranslationMode::Off; } - self.derive_view_from_intent() + self.update_current_view() } pub fn set_translation( @@ -288,7 +311,12 @@ impl AlignmentModel { frame: Option, ) -> Result<(), libmsa::AlignmentError> { let Some(frame) = frame else { - self.translation_enabled = false; + if !matches!( + &self.translation_mode, + TranslationMode::ReloadedProtein { .. } + ) { + self.translation_mode = TranslationMode::Off; + } return Ok(()); }; @@ -300,7 +328,7 @@ impl AlignmentModel { } self.view.translated(frame)?; - self.translation_enabled = true; + self.translation_mode = TranslationMode::Overlay; self.translation_frame = frame; Ok(()) } @@ -309,6 +337,19 @@ impl AlignmentModel { &mut self, frame: libmsa::ReadingFrame, ) -> Result<(), libmsa::AlignmentError> { + let protein = match &self.translation_mode { + TranslationMode::ReloadedProtein { stash: dna_stash } => { + Some(dna_stash.base.translated(frame)?.to_alignment()?) + } + TranslationMode::Off | TranslationMode::Overlay => None, + }; + + if let Some(protein) = protein { + self.translation_frame = frame; + self.base = protein; + return self.update_current_view(); + } + if self.base.active_type() != libmsa::AlignmentType::Dna { return Err(libmsa::AlignmentError::UnsupportedOperation { operation: "set translation frame", @@ -322,52 +363,103 @@ impl AlignmentModel { } pub fn toggle_translation_view(&mut self) -> Result<(), libmsa::AlignmentError> { - if self.translation_enabled { - self.translation_enabled = false; + if matches!(&self.translation_mode, TranslationMode::Off) { + return self.set_translation(Some(self.translation_frame)); + } + + if matches!(&self.translation_mode, TranslationMode::Overlay) { + self.translation_mode = TranslationMode::Off; return Ok(()); } - self.set_translation(Some(self.translation_frame)) + + Err(libmsa::AlignmentError::UnsupportedOperation { + operation: "set translation", + kind: self.base.active_type(), + }) + } + + pub fn toggle_reload_as_protein( + &mut self, + frame: Option, + ) -> Result<(), libmsa::AlignmentError> { + if let Some(frame) = frame { + self.translation_frame = frame; + } + + if matches!( + &self.translation_mode, + TranslationMode::ReloadedProtein { .. } + ) { + let translation_mode = + std::mem::replace(&mut self.translation_mode, TranslationMode::Off); + let dna_stash = match translation_mode { + TranslationMode::ReloadedProtein { stash: dna_stash } => dna_stash, + TranslationMode::Off | TranslationMode::Overlay => unreachable!(), + }; + + self.base = dna_stash.base; + self.translation_mode = TranslationMode::Off; + return self.update_current_view(); + } + + let protein = self + .base + .translated(self.translation_frame)? + .to_alignment()?; + let dna_stash = Stash { + base: self.base.clone(), + }; + self.base = protein; + self.translation_mode = TranslationMode::ReloadedProtein { stash: dna_stash }; + self.update_current_view() } pub fn translated_view(&self) -> Option> { - let frame = self.translation()?; - self.view.translated(frame).ok() + match &self.translation_mode { + TranslationMode::Overlay => self.view.translated(self.translation_frame).ok(), + TranslationMode::Off | TranslationMode::ReloadedProtein { .. } => None, + } } - /// Returns translation-space viewport metadata for the active frame. pub(crate) fn translation_overlay(&self) -> Option { - let frame = self.translation()?; - Some(TranslationOverlay { - frame, - nucleotide_len: self.view().column_count(), - }) + match &self.translation_mode { + TranslationMode::Overlay => Some(TranslationOverlay { + frame: self.translation_frame, + nucleotide_len: self.view().column_count(), + }), + TranslationMode::Off | TranslationMode::ReloadedProtein { .. } => None, + } } pub fn stats_context(&self, visible_col_range: Range) -> Option { - if let Some(frame) = self.translation() { - let nucleotide_len = self.view().column_count(); - let total_columns = complete_protein_len(frame, nucleotide_len); - if total_columns == 0 { - return None; + match &self.translation_mode { + TranslationMode::Overlay => { + let frame = self.translation_frame; + let nucleotide_len = self.view().column_count(); + let total_columns = complete_protein_len(frame, nucleotide_len); + if total_columns == 0 { + return None; + } + let range = visible_protein_range(&visible_col_range, frame, nucleotide_len)?; + Some(StatsContext { + view: StatsView::Translated(frame), + range, + total_columns, + }) + } + TranslationMode::Off | TranslationMode::ReloadedProtein { .. } => { + let total_columns = self.view().column_count(); + if total_columns == 0 || visible_col_range.is_empty() { + return None; + } + + Some(StatsContext { + view: StatsView::Raw, + range: visible_col_range, + total_columns, + }) } - let range = visible_protein_range(&visible_col_range, frame, nucleotide_len)?; - return Some(StatsContext { - view: StatsView::Translated(frame), - range, - total_columns, - }); - } - - let total_columns = self.view().column_count(); - if total_columns == 0 || visible_col_range.is_empty() { - return None; } - - Some(StatsContext { - view: StatsView::Raw, - range: visible_col_range, - total_columns, - }) } pub fn jump_to_sequence(&self, abs_row: usize) -> Option { @@ -388,7 +480,7 @@ impl AlignmentModel { self.base.row_count() } - fn derive_view_from_intent(&mut self) -> Result<(), libmsa::AlignmentError> { + fn update_current_view(&mut self) -> Result<(), libmsa::AlignmentError> { let mut builder = self.base.filter()?; builder = builder.without_rows(self.rows.excluded_rows()); if let Some(pattern) = self.filter.pattern() { @@ -427,8 +519,8 @@ mod tests { } fn alignment_model(sequences: Vec) -> AlignmentModel { - let alignment = libmsa::Alignment::new(sequences).expect("alignment should be valid"); - AlignmentModel::new(alignment).expect("alignment model should build") + let alignment = libmsa::Alignment::new(sequences).unwrap(); + AlignmentModel::new(alignment).unwrap() } #[test] @@ -445,7 +537,7 @@ mod tests { } #[test] - fn row_presentation_state_rejects_pinning_the_reference() { + fn row_presentation_state_rejects_pinning_reference() { let mut state = RowPresentationState::default(); state.set_reference(1, 3).unwrap(); @@ -458,26 +550,18 @@ mod tests { } #[test] - fn row_presentation_state_sets_reference() { - let mut state = RowPresentationState::default(); - - state.set_reference(1, 3).unwrap(); - - assert_eq!(state.reference(), Some(1)); - } - - #[test] - fn row_presentation_state_removes_row_when_reference_set() { + fn row_presentation_state_sets_reference_and_unpins_row() { let mut state = RowPresentationState::default(); state.pin(1, 3).unwrap(); state.set_reference(1, 3).unwrap(); + assert_eq!(state.reference(), Some(1)); assert!(!state.is_pinned(1)); } #[test] - fn row_presentation_state_excluded_rows() { + fn row_presentation_state_lists_pinned_rows_before_reference() { let mut state = RowPresentationState::default(); state.pin(1, 4).unwrap(); state.pin(3, 4).unwrap(); @@ -520,8 +604,8 @@ mod tests { } #[test] - fn alignment_model_new_clones_base_into_view() { - let model = alignment_model(vec![raw("row1", b"ACGT"), raw("row2", b"TGCA")]); + fn alignment_model_new_sets_view_and_defaults() { + let model = alignment_model(vec![raw("seq1", b"CATC"), raw("seq2", b"ATAC")]); assert_eq!(model.base().row_count(), 2); assert_eq!(model.view().row_count(), 2); @@ -531,13 +615,13 @@ mod tests { #[test] fn alignment_model_new_rejects_filtered_alignment() { - let alignment = libmsa::Alignment::new(vec![raw("row1", b"ACGT"), raw("row2", b"ACGT")]) - .expect("alignment should be valid") + let alignment = libmsa::Alignment::new(vec![raw("seq1", b"CATC"), raw("seq2", b"CATC")]) + .unwrap() .filter() - .expect("filter builder should build") - .with_row_regex("row1") + .unwrap() + .with_row_regex("seq1") .apply() - .expect("filtered alignment should build"); + .unwrap(); let error = AlignmentModel::new(alignment).unwrap_err(); @@ -553,9 +637,9 @@ mod tests { #[test] fn pin_hides_row_from_view() { let mut model = alignment_model(vec![ - raw("row1", b"ACGT"), - raw("row2", b"ACGT"), - raw("row3", b"ACGT"), + raw("seq1", b"CATC"), + raw("seq2", b"CATC"), + raw("seq3", b"CATC"), ]); model.pin(1).unwrap(); @@ -568,9 +652,9 @@ mod tests { #[test] fn unpin_restores_row_to_view() { let mut model = alignment_model(vec![ - raw("row1", b"ACGT"), - raw("row2", b"ACGT"), - raw("row3", b"ACGT"), + raw("seq1", b"CATC"), + raw("seq2", b"CATC"), + raw("seq3", b"CATC"), ]); model.pin(1).unwrap(); @@ -584,9 +668,9 @@ mod tests { #[test] fn set_reference_hides_row_from_view() { let mut model = alignment_model(vec![ - raw("row1", b"ACGT"), - raw("row2", b"ACGT"), - raw("row3", b"ACGT"), + raw("seq1", b"CATC"), + raw("seq2", b"CATC"), + raw("seq3", b"CATC"), ]); model.set_reference(1).unwrap(); @@ -598,7 +682,7 @@ mod tests { #[test] fn clear_reference_restores_row_to_view() { - let mut model = alignment_model(vec![raw("row1", b"ACGT"), raw("row2", b"ACGT")]); + let mut model = alignment_model(vec![raw("seq1", b"CATC"), raw("seq2", b"CATC")]); model.set_reference(1).unwrap(); model.clear_reference().unwrap(); @@ -610,25 +694,25 @@ mod tests { #[test] fn set_filter_applies_row_pattern() { let mut model = alignment_model(vec![ - raw("alpha", b"ACGT"), - raw("beta", b"ACGT"), - raw("gamma", b"ACGT"), + raw("seq1", b"CATC"), + raw("seq2", b"CATC"), + raw("seq3", b"CATC"), ]); - model.set_filter("alpha|beta".to_string()).unwrap(); + model.set_filter("seq1|seq2".to_string()).unwrap(); - assert_eq!(model.filter().pattern(), Some("alpha|beta")); + assert_eq!(model.filter().pattern(), Some("seq1|seq2")); assert_eq!(model.view().row_count(), 2); } #[test] - fn set_filter_treats_empty_string_as_clear() { + fn set_filter_clears_pattern_on_empty_string() { let mut model = alignment_model(vec![ - raw("alpha", b"ACGT"), - raw("beta", b"ACGT"), - raw("gamma", b"ACGT"), + raw("seq1", b"CATC"), + raw("seq2", b"CATC"), + raw("seq3", b"CATC"), ]); - model.set_filter("alpha|beta".to_string()).unwrap(); + model.set_filter("seq1|seq2".to_string()).unwrap(); model.set_filter(String::new()).unwrap(); @@ -637,22 +721,22 @@ mod tests { } #[test] - fn set_filter_restores_previous_pattern_on_error() { - let mut model = alignment_model(vec![raw("alpha", b"ACGT"), raw("beta", b"ACGT")]); - model.set_filter("alpha".to_string()).unwrap(); + fn set_filter_keeps_previous_pattern_on_error() { + let mut model = alignment_model(vec![raw("seq1", b"CATC"), raw("seq2", b"CATC")]); + model.set_filter("seq1".to_string()).unwrap(); let error = model.set_filter("(".to_string()).unwrap_err(); - assert_eq!(model.filter().pattern(), Some("alpha")); + assert_eq!(model.filter().pattern(), Some("seq1")); assert!(matches!(error, libmsa::AlignmentError::InvalidRegex { .. })); } #[test] - fn set_gap_filter_applies_column_filter() { + fn set_gap_filter_hides_filtered_columns() { let mut model = alignment_model(vec![ - raw("alpha", b"A--T"), - raw("beta", b"A--T"), - raw("gamma", b"ACGT"), + raw("seq1", b"C--C"), + raw("seq2", b"C--C"), + raw("seq3", b"CATC"), ]); model.set_gap_filter(Some(0.0)).unwrap(); @@ -662,27 +746,29 @@ mod tests { } #[test] - fn set_constant_filter_applies_column_filter() { - let mut model = alignment_model(vec![ - raw("alpha", b"AN-T"), - raw("beta", b"A--T"), - raw("gamma", b"ATGT"), - ]); + fn set_constant_filter_hides_constant_columns() { + let alignment = libmsa::Alignment::new(vec![ + raw("seq1", b"CN-C"), + raw("seq2", b"C--C"), + raw("seq3", b"CTGC"), + ]) + .unwrap(); + let mut model = AlignmentModel::new(alignment).unwrap(); model.set_constant_filter(Some(1.0)).unwrap(); assert_eq!(model.filter().min_constant_fraction(), Some(1.0)); - assert_eq!(model.view().column_count(), 2); + assert_eq!(model.view().column_count(), 0); } #[test] - fn clear_filter_removes_all_filters() { + fn clear_filter_removes_row_and_column_filters() { let mut model = alignment_model(vec![ - raw("alpha", b"A--T"), - raw("beta", b"A--T"), - raw("gamma", b"ACGT"), + raw("seq1", b"C--C"), + raw("seq2", b"C--C"), + raw("seq3", b"CATC"), ]); - model.set_filter("alpha|beta".to_string()).unwrap(); + model.set_filter("seq1|seq2".to_string()).unwrap(); model.set_gap_filter(Some(0.0)).unwrap(); model.set_constant_filter(Some(1.0)).unwrap(); @@ -696,8 +782,8 @@ mod tests { } #[test] - fn set_active_kind_disables_translation_when_leaving_dna() { - let mut model = alignment_model(vec![raw("dna", b"ATGAAATTT")]); + fn set_active_kind_clears_translation_outside_dna() { + let mut model = alignment_model(vec![raw("seq1", b"CATCATCATCAT")]); model .set_translation(Some(libmsa::ReadingFrame::Frame1)) .unwrap(); @@ -711,8 +797,8 @@ mod tests { } #[test] - fn set_translation_enables_translation_for_dna() { - let mut model = alignment_model(vec![raw("dna", b"ATGAAATTT")]); + fn set_translation_enables_translation_in_dna() { + let mut model = alignment_model(vec![raw("seq1", b"CATCATCATCAT")]); model .set_translation(Some(libmsa::ReadingFrame::Frame2)) @@ -723,8 +809,8 @@ mod tests { } #[test] - fn set_translation_rejects_non_dna_alignments() { - let mut model = alignment_model(vec![raw("aa", b"MKF")]); + fn set_translation_rejects_non_dna_alignment() { + let mut model = alignment_model(vec![raw("seq1", b"MKF")]); model .set_active_kind(libmsa::AlignmentType::Protein) .unwrap(); @@ -744,7 +830,7 @@ mod tests { #[test] fn set_translation_frame_updates_stored_frame() { - let mut model = alignment_model(vec![raw("dna", b"ATGAAATTT")]); + let mut model = alignment_model(vec![raw("seq1", b"CATCATCATCAT")]); model .set_translation_frame(libmsa::ReadingFrame::Frame3) @@ -755,8 +841,8 @@ mod tests { } #[test] - fn set_translation_frame_rejects_non_dna_alignments() { - let mut model = alignment_model(vec![raw("aa", b"MKF")]); + fn set_translation_frame_rejects_non_dna_alignment() { + let mut model = alignment_model(vec![raw("seq1", b"MKF")]); model .set_active_kind(libmsa::AlignmentType::Protein) .unwrap(); @@ -775,8 +861,114 @@ mod tests { } #[test] - fn stats_context_returns_raw_range_unchanged() { - let model = alignment_model(vec![raw("row1", b"ACGT"), raw("row2", b"ACGT")]); + fn reload_as_protein_preserves_filter_and_restores_dna() { + let mut model = alignment_model(vec![raw("seq1", b"CATCATCATCAT"), raw("seq2", b"CATCATCATCAT")]); + model.set_filter("seq1".to_string()).unwrap(); + model + .set_translation(Some(libmsa::ReadingFrame::Frame2)) + .unwrap(); + + model.toggle_reload_as_protein(None).unwrap(); + + assert!(model.is_reloaded_as_protein()); + assert_eq!(model.base().active_type(), libmsa::AlignmentType::Protein); + assert_eq!(model.view().column_count(), 4); + assert_eq!(model.filter().pattern(), Some("seq1")); + assert_eq!(model.translation(), None); + + model.toggle_reload_as_protein(None).unwrap(); + + assert!(!model.is_reloaded_as_protein()); + assert_eq!(model.base().active_type(), libmsa::AlignmentType::Dna); + assert_eq!(model.filter().pattern(), Some("seq1")); + assert_eq!(model.translation(), None); + } + + #[test] + fn set_translation_frame_retranslates_reloaded_protein_alignment() { + let mut model = alignment_model(vec![raw("seq1", b"ATGCCCTAA")]); + model.toggle_reload_as_protein(None).unwrap(); + + assert_eq!(model.base().column_count(), 3); + assert_eq!(model.base().sequence(0).unwrap().byte_at(0), Some(b'M')); + + model + .set_translation_frame(libmsa::ReadingFrame::Frame2) + .unwrap(); + + assert!(model.is_reloaded_as_protein()); + assert_eq!(model.translation_frame(), libmsa::ReadingFrame::Frame2); + assert_eq!(model.base().column_count(), 3); + assert_eq!(model.base().sequence(0).unwrap().byte_at(0), Some(b'C')); + } + + #[test] + fn reload_as_protein_uses_requested_frame_and_keeps_it_global() { + let mut model = alignment_model(vec![raw("seq1", b"ATGCCCTAA")]); + + model + .toggle_reload_as_protein(Some(libmsa::ReadingFrame::Frame3)) + .unwrap(); + + assert_eq!(model.translation_frame(), libmsa::ReadingFrame::Frame3); + assert_eq!(model.base().sequence(0).unwrap().byte_at(0), Some(b'A')); + + model.toggle_reload_as_protein(None).unwrap(); + + assert_eq!(model.translation_frame(), libmsa::ReadingFrame::Frame3); + } + + #[test] + fn filters_changed_in_reloaded_protein_view_persist_in_dna() { + let mut model = alignment_model(vec![ + raw("seq1", b"CAT---CATCAT"), + raw("seq2", b"CATCATCATCAT"), + raw("seq3", b"CATCATCATCAT"), + ]); + model.toggle_reload_as_protein(None).unwrap(); + + model.set_filter("seq1|seq2".to_string()).unwrap(); + model.set_gap_filter(Some(0.5)).unwrap(); + model.set_constant_filter(Some(1.0)).unwrap(); + + assert_eq!(model.filter().pattern(), Some("seq1|seq2")); + assert_eq!(model.filter().max_gap_fraction(), Some(0.5)); + assert_eq!(model.filter().min_constant_fraction(), Some(1.0)); + + model.toggle_reload_as_protein(None).unwrap(); + + assert_eq!(model.base().active_type(), libmsa::AlignmentType::Dna); + assert_eq!(model.filter().pattern(), Some("seq1|seq2")); + assert_eq!(model.filter().max_gap_fraction(), Some(0.5)); + assert_eq!(model.filter().min_constant_fraction(), Some(1.0)); + } + + #[test] + fn live_presentation_state_persists_across_reloaded_protein_toggle() { + let mut model = alignment_model(vec![ + raw("seq1", b"CATCATCATCAT"), + raw("seq2", b"CATCATCATCAT"), + raw("seq3", b"CATCATCATCAT"), + ]); + model.toggle_reload_as_protein(None).unwrap(); + + model.pin(0).unwrap(); + model.set_reference(1).unwrap(); + model.diff_mode = DiffMode::Consensus; + model.consensus_method = libmsa::ConsensusMethod::Majority; + + model.toggle_reload_as_protein(None).unwrap(); + + assert_eq!(model.base().active_type(), libmsa::AlignmentType::Dna); + assert_eq!(model.rows().pinned(), &[0]); + assert_eq!(model.rows().reference(), Some(1)); + assert_eq!(model.diff_mode, DiffMode::Consensus); + assert_eq!(model.consensus_method, libmsa::ConsensusMethod::Majority); + } + + #[test] + fn stats_context_keeps_raw_range() { + let model = alignment_model(vec![raw("seq1", b"CATC"), raw("seq2", b"CATC")]); assert_eq!( model.stats_context(1..3), @@ -790,7 +982,7 @@ mod tests { #[test] fn stats_context_maps_translated_range_to_protein_columns() { - let mut model = alignment_model(vec![raw("row1", b"ATGAAATTT")]); + let mut model = alignment_model(vec![raw("seq1", b"ATGAAATTT")]); model .set_translation(Some(libmsa::ReadingFrame::Frame2)) .unwrap(); @@ -806,12 +998,12 @@ mod tests { } #[test] - fn stats_context_returns_none_when_no_columns_can_be_computed() { - let model = alignment_model(vec![raw("row1", b"ACGT")]); + fn stats_context_returns_none_without_visible_columns() { + let model = alignment_model(vec![raw("seq1", b"CATC")]); assert_eq!(model.stats_context(0..0), None); - let mut translated = alignment_model(vec![raw("row1", b"AT")]); + let mut translated = alignment_model(vec![raw("seq1", b"AT")]); translated .set_translation(Some(libmsa::ReadingFrame::Frame1)) .unwrap(); @@ -819,16 +1011,16 @@ mod tests { } #[test] - fn jump_to_sequence_reports_why_hidden_rows_are_not_visible() { + fn jump_to_sequence_reports_why_row_is_hidden() { let mut model = alignment_model(vec![ - raw("row1", b"ACGT"), - raw("row2", b"ACGT"), - raw("row3", b"ACGT"), - raw("row4", b"ACGT"), + raw("seq1", b"CATC"), + raw("seq2", b"CATC"), + raw("seq3", b"CATC"), + raw("seq4", b"CATC"), ]); model.pin(0).unwrap(); model.set_reference(1).unwrap(); - model.set_filter("row4".to_string()).unwrap(); + model.set_filter("seq4".to_string()).unwrap(); assert_eq!( model.jump_to_sequence(0), From a14e319eaa1d1cfc68db6f6e4321cfb188557f6a Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sat, 4 Apr 2026 12:34:00 +0100 Subject: [PATCH 11/48] tests(salti): snapshot testing --- salti/src/core/codon.rs | 99 +++-- salti/src/core/parser.rs | 92 +++-- salti/src/core/stats_cache.rs | 49 ++- salti/src/ui/alignment_pane.rs | 354 ++++++++++++++++++ salti/src/ui/consensus_pane.rs | 204 +++++++--- salti/src/ui/frame.rs | 177 +++++---- salti/src/ui/render.rs | 262 +++++++++++++ salti/src/ui/rows.rs | 16 +- salti/src/ui/selection.rs | 19 - salti/src/ui/sequence_id_pane.rs | 124 ++++++ ...ent_pane__tests__alignment_pane_basic.snap | 13 + ...alignment_pane_dense_fragmented_ruler.snap | 13 + ..._alignment_pane_pinned_and_fragmented.snap | 13 + ...ment_pane_pinned_with_vertical_scroll.snap | 11 + ...ts__alignment_pane_raw_diff_consensus.snap | 13 + ...nment_pane_raw_diff_consensus_loading.snap | 13 + ...ts__alignment_pane_raw_diff_reference.snap | 13 + ..._raw_diff_reference_without_reference.snap | 13 + ...lignment_pane_scrolled_with_scrollbar.snap | 13 + ...ane__tests__alignment_pane_translated.snap | 13 + ...gnment_pane_translated_diff_reference.snap | 13 + ...sus_pane_generic_without_conservation.snap | 9 + ...ensus_pane__tests__consensus_pane_raw.snap | 10 + ...ne__tests__consensus_pane_raw_loading.snap | 10 + ...ests__consensus_pane_raw_no_reference.snap | 10 + ...ane__tests__consensus_pane_translated.snap | 10 + ...ts__consensus_pane_translated_loading.snap | 10 + ...onsensus_pane_translated_no_reference.snap | 10 + ...__frame_bottom_status_constant_filter.snap | 6 + ...ame_bottom_status_filters_translation.snap | 6 + ...__frame_bottom_status_multi_selection.snap | 6 + ..._frame_bottom_status_single_selection.snap | 6 + ...__tests__frame_top_status_failed_load.snap | 6 + ...ts__frame_top_status_loaded_alignment.snap | 6 + ...render__tests__render_command_palette.snap | 29 ++ ...i__render__tests__render_empty_failed.snap | 17 + ..._ui__render__tests__render_empty_idle.snap | 18 + ...__render__tests__render_empty_loading.snap | 6 + ...i__render__tests__render_loaded_basic.snap | 27 ++ ...der__tests__render_loaded_translation.snap | 28 ++ ...__render_loaded_with_selection_status.snap | 28 ++ ...ti__ui__render__tests__render_minimap.snap | 29 ++ ...i__render__tests__render_notification.snap | 29 ++ ...d_pane__tests__sequence_id_pane_basic.snap | 13 + ...__tests__sequence_id_pane_name_scroll.snap | 12 + ..._pane__tests__sequence_id_pane_pinned.snap | 13 + 46 files changed, 1614 insertions(+), 277 deletions(-) create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_basic.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_dense_fragmented_ruler.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_and_fragmented.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_with_vertical_scroll.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus_loading.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference_without_reference.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_scrolled_with_scrollbar.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated.snap create mode 100644 salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated_diff_reference.snap create mode 100644 salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_generic_without_conservation.snap create mode 100644 salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw.snap create mode 100644 salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_loading.snap create mode 100644 salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_no_reference.snap create mode 100644 salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated.snap create mode 100644 salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_loading.snap create mode 100644 salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_no_reference.snap create mode 100644 salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_constant_filter.snap create mode 100644 salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_filters_translation.snap create mode 100644 salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_multi_selection.snap create mode 100644 salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_single_selection.snap create mode 100644 salti/src/ui/snapshots/salti__ui__frame__tests__frame_top_status_failed_load.snap create mode 100644 salti/src/ui/snapshots/salti__ui__frame__tests__frame_top_status_loaded_alignment.snap create mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap create mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_empty_failed.snap create mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_empty_idle.snap create mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_empty_loading.snap create mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_basic.snap create mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_translation.snap create mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_with_selection_status.snap create mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_minimap.snap create mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_notification.snap create mode 100644 salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_basic.snap create mode 100644 salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_name_scroll.snap create mode 100644 salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_pinned.snap diff --git a/salti/src/core/codon.rs b/salti/src/core/codon.rs index be2bca3..3c6c706 100644 --- a/salti/src/core/codon.rs +++ b/salti/src/core/codon.rs @@ -157,69 +157,60 @@ mod tests { use super::*; #[test] - fn visible_protein_range_includes_complete_codons_overlapping_window() { - let range = visible_protein_range(&(1..8), ReadingFrame::Frame1, 9); - assert_eq!(range, Some(0..3)); - - let range = visible_protein_range(&(0..2), ReadingFrame::Frame3, 9); - assert!(range.is_none()); + fn visible_protein_range_is_correct() { + let cases = [ + ((0..1), ReadingFrame::Frame2, 8, None), + ((1..2), ReadingFrame::Frame2, 8, Some(0..1)), + ((2..7), ReadingFrame::Frame2, 8, Some(0..2)), + ((6..8), ReadingFrame::Frame2, 8, Some(1..2)), + ((7..8), ReadingFrame::Frame2, 8, None), + ]; + + for (visible_nuc_range, frame, nucleotide_len, expected) in cases { + let actual = visible_protein_range(&visible_nuc_range, frame, nucleotide_len); + assert_eq!(actual, expected, "range {visible_nuc_range:?} in {frame:?}"); + } } #[test] - fn codon_span_maps_any_column_in_the_same_codon() { - let frame = ReadingFrame::Frame1; + fn visible_codons_absolute_positions() { + let codons: Vec = visible_codons(&(2..7), ReadingFrame::Frame2, 8).collect(); - assert_eq!(codon_span_for_absolute_column(0, frame, 9), Some(0..3)); - assert_eq!(codon_span_for_absolute_column(1, frame, 9), Some(0..3)); - assert_eq!(codon_span_for_absolute_column(2, frame, 9), Some(0..3)); - assert_eq!(codon_span_for_absolute_column(3, frame, 9), Some(3..6)); + assert_eq!( + codons, + vec![ + VisibleCodon { + protein_col: 0, + nuc_start: 1, + centre: 2, + }, + VisibleCodon { + protein_col: 1, + nuc_start: 4, + centre: 5, + }, + ] + ); } #[test] - fn codon_span_returns_none_for_partial_frame_edges() { + fn codon_span_maps_column_to_codon() { let frame = ReadingFrame::Frame2; - assert_eq!(codon_span_for_absolute_column(0, frame, 9), None); - assert_eq!(codon_span_for_absolute_column(8, frame, 9), None); - } - - #[test] - fn nuc_start_is_frame_offset_plus_triple() { - assert_eq!(nuc_start(0, ReadingFrame::Frame1), 0); - assert_eq!(nuc_start(1, ReadingFrame::Frame1), 3); - assert_eq!(nuc_start(0, ReadingFrame::Frame2), 1); - assert_eq!(nuc_start(1, ReadingFrame::Frame2), 4); - assert_eq!(nuc_start(0, ReadingFrame::Frame3), 2); - } - - #[test] - fn visible_codons_yields_correct_codons() { - let codons: Vec = visible_codons(&(0..9), ReadingFrame::Frame1, 9).collect(); - assert_eq!(codons.len(), 3); - assert_eq!( - codons[0], - VisibleCodon { - protein_col: 0, - nuc_start: 0, - centre: 1, - } - ); - assert_eq!( - codons[1], - VisibleCodon { - protein_col: 1, - nuc_start: 3, - centre: 4, - } - ); - assert_eq!( - codons[2], - VisibleCodon { - protein_col: 2, - nuc_start: 6, - centre: 7, - } - ); + let cases = [ + (0, None), + (1, Some(1..4)), + (2, Some(1..4)), + (3, Some(1..4)), + (4, Some(4..7)), + (6, Some(4..7)), + (7, None), + ]; + + for (absolute_col, expected) in cases { + let actual = codon_span_for_absolute_column(absolute_col, frame, 8); + assert_eq!(actual, expected, "column {absolute_col}"); + } } #[test] diff --git a/salti/src/core/parser.rs b/salti/src/core/parser.rs index 40ed72d..6edcdcb 100644 --- a/salti/src/core/parser.rs +++ b/salti/src/core/parser.rs @@ -92,59 +92,77 @@ mod tests { temp_file } - #[test] - fn test_parse_valid() { - let content = ">seq1\nA-CG\n>seq2\nTGCA\n"; + fn parse_temp_fasta(content: &str, cancel: &CancellationToken) -> Result> { let temp_file = create_temp_fasta(content); let input = temp_file.path().to_str().unwrap(); - let result = parse_fasta_file(input, &CancellationToken::new()); - let sequences = result.expect("parse should succeed"); - assert_eq!(sequences.len(), 2); - assert_eq!(sequences[0].id.as_str(), "seq1"); - assert_eq!(sequences[0].sequence.as_slice(), b"A-CG"); - assert_eq!(sequences[1].id.as_str(), "seq2"); - assert_eq!(sequences[1].sequence.as_slice(), b"TGCA"); + parse_fasta_file(input, cancel) } #[test] - fn test_parse_nonexistant() { - let result = parse_fasta_file("idontexist.fasta", &CancellationToken::new()); - assert!(result.is_err()); + fn parse_fasta_file_success() { + let sequences = parse_temp_fasta(">seq1\nA-CG\n>seq2\nTGCA\n", &CancellationToken::new()) + .unwrap(); + + assert_eq!( + sequences, + vec![ + RawSequence { + id: "seq1".to_string(), + sequence: b"A-CG".to_vec(), + }, + RawSequence { + id: "seq2".to_string(), + sequence: b"TGCA".to_vec(), + }, + ] + ); } #[test] - fn test_parse_empty() { - let content = ""; - let temp_file = create_temp_fasta(content); - let input = temp_file.path().to_str().unwrap(); - let result = parse_fasta_file(input, &CancellationToken::new()); - assert!(result.is_err()); + fn parse_fasta_file_errors_missing_input() { + let error = parse_fasta_file("idontexist.fasta", &CancellationToken::new()) + .unwrap_err(); + + assert!(error.to_string().starts_with("Failed to open input:")); } #[test] - fn test_parse_no_seqs() { - let content = ">seq1\n>seq2\n"; - let temp_file = create_temp_fasta(content); - let input = temp_file.path().to_str().unwrap(); - let result = parse_fasta_file(input, &CancellationToken::new()); - assert!(result.is_err()); + fn parse_fasta_file_errors_empty_file() { + let error = parse_temp_fasta("", &CancellationToken::new()) + .unwrap_err(); + + assert!(error.to_string().starts_with("Failed to open input:")); } #[test] - fn test_parse_length_mismatch() { - let content = ">seq1\nATCG\n>seq2\nTGCAAA\n"; - let temp_file = create_temp_fasta(content); - let input = temp_file.path().to_str().unwrap(); - let result = parse_fasta_file(input, &CancellationToken::new()); - assert!(result.is_err()); + fn parse_fasta_file_errors_zero_length_sequences() { + let error = parse_temp_fasta(">seq1\n>seq2\n", &CancellationToken::new()) + .unwrap_err(); + + assert_eq!(error.to_string(), "Sequence has zero length for id seq1"); } #[test] - fn test_parse_invalid() { - let content = "imaninvalidfasta\nfile\n"; - let temp_file = create_temp_fasta(content); - let input = temp_file.path().to_str().unwrap(); - let result = parse_fasta_file(input, &CancellationToken::new()); - assert!(result.is_err()); + fn parse_fasta_file_errors_length_mismatch() { + let error = parse_temp_fasta(">seq1\nATCG\n>seq2\nTGCAAA\n", &CancellationToken::new()) + .unwrap_err(); + + assert_eq!( + error.to_string(), + "Sequence length mismatch: expected 4, found 6 for id seq2" + ); + } + + #[test] + fn parse_fasta_file_errors_invalid_fasta() { + let error = parse_temp_fasta("imaninvalidfasta\nfile\n", &CancellationToken::new()) + .unwrap_err(); + + let message = error.to_string(); + assert!( + message.starts_with("Failed to open input:") + || message.starts_with("Error reading records:") + || message == "No valid FASTA records found in input" + ); } } diff --git a/salti/src/core/stats_cache.rs b/salti/src/core/stats_cache.rs index 6cfc13c..1d592ad 100644 --- a/salti/src/core/stats_cache.rs +++ b/salti/src/core/stats_cache.rs @@ -238,12 +238,11 @@ mod tests { position: 0, consensus: Some(consensus), conservation: Some(1.0), - gap_fraction: 0.0, } } #[test] - fn chunks_for_range_handles_chunk_boundaries() { + fn chunks_for_range_boundaries() { let cache = ChunkedCache::new(CHUNK_SIZE * 3); assert_eq!(cache.chunks_for_range(&(0..0)), 0..0); @@ -258,7 +257,7 @@ mod tests { } #[test] - fn fill_chunk_writes_summaries_into_the_chunk_range() { + fn fill_chunk() { let mut cache = ChunkedCache::new(CHUNK_SIZE + 3); cache.fill_chunk(1, vec![summary(b'A'), summary(b'C'), summary(b'G')]); @@ -285,7 +284,7 @@ mod tests { } #[test] - fn raw_chunks_to_spawn_returns_only_empty_chunks() { + fn raw_chunks_to_spawn_skips_pending_and_filled() { let mut cache = ColumnStatsCache::default(); cache.init(CHUNK_SIZE * 3); cache.mark_raw_pending(1); @@ -295,7 +294,21 @@ mod tests { } #[test] - fn store_discards_generation_mismatch() { + fn translated_chunks_to_spawn_resets_cache_on_frame_change() { + let mut cache = ColumnStatsCache::default(); + cache.init(10); + let _ = cache.translated_chunks_to_spawn(&(0..2), libmsa::ReadingFrame::Frame1, 2); + cache.mark_translated_pending(0); + + let chunks = cache.translated_chunks_to_spawn(&(0..2), libmsa::ReadingFrame::Frame2, 2); + + assert_eq!(chunks, vec![0]); + assert_eq!(cache.translated_frame, Some(libmsa::ReadingFrame::Frame2)); + assert_eq!(cache.translated.chunks[0], ChunkState::Empty); + } + + #[test] + fn store_rejects_generation_mismatch() { let mut cache = ColumnStatsCache::default(); cache.init(10); @@ -311,7 +324,7 @@ mod tests { } #[test] - fn store_discards_translated_frame_mismatch() { + fn store_rejects_translated_frame_mismatch() { let mut cache = ColumnStatsCache::default(); cache.init(10); let _ = cache.translated_chunks_to_spawn(&(0..2), libmsa::ReadingFrame::Frame1, 2); @@ -332,7 +345,7 @@ mod tests { } #[test] - fn store_fills_chunk_and_marks_it_filled() { + fn store_fills_raw_chunk() { let mut cache = ColumnStatsCache::default(); cache.init(10); cache.mark_raw_pending(0); @@ -353,7 +366,25 @@ mod tests { } #[test] - fn invalidate_all_resets_both_caches_and_bumps_generation() { + fn store_error_respawns_chunk() { + let mut cache = ColumnStatsCache::default(); + cache.init(10); + cache.mark_raw_pending(0); + + let stored = cache.store(StatsJobResult { + generation: cache.generation, + chunk_idx: 0, + view: StatsView::Raw, + summaries: Err("crashbangwallop".to_string()), + }); + + assert!(!stored); + assert_eq!(cache.raw.chunks[0], ChunkState::Empty); + assert_eq!(cache.raw_chunks_to_spawn(&(0..10)), vec![0]); + } + + #[test] + fn invalidate_all_resets_raw_and_translated() { let mut cache = ColumnStatsCache::default(); cache.init(10); let previous_generation = cache.generation; @@ -368,7 +399,7 @@ mod tests { } #[test] - fn invalidate_translated_preserves_raw_cache_and_bumps_generation() { + fn invalidate_translated_keeps_raw() { let mut cache = ColumnStatsCache::default(); cache.init(10); cache.store(StatsJobResult { diff --git a/salti/src/ui/alignment_pane.rs b/salti/src/ui/alignment_pane.rs index 90db1ba..1129267 100644 --- a/salti/src/ui/alignment_pane.rs +++ b/salti/src/ui/alignment_pane.rs @@ -528,3 +528,357 @@ pub fn render_alignment_pane( layout.alignment_pane, ); } + +#[cfg(test)] +mod tests { + use super::*; + use crate::core::model::StatsView; + use crate::core::stats_cache::StatsJobResult; + use ratatui::backend::TestBackend; + use ratatui::buffer::Buffer; + use ratatui::Terminal; + + fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { + libmsa::RawSequence { + id: id.to_string(), + sequence: sequence.to_vec(), + } + } + + fn alignment_model(sequences: Vec) -> AlignmentModel { + let alignment = libmsa::Alignment::new(sequences).unwrap(); + AlignmentModel::new(alignment).unwrap() + } + + fn metrics_with( + view: StatsView, + consensus: &[u8], + conservation: Option, + ) -> ColumnStatsCache { + let mut cache = ColumnStatsCache::default(); + match view { + StatsView::Raw => cache.init(consensus.len()), + StatsView::Translated(frame) => { + cache.init(consensus.len() * 3); + let _ = + cache.translated_chunks_to_spawn(&(0..consensus.len()), frame, consensus.len()); + } + } + + let summaries = consensus + .iter() + .enumerate() + .map(|(position, &byte)| libmsa::ColumnSummary { + position, + consensus: Some(byte), + conservation, + }) + .collect(); + let generation = cache.generation; + let chunk_idx = 0; + let stored = cache.store(StatsJobResult { + generation, + chunk_idx, + view, + summaries: Ok(summaries), + }); + assert!(stored); + cache + } + + fn render_alignment_pane_text( + alignment: &AlignmentModel, + stats_cache: &ColumnStatsCache, + area: Rect, + row_offset: usize, + col_offset: usize, + ) -> String { + let backend = TestBackend::new(area.width, area.height); + let mut terminal = Terminal::new(backend).unwrap(); + let layout = AppLayout::new(area); + let mut viewport = Viewport::default(); + viewport.update_dimensions( + layout.alignment_pane_sequence_rows.width as usize, + layout.alignment_pane_sequence_rows.height as usize, + 0, + ); + viewport.set_bounds( + alignment.view().row_count(), + alignment.view().column_count(), + alignment.base().max_id_len(), + ); + viewport.offsets.rows = row_offset; + viewport.offsets.cols = col_offset; + + terminal + .draw(|frame| { + render_alignment_pane( + frame, + &layout, + alignment, + &viewport, + stats_cache, + &ThemeState::default(), + ); + }) + .unwrap(); + + buffer_text(terminal.backend().buffer(), layout.alignment_pane) + } + + fn buffer_text(buffer: &Buffer, area: Rect) -> String { + let mut lines = Vec::new(); + + for y in area.top()..area.bottom() { + let mut line = String::new(); + for x in area.left()..area.right() { + let symbol = buffer[(x, y)].symbol(); + if symbol.is_empty() { + line.push(' '); + } else { + line.push_str(symbol); + } + } + while line.ends_with(' ') { + line.pop(); + } + lines.push(line); + } + + while matches!(lines.last(), Some(last) if last.is_empty()) { + lines.pop(); + } + + lines.join("\n") + } + + #[test] + fn alignment_pane_basic_snapshot() { + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCAT"), + ]); + + insta::assert_snapshot!( + "alignment_pane_basic", + render_alignment_pane_text( + &alignment, + &ColumnStatsCache::default(), + Rect::new(0, 0, 100, 12), + 0, + 0, + ) + ); + } + + #[test] + fn alignment_pane_pinned_and_fragmented_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CAT---CATCATCATCAT"), + raw("seq2", b"CAT---CATCATCATCAT"), + raw("seq3", b"CAT---CATCATCATCAT"), + raw("seq4", b"CAT---CATCATCATCAT"), + ]); + alignment.pin(1).unwrap(); + alignment.pin(3).unwrap(); + alignment.set_gap_filter(Some(0.5)).unwrap(); + + insta::assert_snapshot!( + "alignment_pane_pinned_and_fragmented", + render_alignment_pane_text( + &alignment, + &ColumnStatsCache::default(), + Rect::new(0, 0, 100, 12), + 0, + 0, + ) + ); + } + + #[test] + fn alignment_pane_translated_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCAT"), + ]); + alignment.set_translation(Some(libmsa::ReadingFrame::Frame1)).unwrap(); + + insta::assert_snapshot!( + "alignment_pane_translated", + render_alignment_pane_text( + &alignment, + &ColumnStatsCache::default(), + Rect::new(0, 0, 100, 12), + 0, + 0, + ) + ); + } + + #[test] + fn alignment_pane_raw_diff_reference_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATGATCATCATCAT"), + raw("seq3", b"CATCATCATCATGATCAT"), + ]); + alignment.set_reference(0).unwrap(); + alignment.diff_mode = DiffMode::Reference; + + insta::assert_snapshot!( + "alignment_pane_raw_diff_reference", + render_alignment_pane_text( + &alignment, + &ColumnStatsCache::default(), + Rect::new(0, 0, 100, 12), + 0, + 0, + ) + ); + } + + #[test] + fn alignment_pane_translated_diff_reference_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATGATCATCATCAT"), + raw("seq3", b"CATCATCATCATGATCAT"), + ]); + alignment.set_reference(0).unwrap(); + alignment.set_translation(Some(libmsa::ReadingFrame::Frame1)).unwrap(); + alignment.diff_mode = DiffMode::Reference; + + insta::assert_snapshot!( + "alignment_pane_translated_diff_reference", + render_alignment_pane_text( + &alignment, + &ColumnStatsCache::default(), + Rect::new(0, 0, 100, 12), + 0, + 0, + ) + ); + } + + #[test] + fn alignment_pane_raw_diff_reference_without_reference_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATGATCATCATCAT"), + raw("seq3", b"CATCATCATCATGATCAT"), + ]); + alignment.diff_mode = DiffMode::Reference; + + insta::assert_snapshot!( + "alignment_pane_raw_diff_reference_without_reference", + render_alignment_pane_text( + &alignment, + &ColumnStatsCache::default(), + Rect::new(0, 0, 100, 12), + 0, + 0, + ) + ); + } + + #[test] + fn alignment_pane_raw_diff_consensus_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATGATCATCATCAT"), + raw("seq3", b"CATCATCATCATGATCAT"), + ]); + alignment.diff_mode = DiffMode::Consensus; + let metrics = metrics_with(StatsView::Raw, b"CATCATCATCATCATCAT", Some(1.0)); + + insta::assert_snapshot!( + "alignment_pane_raw_diff_consensus", + render_alignment_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 12), 0, 0,) + ); + } + + #[test] + fn alignment_pane_raw_diff_consensus_loading_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATGATCATCATCAT"), + raw("seq3", b"CATCATCATCATGATCAT"), + ]); + alignment.diff_mode = DiffMode::Consensus; + let mut metrics = ColumnStatsCache::default(); + metrics.init(alignment.view().column_count()); + + insta::assert_snapshot!( + "alignment_pane_raw_diff_consensus_loading", + render_alignment_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 12), 0, 0,) + ); + } + + #[test] + fn alignment_pane_scrolled_with_scrollbar_snapshot() { + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCATCATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCATCATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCATCATCATCATCATCATCAT"), + ]); + + insta::assert_snapshot!( + "alignment_pane_scrolled_with_scrollbar", + render_alignment_pane_text( + &alignment, + &ColumnStatsCache::default(), + Rect::new(0, 0, 60, 12), + 0, + 10, + ) + ); + } + + #[test] + fn alignment_pane_pinned_with_vertical_scroll_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCAT"), + raw("seq4", b"CATCATCATCATCATCAT"), + raw("seq5", b"CATCATCATCATCATCAT"), + raw("seq6", b"CATCATCATCATCATCAT"), + ]); + alignment.pin(1).unwrap(); + alignment.pin(4).unwrap(); + + insta::assert_snapshot!( + "alignment_pane_pinned_with_vertical_scroll", + render_alignment_pane_text( + &alignment, + &ColumnStatsCache::default(), + Rect::new(0, 0, 100, 10), + 2, + 0, + ) + ); + } + + #[test] + fn alignment_pane_dense_fragmented_ruler_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CA-CA-CA-CA-CA-CA-CA-CA"), + raw("seq2", b"CA-CA-CA-CA-CA-CA-CA-CA"), + raw("seq3", b"CA-CA-CA-CA-CA-CA-CA-CA"), + ]); + alignment.set_gap_filter(Some(0.5)).unwrap(); + + insta::assert_snapshot!( + "alignment_pane_dense_fragmented_ruler", + render_alignment_pane_text( + &alignment, + &ColumnStatsCache::default(), + Rect::new(0, 0, 100, 12), + 0, + 0, + ) + ); + } +} diff --git a/salti/src/ui/consensus_pane.rs b/salti/src/ui/consensus_pane.rs index 9c0544f..b259d2b 100644 --- a/salti/src/ui/consensus_pane.rs +++ b/salti/src/ui/consensus_pane.rs @@ -300,6 +300,10 @@ mod tests { use super::*; use crate::core::model::StatsView; use crate::core::stats_cache::StatsJobResult; + use ratatui::backend::TestBackend; + use ratatui::buffer::Buffer; + use ratatui::layout::Rect; + use ratatui::Terminal; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -308,11 +312,9 @@ mod tests { } } - fn line_text(line: &Line<'_>) -> String { - line.spans - .iter() - .map(|span| span.content.as_ref()) - .collect() + fn alignment_model(sequences: Vec) -> AlignmentModel { + let alignment = libmsa::Alignment::new(sequences).unwrap(); + AlignmentModel::new(alignment).unwrap() } fn metrics_with( @@ -337,7 +339,6 @@ mod tests { position, consensus: Some(byte), conservation, - gap_fraction: 0.0, }) .collect(); let generation = cache.generation; @@ -352,76 +353,163 @@ mod tests { cache } - #[test] - fn translated_consensus_lines_use_codon_spread_rendering() { - let alignment = - libmsa::Alignment::new(vec![raw("ref", b"ATGAAATTT"), raw("row", b"ATGAAATTT")]) - .expect("alignment should be valid"); - let mut alignment = - AlignmentModel::new(alignment).expect("alignment model should be created"); - alignment.set_reference(0).expect("reference should be set"); - alignment - .set_translation(Some(libmsa::ReadingFrame::Frame1)) - .expect("translation should succeed"); - + fn render_consensus_pane_text( + alignment: &AlignmentModel, + metrics: &ColumnStatsCache, + area: Rect, + ) -> String { + let backend = TestBackend::new(area.width, area.height); + let mut terminal = Terminal::new(backend).unwrap(); + let layout = AppLayout::new(area); let window = ViewportWindow { row_range: 0..alignment.view().row_count(), col_range: 0..alignment.view().column_count(), name_range: 0..0, }; - let lines = consensus_alignment_lines( - &alignment, - &window, - &metrics_with( - StatsView::Translated(libmsa::ReadingFrame::Frame1), - b"MKF", - Some(1.0), - ), - &ThemeState::default(), + + terminal + .draw(|frame| { + render_consensus_pane( + frame, + &layout, + alignment, + &window, + metrics, + &ThemeState::default(), + ); + }) + .unwrap(); + + buffer_text(terminal.backend().buffer()) + } + + fn buffer_text(buffer: &Buffer) -> String { + let area = buffer.area; + let mut lines = Vec::new(); + + for y in area.top()..area.bottom() { + let mut line = String::new(); + for x in area.left()..area.right() { + let symbol = buffer[(x, y)].symbol(); + if symbol.is_empty() { + line.push(' '); + } else { + line.push_str(symbol); + } + } + while line.ends_with(' ') { + line.pop(); + } + lines.push(line); + } + + while matches!(lines.last(), Some(last) if last.is_empty()) { + lines.pop(); + } + + lines.join("\n") + } + + #[test] + fn raw_consensus_pane_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + ]); + alignment.set_reference(0).unwrap(); + let metrics = metrics_with(StatsView::Raw, b"CATCATCATCATCATCAT", Some(1.0)); + + insta::assert_snapshot!( + "consensus_pane_raw", + render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5)) ); + } - assert_eq!(lines.len(), 3); - assert_eq!(line_text(&lines[0]), " M K F "); - assert_eq!(line_text(&lines[1]), " M K F "); - assert_eq!(line_text(&lines[2]), "█████████"); + #[test] + fn raw_consensus_pane_no_reference_and_loading_snapshots() { + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + ]); + let metrics = metrics_with(StatsView::Raw, b"CATCATCATCATCATCAT", Some(1.0)); + + insta::assert_snapshot!( + "consensus_pane_raw_no_reference", + render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5)) + ); + + let mut loading_metrics = ColumnStatsCache::default(); + loading_metrics.init(alignment.view().column_count()); + + insta::assert_snapshot!( + "consensus_pane_raw_loading", + render_consensus_pane_text(&alignment, &loading_metrics, Rect::new(0, 0, 100, 5)) + ); } #[test] - fn translated_mode_keeps_conservation_label() { - let alignment = - libmsa::Alignment::new(vec![raw("ref", b"ATGAAATTT"), raw("row", b"ATGAAATTT")]) - .expect("alignment should be valid"); - let mut alignment = - AlignmentModel::new(alignment).expect("alignment model should be created"); + fn translated_consensus_pane_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + ]); + alignment.set_reference(0).unwrap(); alignment .set_translation(Some(libmsa::ReadingFrame::Frame1)) - .expect("translation should succeed"); + .unwrap(); + let metrics = metrics_with( + StatsView::Translated(libmsa::ReadingFrame::Frame1), + b"HHHHHH", + Some(1.0), + ); - assert!(shows_conservation_line(&alignment)); + insta::assert_snapshot!( + "consensus_pane_translated", + render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5)) + ); } #[test] - fn raw_consensus_lines_keep_conservation_row() { - let alignment = libmsa::Alignment::new(vec![raw("ref", b"ACGT"), raw("row", b"ACGT")]) - .expect("alignment should be valid"); - let mut alignment = - AlignmentModel::new(alignment).expect("alignment model should be created"); - alignment.set_reference(0).expect("reference should be set"); + fn translated_consensus_pane_no_reference_and_loading_snapshots() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + ]); + alignment + .set_translation(Some(libmsa::ReadingFrame::Frame1)) + .unwrap(); + let metrics = metrics_with( + StatsView::Translated(libmsa::ReadingFrame::Frame1), + b"HHHHHH", + Some(1.0), + ); - let window = ViewportWindow { - row_range: 0..alignment.view().row_count(), - col_range: 0..alignment.view().column_count(), - name_range: 0..0, - }; - let lines = consensus_alignment_lines( - &alignment, - &window, - &metrics_with(StatsView::Raw, b"ACGT", Some(1.0)), - &ThemeState::default(), + insta::assert_snapshot!( + "consensus_pane_translated_no_reference", + render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5)) + ); + + let mut loading_metrics = ColumnStatsCache::default(); + loading_metrics.init(alignment.view().column_count()); + + insta::assert_snapshot!( + "consensus_pane_translated_loading", + render_consensus_pane_text(&alignment, &loading_metrics, Rect::new(0, 0, 100, 5)) ); + } - assert_eq!(lines.len(), 3); - assert_eq!(line_text(&lines[0]), "ACGT"); - assert_eq!(line_text(&lines[1]), "ACGT"); + #[test] + fn generic_consensus_pane_hides_conservation_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"ACDEACDEACDE"), + raw("seq2", b"ACDEACDEACDE"), + ]); + alignment.set_reference(0).unwrap(); + let metrics = metrics_with(StatsView::Raw, b"ACDEACDEACDE", Some(1.0)); + + insta::assert_snapshot!( + "consensus_pane_generic_without_conservation", + render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 4)) + ); } } diff --git a/salti/src/ui/frame.rs b/salti/src/ui/frame.rs index 8345210..d77f43e 100644 --- a/salti/src/ui/frame.rs +++ b/salti/src/ui/frame.rs @@ -182,7 +182,7 @@ pub fn render_frame( mod tests { use super::*; use crate::cli::StartupState; - use crate::core::model::AlignmentModel; + use crate::ui::ui_state::MouseSelection; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -195,8 +195,9 @@ mod tests { spans.iter().map(|span| span.content.as_ref()).collect() } - fn top_status_text(alignment: Option<&AlignmentModel>, ui: &UiState) -> String { - status_text(&build_top_status_bar(alignment, ui)) + fn alignment_model(sequences: Vec) -> AlignmentModel { + let alignment = libmsa::Alignment::new(sequences).unwrap(); + AlignmentModel::new(alignment).unwrap() } fn ui_state() -> UiState { @@ -206,111 +207,103 @@ mod tests { } #[test] - fn bottom_status_bar_formats_row_filter_summary() { - let alignment = libmsa::Alignment::new(vec![ - raw("alpha", b"ACGT"), - raw("beta", b"ACGT"), - raw("gamma", b"ACGT"), - ]) - .expect("alignment should be valid"); - let mut alignment = AlignmentModel::new(alignment).expect("alignment model should build"); - alignment - .set_filter("alpha|beta".to_string()) - .expect("row filter should apply"); - let ui = ui_state(); - - assert_eq!( - status_text(&build_bottom_status_bar(Some(&alignment), &ui)), - "Filters: [rows: alpha|beta] (2 rows)" + fn top_status_bar_snapshots() { + let alignment = alignment_model(vec![ + raw("seq1", b"ACGTACGT"), + raw("seq2", b"ACGTAC-T"), + raw("seq3", b"ACGTACGA"), + ]); + + let mut loaded_ui = ui_state(); + loaded_ui.meta.input_path = Some("/iamnotreal.fasta".to_string()); + loaded_ui.viewport.update_dimensions(5, 3, 0); + loaded_ui.viewport.set_bounds( + alignment.view().row_count(), + alignment.view().column_count(), + alignment.base().max_id_len(), ); - } - #[test] - fn bottom_status_bar_formats_row_and_gap_filter_summary() { - let alignment = libmsa::Alignment::new(vec![ - raw("alpha", b"A--T"), - raw("beta", b"A--T"), - raw("gamma", b"ACGT"), - ]) - .expect("alignment should be valid"); - let mut alignment = AlignmentModel::new(alignment).expect("alignment model should build"); - alignment - .set_filter("alpha|beta".to_string()) - .expect("row filter should apply"); - alignment - .set_gap_filter(Some(0.0)) - .expect("gap filter should apply"); - let ui = ui_state(); - - assert_eq!( - status_text(&build_bottom_status_bar(Some(&alignment), &ui)), - "Filters: [rows: alpha|beta] [gaps: <= 0%] (2 rows) (2 cols)" + insta::assert_snapshot!( + "frame_top_status_loaded_alignment", + status_text(&build_top_status_bar(Some(&alignment), &loaded_ui)) ); - } - #[test] - fn bottom_status_bar_formats_constant_filter_summary() { - let alignment = libmsa::Alignment::new(vec![ - raw("alpha", b"AN-T"), - raw("beta", b"A--T"), - raw("gamma", b"ATGT"), - ]) - .expect("alignment should be valid"); - let mut alignment = AlignmentModel::new(alignment).expect("alignment model should build"); - alignment - .set_constant_filter(Some(1.0)) - .expect("constant filter should apply"); - let ui = ui_state(); + let mut failed_ui = UiState::new(StartupState::default()); + failed_ui.meta.loading_state = LoadingState::Failed("boom".to_string()); - assert_eq!( - status_text(&build_bottom_status_bar(Some(&alignment), &ui)), - "Filters: [constant: >= 100%] (3 rows) (2 cols)" + insta::assert_snapshot!( + "frame_top_status_failed_load", + status_text(&build_top_status_bar(None, &failed_ui)) ); } #[test] - fn bottom_status_bar_formats_combined_column_filter_summary() { - let alignment = libmsa::Alignment::new(vec![ - raw("alpha", b"AN-T"), - raw("beta", b"A--T"), - raw("gamma", b"ATGT"), - ]) - .expect("alignment should be valid"); - let mut alignment = AlignmentModel::new(alignment).expect("alignment model should build"); - alignment + fn bottom_status_bar_snapshots() { + let mut filtered_alignment = alignment_model(vec![ + raw("seq1", b"ATGAAATTT"), + raw("seq2", b"ATG---TTT"), + raw("seq3", b"ATGAAGTTT"), + ]); + filtered_alignment + .set_filter("seq1|seq2".to_string()) + .unwrap(); + filtered_alignment .set_gap_filter(Some(0.5)) - .expect("gap filter should apply"); - alignment + .unwrap(); + filtered_alignment + .set_translation(Some(libmsa::ReadingFrame::Frame2)) + .unwrap(); + + insta::assert_snapshot!( + "frame_bottom_status_filters_translation", + status_text(&build_bottom_status_bar(Some(&filtered_alignment), &ui_state())) + ); + + let mut constant_filter_alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCAT"), + raw("seq2", b"CATCATCATCAT"), + raw("seq3", b"CATCATCATCAT"), + ]); + constant_filter_alignment .set_constant_filter(Some(1.0)) - .expect("constant filter should apply"); - let ui = ui_state(); + .unwrap(); - assert_eq!( - status_text(&build_bottom_status_bar(Some(&alignment), &ui)), - "Filters: [gaps: <= 50%] [constant: >= 100%] (3 rows) (2 cols)" + insta::assert_snapshot!( + "frame_bottom_status_constant_filter", + status_text(&build_bottom_status_bar( + Some(&constant_filter_alignment), + &ui_state(), + )) ); - } - #[test] - fn top_status_bar_shows_alignment_length() { - let alignment = libmsa::Alignment::new(vec![ - raw("alpha", b"ACGT"), - raw("beta", b"ACGT"), - raw("gamma", b"ACGT"), - ]) - .expect("alignment should be valid"); - let alignment = AlignmentModel::new(alignment).expect("alignment model should build"); - let mut ui = ui_state(); - ui.viewport.update_dimensions(4, 3, 0); - ui.viewport.set_bounds( - alignment.view().row_count(), - alignment.view().column_count(), - alignment.base().max_id_len(), + let selected_alignment = alignment_model(vec![ + raw("seq1", b"ACGTACGT"), + raw("seq2", b"ACGTACGT"), + ]); + let mut single_selection_ui = ui_state(); + single_selection_ui.selection = Some(MouseSelection { + sequence_id: 0, + column: 5, + end_sequence_id: 0, + end_column: 5, + }); + + insta::assert_snapshot!( + "frame_bottom_status_single_selection", + status_text(&build_bottom_status_bar(Some(&selected_alignment), &single_selection_ui)) ); - assert_eq!( - top_status_text(Some(&alignment), &ui), - "File: Unknown | Status: Loaded | 3 alignments | Length: 4 | Positions: 1-4" + let mut multi_selection_ui = ui_state(); + multi_selection_ui.selection = Some(MouseSelection { + sequence_id: 0, + column: 1, + end_sequence_id: 2, + end_column: 4, + }); + + insta::assert_snapshot!( + "frame_bottom_status_multi_selection", + status_text(&build_bottom_status_bar(None, &multi_selection_ui)) ); } } diff --git a/salti/src/ui/render.rs b/salti/src/ui/render.rs index 45aabd3..b07ce77 100644 --- a/salti/src/ui/render.rs +++ b/salti/src/ui/render.rs @@ -304,3 +304,265 @@ pub fn render( ui, ); } + +#[cfg(test)] +mod tests { + use super::*; + use crate::cli::StartupState; + use crate::core::model::{DiffMode, StatsView}; + use crate::core::stats_cache::StatsJobResult; + use crate::overlay::command_palette::CommandPaletteState; + use crate::ui::notification::{Notification, NotificationLevel}; + use crate::ui::ui_state::MouseSelection; + use ratatui::backend::TestBackend; + use ratatui::buffer::Buffer; + use ratatui::Terminal; + + fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { + libmsa::RawSequence { + id: id.to_string(), + sequence: sequence.to_vec(), + } + } + + fn alignment_model(sequences: Vec) -> AlignmentModel { + let alignment = libmsa::Alignment::new(sequences).unwrap(); + AlignmentModel::new(alignment).unwrap() + } + + fn metrics_with( + view: StatsView, + consensus: &[u8], + conservation: Option, + ) -> ColumnStatsCache { + let mut cache = ColumnStatsCache::default(); + match view { + StatsView::Raw => cache.init(consensus.len()), + StatsView::Translated(frame) => { + cache.init(consensus.len() * 3); + let _ = + cache.translated_chunks_to_spawn(&(0..consensus.len()), frame, consensus.len()); + } + } + + let summaries = consensus + .iter() + .enumerate() + .map(|(position, &byte)| libmsa::ColumnSummary { + position, + consensus: Some(byte), + conservation, + }) + .collect(); + let generation = cache.generation; + let chunk_idx = 0; + let stored = cache.store(StatsJobResult { + generation, + chunk_idx, + view, + summaries: Ok(summaries), + }); + assert!(stored); + cache + } + + fn ui_state() -> UiState { + let mut ui = UiState::new(StartupState::default()); + ui.meta.loading_state = LoadingState::Loaded; + ui + } + + fn render_text( + alignment: Option<&AlignmentModel>, + ui: &UiState, + stats_cache: &ColumnStatsCache, + area: Rect, + ) -> String { + let backend = TestBackend::new(area.width, area.height); + let mut terminal = Terminal::new(backend).unwrap(); + let frame_layout = FrameLayout::new(area); + let layout = AppLayout::new(frame_layout.content_area); + + terminal + .draw(|frame| { + render(frame, alignment, ui, stats_cache, &frame_layout, &layout); + }) + .unwrap(); + + buffer_text(terminal.backend().buffer(), area) + } + + fn buffer_text(buffer: &Buffer, area: Rect) -> String { + let mut lines = Vec::new(); + + for y in area.top()..area.bottom() { + let mut line = String::new(); + for x in area.left()..area.right() { + let symbol = buffer[(x, y)].symbol(); + if symbol.is_empty() { + line.push(' '); + } else { + line.push_str(symbol); + } + } + while line.ends_with(' ') { + line.pop(); + } + lines.push(line); + } + + while matches!(lines.last(), Some(last) if last.is_empty()) { + lines.pop(); + } + + lines.join("\n") + } + + fn set_viewport(ui: &mut UiState, alignment: &AlignmentModel, area: Rect) { + let frame_layout = FrameLayout::new(area); + let layout = AppLayout::new(frame_layout.content_area); + ui.viewport.update_dimensions( + layout.alignment_pane_sequence_rows.width as usize, + layout.alignment_pane_sequence_rows.height as usize, + layout.sequence_id_pane.width.saturating_sub(2) as usize, + ); + ui.viewport.set_bounds( + alignment.view().row_count(), + alignment.view().column_count(), + alignment.base().max_id_len(), + ); + } + + #[test] + fn render_empty_state_snapshots() { + let area = Rect::new(0, 0, 100, 24); + + let idle_ui = UiState::new(StartupState::default()); + insta::assert_snapshot!( + "render_empty_idle", + render_text(None, &idle_ui, &ColumnStatsCache::default(), area) + ); + + let mut failed_ui = UiState::new(StartupState::default()); + failed_ui.meta.loading_state = LoadingState::Failed("boom".to_string()); + insta::assert_snapshot!( + "render_empty_failed", + render_text(None, &failed_ui, &ColumnStatsCache::default(), area) + ); + + let mut loading_ui = UiState::new(StartupState::default()); + loading_ui.meta.loading_state = LoadingState::Loading; + insta::assert_snapshot!( + "render_empty_loading", + render_text(None, &loading_ui, &ColumnStatsCache::default(), area) + ); + } + + #[test] + fn render_loaded_alignment_snapshots() { + let area = Rect::new(0, 0, 100, 24); + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATGATCATCATCAT"), + raw("seq3", b"CATCATCATCATGATCAT"), + raw("seq4", b"CATCATCATCATCATCAT"), + ]); + let metrics = metrics_with(StatsView::Raw, b"CATCATCATCATCATCAT", Some(1.0)); + let mut ui = ui_state(); + set_viewport(&mut ui, &alignment, area); + + insta::assert_snapshot!("render_loaded_basic", render_text(Some(&alignment), &ui, &metrics, area)); + + let mut selection_ui = ui_state(); + set_viewport(&mut selection_ui, &alignment, area); + selection_ui.selection = Some(MouseSelection { + sequence_id: 1, + column: 2, + end_sequence_id: 2, + end_column: 8, + }); + insta::assert_snapshot!( + "render_loaded_with_selection_status", + render_text(Some(&alignment), &selection_ui, &metrics, area) + ); + } + + #[test] + fn render_loaded_translation_snapshot() { + let area = Rect::new(0, 0, 100, 24); + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATGATCATCATCAT"), + raw("seq3", b"CATCATCATCATGATCAT"), + ]); + alignment.set_reference(0).unwrap(); + alignment.set_translation(Some(libmsa::ReadingFrame::Frame1)).unwrap(); + alignment.diff_mode = DiffMode::Reference; + let metrics = metrics_with(StatsView::Translated(libmsa::ReadingFrame::Frame1), b"HHHHHH", Some(1.0)); + let mut ui = ui_state(); + set_viewport(&mut ui, &alignment, area); + + insta::assert_snapshot!( + "render_loaded_translation", + render_text(Some(&alignment), &ui, &metrics, area) + ); + } + + #[test] + fn render_notification_snapshot() { + let area = Rect::new(0, 0, 100, 24); + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + ]); + let metrics = metrics_with(StatsView::Raw, b"CATCATCATCATCATCAT", Some(1.0)); + let mut ui = ui_state(); + set_viewport(&mut ui, &alignment, area); + ui.notification = Some(Notification { + level: NotificationLevel::Info, + message: "Loaded alignment".to_string(), + }); + + insta::assert_snapshot!( + "render_notification", + render_text(Some(&alignment), &ui, &metrics, area) + ); + } + + #[test] + fn render_command_palette_snapshot() { + let area = Rect::new(0, 0, 100, 24); + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + ]); + let metrics = metrics_with(StatsView::Raw, b"CATCATCATCATCATCAT", Some(1.0)); + let mut ui = ui_state(); + set_viewport(&mut ui, &alignment, area); + ui.overlay.open_palette(CommandPaletteState::empty()); + + insta::assert_snapshot!( + "render_command_palette", + render_text(Some(&alignment), &ui, &metrics, area) + ); + } + + #[test] + fn render_minimap_snapshot() { + let area = Rect::new(0, 0, 100, 24); + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCATCATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCATCATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCATCATCATCATCATCATCAT"), + ]); + let metrics = metrics_with(StatsView::Raw, b"CATCATCATCATCATCATCATCATCATCATCATCAT", Some(1.0)); + let mut ui = ui_state(); + set_viewport(&mut ui, &alignment, area); + ui.overlay.toggle_minimap(); + + insta::assert_snapshot!( + "render_minimap", + render_text(Some(&alignment), &ui, &metrics, area) + ); + } +} diff --git a/salti/src/ui/rows.rs b/salti/src/ui/rows.rs index f3ef5bd..d98ca6d 100644 --- a/salti/src/ui/rows.rs +++ b/salti/src/ui/rows.rs @@ -219,8 +219,8 @@ mod tests { let sequence = alignment .translated(libmsa::ReadingFrame::Frame1) .expect("DNA alignment should translate") - .sequence_by_absolute(0) - .expect("visible row should resolve"); + .project_absolute_row(0) + .expect("row should resolve"); let spans = format_translated_row_spans( sequence, @@ -241,8 +241,8 @@ mod tests { let sequence = alignment .translated(libmsa::ReadingFrame::Frame1) .expect("DNA alignment should translate") - .sequence_by_absolute(0) - .expect("visible row should resolve"); + .project_absolute_row(0) + .expect("row should resolve"); let diff_against = TranslatedDiffRange::new(0, b"MKF"); let spans = format_translated_row_spans( @@ -263,8 +263,8 @@ mod tests { let sequence = alignment .translated(libmsa::ReadingFrame::Frame1) .expect("DNA alignment should translate") - .sequence_by_absolute(0) - .expect("visible row should resolve"); + .project_absolute_row(0) + .expect("row should resolve"); let diff_against = TranslatedDiffRange::new(0, b"MKF"); let spans = format_translated_row_spans( @@ -288,8 +288,8 @@ mod tests { let sequence = alignment .translated(libmsa::ReadingFrame::Frame2) .expect("DNA alignment should translate") - .sequence_by_absolute(0) - .expect("visible row should resolve"); + .project_absolute_row(0) + .expect("row should resolve"); let spans = format_translated_row_spans( sequence, diff --git a/salti/src/ui/selection.rs b/salti/src/ui/selection.rs index 56f6fe0..8c55478 100644 --- a/salti/src/ui/selection.rs +++ b/salti/src/ui/selection.rs @@ -155,7 +155,6 @@ fn translated_selection_visible_col_range( mod tests { use super::*; use crate::core::Viewport; - use crate::core::codon::codon_span_for_absolute_column; use crate::core::model::AlignmentModel; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { @@ -219,24 +218,6 @@ mod tests { assert!(range.is_none()); } - #[test] - fn codon_span_maps_any_column_in_the_same_codon() { - let frame = libmsa::ReadingFrame::Frame1; - - assert_eq!(codon_span_for_absolute_column(0, frame, 9), Some(0..3)); - assert_eq!(codon_span_for_absolute_column(1, frame, 9), Some(0..3)); - assert_eq!(codon_span_for_absolute_column(2, frame, 9), Some(0..3)); - assert_eq!(codon_span_for_absolute_column(3, frame, 9), Some(3..6)); - } - - #[test] - fn codon_span_returns_none_for_partial_frame_edges() { - let frame = libmsa::ReadingFrame::Frame2; - - assert_eq!(codon_span_for_absolute_column(0, frame, 9), None); - assert_eq!(codon_span_for_absolute_column(8, frame, 9), None); - } - #[test] fn translated_selection_visible_col_range_expands_to_overlapping_codon() { let alignment = diff --git a/salti/src/ui/sequence_id_pane.rs b/salti/src/ui/sequence_id_pane.rs index c4f6174..5a50a59 100644 --- a/salti/src/ui/sequence_id_pane.rs +++ b/salti/src/ui/sequence_id_pane.rs @@ -128,3 +128,127 @@ pub fn render_sequence_id_pane( render_sequence_id_rows(f, alignment, window, theme, inner_area); } + +#[cfg(test)] +mod tests { + use super::*; + use ratatui::backend::TestBackend; + use ratatui::buffer::Buffer; + use ratatui::layout::Rect; + use ratatui::Terminal; + + fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { + libmsa::RawSequence { + id: id.to_string(), + sequence: sequence.to_vec(), + } + } + + fn alignment_model(sequences: Vec) -> AlignmentModel { + let alignment = libmsa::Alignment::new(sequences).unwrap(); + AlignmentModel::new(alignment).unwrap() + } + + fn render_sequence_id_pane_text(alignment: &AlignmentModel, window: &ViewportWindow) -> String { + let area = Rect::new(0, 0, 150, 12); + let backend = TestBackend::new(area.width, area.height); + let mut terminal = Terminal::new(backend).unwrap(); + let layout = AppLayout::new(area); + + terminal + .draw(|frame| { + render_sequence_id_pane(frame, &layout, alignment, window, &ThemeState::default()); + }) + .unwrap(); + + buffer_text(terminal.backend().buffer()) + } + + fn buffer_text(buffer: &Buffer) -> String { + let area = buffer.area; + let mut lines = Vec::new(); + + for y in area.top()..area.bottom() { + let mut line = String::new(); + for x in area.left()..area.right() { + let symbol = buffer[(x, y)].symbol(); + if symbol.is_empty() { + line.push(' '); + } else { + line.push_str(symbol); + } + } + while line.ends_with(' ') { + line.pop(); + } + lines.push(line); + } + + while matches!(lines.last(), Some(last) if last.is_empty()) { + lines.pop(); + } + + lines.join("\n") + } + + #[test] + fn sequence_id_pane_basic_snapshot() { + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCAT"), + ]); + let window = ViewportWindow { + row_range: 0..alignment.view().row_count(), + col_range: 0..alignment.view().column_count(), + name_range: 0..18, + }; + + insta::assert_snapshot!( + "sequence_id_pane_basic", + render_sequence_id_pane_text(&alignment, &window) + ); + } + + #[test] + fn sequence_id_pane_pinned_snapshot() { + let mut alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCAT"), + raw("seq4", b"CATCATCATCATCATCAT"), + ]); + alignment.pin(1).unwrap(); + alignment.pin(3).unwrap(); + + let window = ViewportWindow { + row_range: 0..alignment.view().row_count(), + col_range: 0..alignment.view().column_count(), + name_range: 0..18, + }; + + insta::assert_snapshot!( + "sequence_id_pane_pinned", + render_sequence_id_pane_text(&alignment, &window) + ); + } + + #[test] + fn sequence_id_pane_name_scroll_snapshot() { + let alignment = alignment_model(vec![ + raw("seq1-loooooooooooong-name", b"CATCATCATCATCATCAT"), + raw("seq2-loooooooooooong-name", b"CATCATCATCATCATCAT"), + raw("seq3-loooooooooooong-name", b"CATCATCATCATCATCAT"), + ]); + let window = ViewportWindow { + row_range: 0..alignment.view().row_count(), + col_range: 0..alignment.view().column_count(), + name_range: 5..23, + }; + + insta::assert_snapshot!( + "sequence_id_pane_name_scroll", + render_sequence_id_pane_text(&alignment, &window) + ); + } +} diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_basic.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_basic.snap new file mode 100644 index 0000000..0deefc4 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_basic.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 619 +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12),)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 │ +│. . | . │ +│CATCATCATCATCATCAT │ +│CATCATCATCATCATCAT │ +│CATCATCATCATCATCAT │ +│ │ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_dense_fragmented_ruler.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_dense_fragmented_ruler.snap new file mode 100644 index 0000000..be0fb71 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_dense_fragmented_ruler.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 871 +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 20 │ +│. ~~~~~~~~~~~~~ │ +│CACACACACACACACA │ +│CACACACACACACACA │ +│CACACACACACACACA │ +│ │ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_and_fragmented.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_and_fragmented.snap new file mode 100644 index 0000000..127f6e3 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_and_fragmented.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 641 +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12),)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 │ +│. › | . │ +│CATCATCATCATCAT │ +│CATCATCATCATCAT │ +│───────────────────────────────────────────────────────────────────────────────│ +│CATCATCATCATCAT │ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_with_vertical_scroll.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_with_vertical_scroll.snap new file mode 100644 index 0000000..1fa1e87 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_with_vertical_scroll.snap @@ -0,0 +1,11 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 850 +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 10), 2, 0,)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 │ +│. . | . │ +│CATCATCATCATCATCAT │ +│───────────────────────────────────────────────────────────────────────────────│ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus.snap new file mode 100644 index 0000000..aaae619 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 794 +expression: "render_alignment_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 12), 0,\n0,)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 │ +│. . | . │ +│.................. │ +│......G........... │ +│............G..... │ +│ │ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus_loading.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus_loading.snap new file mode 100644 index 0000000..63ce4b2 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus_loading.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 811 +expression: "render_alignment_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 12), 0,\n0,)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 │ +│. . | . │ +│CATCATCATCATCATCAT │ +│CATCATGATCATCATCAT │ +│CATCATCATCATGATCAT │ +│ │ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference.snap new file mode 100644 index 0000000..467f09c --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 728 +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 │ +│. . | . │ +│......G........... │ +│............G..... │ +│ │ +│ │ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference_without_reference.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference_without_reference.snap new file mode 100644 index 0000000..de17b15 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference_without_reference.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 772 +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 │ +│. . | . │ +│CATCATCATCATCATCAT │ +│CATCATGATCATCATCAT │ +│CATCATCATCATGATCAT │ +│ │ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_scrolled_with_scrollbar.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_scrolled_with_scrollbar.snap new file mode 100644 index 0000000..8ba37ab --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_scrolled_with_scrollbar.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 825 +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 60, 12), 0, 10,)" +--- +┌Alignment──────────────────────────────────────┐ +│ 20 30 │ +│ . | . | . │ +│ATCATCATCATCATCATCATCATCAT │ +│ATCATCATCATCATCATCATCATCAT │ +│ATCATCATCATCATCATCATCATCAT │ +│ │ +└───────────▬▬▬─────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated.snap new file mode 100644 index 0000000..8efdfe1 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 660 +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12),)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 │ +│. . | . │ +│ H H H H H H │ +│ H H H H H H │ +│ H H H H H H │ +│ │ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated_diff_reference.snap b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated_diff_reference.snap new file mode 100644 index 0000000..e429cf9 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated_diff_reference.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/alignment_pane.rs +assertion_line: 751 +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" +--- +┌Alignment──────────────────────────────────────────────────────────────────────┐ +│1 10 │ +│. . | . │ +│ . . D . . . │ +│ . . . . D . │ +│ │ +│ │ +└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_generic_without_conservation.snap b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_generic_without_conservation.snap new file mode 100644 index 0000000..402865a --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_generic_without_conservation.snap @@ -0,0 +1,9 @@ +--- +source: salti/src/ui/consensus_pane.rs +assertion_line: 510 +expression: "render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 4))" +--- +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ +│Reference Sequence│ACDEACDEACDE │ +│Consensus Sequence│ACDEACDEACDE │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw.snap b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw.snap new file mode 100644 index 0000000..39187a2 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw.snap @@ -0,0 +1,10 @@ +--- +source: salti/src/ui/consensus_pane.rs +assertion_line: 422 +expression: "render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5))" +--- +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ +│Reference Sequence│CATCATCATCATCATCAT │ +│Consensus Sequence│CATCATCATCATCATCAT │ +│Conservation: │██████████████████ │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_loading.snap b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_loading.snap new file mode 100644 index 0000000..0bef212 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_loading.snap @@ -0,0 +1,10 @@ +--- +source: salti/src/ui/consensus_pane.rs +assertion_line: 444 +expression: "render_consensus_pane_text(&alignment, &loading_metrics,\nRect::new(0, 0, 100, 5))" +--- +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ +│Reference Sequence│No reference selected │ +│Consensus Sequence│Calculating consensus... │ +│Conservation: │Calculating conservation... │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_no_reference.snap b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_no_reference.snap new file mode 100644 index 0000000..275c39b --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_no_reference.snap @@ -0,0 +1,10 @@ +--- +source: salti/src/ui/consensus_pane.rs +assertion_line: 436 +expression: "render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5))" +--- +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ +│Reference Sequence│No reference selected │ +│Consensus Sequence│CATCATCATCATCATCAT │ +│Conservation: │██████████████████ │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated.snap b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated.snap new file mode 100644 index 0000000..8c8735a --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated.snap @@ -0,0 +1,10 @@ +--- +source: salti/src/ui/consensus_pane.rs +assertion_line: 466 +expression: "render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5))" +--- +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ +│Reference Sequence│ H H H H H H │ +│Consensus Sequence│ H H H H H H │ +│Conservation: │██████████████████ │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_loading.snap b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_loading.snap new file mode 100644 index 0000000..adc5a4b --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_loading.snap @@ -0,0 +1,10 @@ +--- +source: salti/src/ui/consensus_pane.rs +assertion_line: 495 +expression: "render_consensus_pane_text(&alignment, &loading_metrics,\nRect::new(0, 0, 100, 5))" +--- +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ +│Reference Sequence│No reference selected │ +│Consensus Sequence│Calculating consensus... │ +│Conservation: │Calculating conservation... │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_no_reference.snap b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_no_reference.snap new file mode 100644 index 0000000..f6b8bc9 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_no_reference.snap @@ -0,0 +1,10 @@ +--- +source: salti/src/ui/consensus_pane.rs +assertion_line: 487 +expression: "render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5))" +--- +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ +│Reference Sequence│No reference selected │ +│Consensus Sequence│ H H H H H H │ +│Conservation: │██████████████████ │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_constant_filter.snap b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_constant_filter.snap new file mode 100644 index 0000000..ca16c43 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_constant_filter.snap @@ -0,0 +1,6 @@ +--- +source: salti/src/ui/frame.rs +assertion_line: 285 +expression: "status_text(&build_bottom_status_bar(Some(&constant_filter_alignment),\n&ui_state(),))" +--- +Filters: [constant: >= 100%] (3 rows) (0 cols) diff --git a/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_filters_translation.snap b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_filters_translation.snap new file mode 100644 index 0000000..1feb2d2 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_filters_translation.snap @@ -0,0 +1,6 @@ +--- +source: salti/src/ui/frame.rs +assertion_line: 271 +expression: "status_text(&build_bottom_status_bar(Some(&filtered_alignment), &ui_state()))" +--- +Filters: [rows: seq1|seq2] [gaps: <= 50%] (2 rows) (9 cols) | Translation frame: 2 diff --git a/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_multi_selection.snap b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_multi_selection.snap new file mode 100644 index 0000000..8b1d337 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_multi_selection.snap @@ -0,0 +1,6 @@ +--- +source: salti/src/ui/frame.rs +assertion_line: 301 +expression: "status_text(&build_bottom_status_bar(None, &multi_selection_ui))" +--- +3 sequence(s) selected @ 2-5 diff --git a/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_single_selection.snap b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_single_selection.snap new file mode 100644 index 0000000..cb4a887 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_bottom_status_single_selection.snap @@ -0,0 +1,6 @@ +--- +source: salti/src/ui/frame.rs +assertion_line: 288 +expression: "status_text(&build_bottom_status_bar(Some(&selected_alignment),\n&single_selection_ui))" +--- +Selected: seq1 @ 6 diff --git a/salti/src/ui/snapshots/salti__ui__frame__tests__frame_top_status_failed_load.snap b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_top_status_failed_load.snap new file mode 100644 index 0000000..da169c7 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_top_status_failed_load.snap @@ -0,0 +1,6 @@ +--- +source: salti/src/ui/frame.rs +assertion_line: 248 +expression: "status_text(&build_top_status_bar(None, &failed_ui))" +--- +File: Unknown | Status: Failed | 0 alignments | Length: 0 | Positions: 0-0 diff --git a/salti/src/ui/snapshots/salti__ui__frame__tests__frame_top_status_loaded_alignment.snap b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_top_status_loaded_alignment.snap new file mode 100644 index 0000000..8e4de94 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__frame__tests__frame_top_status_loaded_alignment.snap @@ -0,0 +1,6 @@ +--- +source: salti/src/ui/frame.rs +assertion_line: 240 +expression: "status_text(&build_top_status_bar(Some(&alignment), &loaded_ui))" +--- +File: iamnotreal.fasta | Status: Loaded | 3 alignments | Length: 8 | Positions: 1-5 diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap new file mode 100644 index 0000000..23c0db7 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap @@ -0,0 +1,29 @@ +--- +source: salti/src/ui/render.rs +assertion_line: 544 +expression: "render_text(Some(&alignment), &ui, &metrics, area)" +--- + File: Unknown | Status: Loaded | 2 alignments | Length: 18 | Positions: 1-18 +┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +│ │1 10 │ +│ │. . | . │ +│1 seq1 │CATCATCATCATCATCAT │ +│2 seq2 │CATCATCATCATCATCAT │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ +jump-position clear-filter toggle-translate load-alignment +jump-sequence filter-gaps reload-as-protein set-consensus-method +pin-sequence filter-constant check-update set-translation-frame +unpin-sequence set-reference quit set-theme +filter-rows clear-reference set-diff-mode set-sequence-type +:█ diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_failed.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_failed.snap new file mode 100644 index 0000000..684d717 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_failed.snap @@ -0,0 +1,17 @@ +--- +source: salti/src/ui/render.rs +assertion_line: 448 +expression: "render_text(None, &failed_ui, &ColumnStatsCache::default(), area)" +--- + File: Unknown | Status: Failed | 0 alignments | Length: 0 | Positions: 0-0 + + + + + + + + + + + Failed to load alignment: boom diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_idle.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_idle.snap new file mode 100644 index 0000000..cb798f1 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_idle.snap @@ -0,0 +1,18 @@ +--- +source: salti/src/ui/render.rs +assertion_line: 441 +expression: "render_text(None, &idle_ui, &ColumnStatsCache::default(), area)" +--- + File: Unknown | Status: Idle | 0 alignments | Length: 0 | Positions: 0-0 + + + + + + + + + salti: A modern MSA browser for the terminal. + Use the command palette to open an alignment. + + Hint: use :load-alignment diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_loading.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_loading.snap new file mode 100644 index 0000000..8382835 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_loading.snap @@ -0,0 +1,6 @@ +--- +source: salti/src/ui/render.rs +assertion_line: 455 +expression: "render_text(None, &loading_ui, &ColumnStatsCache::default(), area)" +--- + File: Unknown | Status: Loading | 0 alignments | Length: 0 | Positions: 0-0 diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_basic.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_basic.snap new file mode 100644 index 0000000..ec18596 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_basic.snap @@ -0,0 +1,27 @@ +--- +source: salti/src/ui/render.rs +assertion_line: 474 +expression: "render_text(Some(&alignment), &ui, &metrics, area)" +--- + File: Unknown | Status: Loaded | 4 alignments | Length: 18 | Positions: 1-18 +┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +│ │1 10 │ +│ │. . | . │ +│1 seq1 │CATCATCATCATCATCAT │ +│2 seq2 │CATCATGATCATCATCAT │ +│3 seq3 │CATCATCATCATGATCAT │ +│4 seq4 │CATCATCATCATCATCAT │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ +│Reference Sequence│No reference selected │ +│Consensus Sequence│CATCATCATCATCATCAT │ +│Conservation: │██████████████████ │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_translation.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_translation.snap new file mode 100644 index 0000000..9d3a10c --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_translation.snap @@ -0,0 +1,28 @@ +--- +source: salti/src/ui/render.rs +assertion_line: 505 +expression: "render_text(Some(&alignment), &ui, &metrics, area)" +--- + File: Unknown | Status: Loaded | 2 alignments | Length: 18 | Positions: 1-18 +┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +│ │1 10 │ +│ │. . | . │ +│2 seq2 │ . . D . . . │ +│3 seq3 │ . . . . D . │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ +│Reference Sequence│ H H H H H H │ +│Consensus Sequence│ H H H H H H │ +│Conservation: │██████████████████ │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ + Translation frame: 1 diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_with_selection_status.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_with_selection_status.snap new file mode 100644 index 0000000..70cf9aa --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_with_selection_status.snap @@ -0,0 +1,28 @@ +--- +source: salti/src/ui/render.rs +assertion_line: 484 +expression: "render_text(Some(&alignment), &selection_ui, &metrics, area)" +--- + File: Unknown | Status: Loaded | 4 alignments | Length: 18 | Positions: 1-18 +┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +│ │1 10 │ +│ │. . | . │ +│1 seq1 │CATCATCATCATCATCAT │ +│2 seq2 │CATCATGATCATCATCAT │ +│3 seq3 │CATCATCATCATGATCAT │ +│4 seq4 │CATCATCATCATCATCAT │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ +│Reference Sequence│No reference selected │ +│Consensus Sequence│CATCATCATCATCATCAT │ +│Conservation: │██████████████████ │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ + 2 sequence(s) selected @ 3-9 diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_minimap.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_minimap.snap new file mode 100644 index 0000000..b8fae7a --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_minimap.snap @@ -0,0 +1,29 @@ +--- +source: salti/src/ui/render.rs +assertion_line: 563 +expression: "render_text(Some(&alignment), &ui, &metrics, area)" +--- + File: Unknown | Status: Loaded | 3 alignments | Length: 36 | Positions: 1-36 +┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +│ │1 10 20 30 │ +│ │. . | . | . | . │ +│1 seq1 │CATCATCATCATCATCATCATCATCATCATCATCAT │ +│2 seq2 │CATCATCATCATCATCATCATCATCATCATCATCAT │ +│3 seq3 │CATCATCATCATCATCATCATCATCATCATCATCAT │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ +│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│ +│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│ +│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│ +│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│ +│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│ +└──────────────────────────────────────────────────────────────────────────────────────────────────┘ +Drag to pan diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_notification.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_notification.snap new file mode 100644 index 0000000..92cf1f9 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_notification.snap @@ -0,0 +1,29 @@ +--- +source: salti/src/ui/render.rs +assertion_line: 526 +expression: "render_text(Some(&alignment), &ui, &metrics, area)" +--- + File: Unknown | Status: Loaded | 2 alignments | Length: 18 | Positions: 1-18 +┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +│ │1 10 │ +│ │. . | . │ +│1 seq1 │CATCATCATCATCATCAT │ +│2 seq2 │CATCATCATCATCATCAT │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ +│Reference Sequence│No reference selected │ +│Consensus Sequence│CATCATCATCATCATCAT │ +│Conservation: │██████████████████ │ +└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ + +Loaded alignment diff --git a/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_basic.snap b/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_basic.snap new file mode 100644 index 0000000..9802923 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_basic.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/sequence_id_pane.rs +assertion_line: 207 +expression: "render_sequence_id_pane_text(&alignment, &window)" +--- +┌Sequence Name───────────────┐ +│ │ +│ │ +│1 seq1 │ +│2 seq2 │ +│3 seq3 │ +│ │ +└────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_name_scroll.snap b/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_name_scroll.snap new file mode 100644 index 0000000..989ad48 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_name_scroll.snap @@ -0,0 +1,12 @@ +--- +source: salti/src/ui/sequence_id_pane.rs +expression: "render_sequence_id_pane_text(&alignment, &window)" +--- +┌Sequence Name───────────────┐ +│ │ +│ │ +│1 loooooooooooong-na │ +│2 loooooooooooong-na │ +│3 loooooooooooong-na │ +│ │ +└────────────────────────────┘ diff --git a/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_pinned.snap b/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_pinned.snap new file mode 100644 index 0000000..5a0a0e9 --- /dev/null +++ b/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_pinned.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/sequence_id_pane.rs +assertion_line: 230 +expression: "render_sequence_id_pane_text(&alignment, &window)" +--- +┌Sequence Name───────────────┐ +│ │ +│Pinned sequences: │ +│2 seq2 │ +│4 seq4 │ +│────────────────────────────│ +│1 seq1 │ +└────────────────────────────┘ From 14418f9ffea31c0a033758e5ef75661998854e59 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sat, 4 Apr 2026 15:00:00 +0100 Subject: [PATCH 12/48] fix(salti): ruler major tick mark rendering and render frame when translated --- libmsa/src/model.rs | 2 ++ salti/src/ui/alignment_pane.rs | 10 +++--- salti/src/ui/frame.rs | 58 +++++++++++++++++++++------------- salti/src/ui/rows.rs | 2 +- 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/libmsa/src/model.rs b/libmsa/src/model.rs index 7f2368b..60d2a12 100644 --- a/libmsa/src/model.rs +++ b/libmsa/src/model.rs @@ -358,12 +358,14 @@ impl<'a> RowView<'a> { if range.is_empty() { return Err(AlignmentError::EmptyRange); } + if range.end > self.columns.len() { return Err(AlignmentError::ColumnOutOfBounds { index: range.end - 1, length: self.columns.len(), }); } + let columns = self.columns; let data = self.data; Ok(range.map(move |rel_col| { diff --git a/salti/src/ui/alignment_pane.rs b/salti/src/ui/alignment_pane.rs index 1129267..4e6da85 100644 --- a/salti/src/ui/alignment_pane.rs +++ b/salti/src/ui/alignment_pane.rs @@ -425,12 +425,10 @@ fn build_ruler( ".".set_style(theme.styles.text_dim) }; - let should_label = if let Some(run_starts) = &run_starts { - run_starts.contains(&index) - } else { - is_major_tick || display_pos == 1 - }; - if should_label { + let is_run_start = run_starts + .as_ref() + .is_some_and(|run_starts| run_starts.contains(&index)); + if is_major_tick || display_pos == 1 || is_run_start { let _ = add_number_to_ruler(&mut number_line, index, display_pos, theme); } } diff --git a/salti/src/ui/frame.rs b/salti/src/ui/frame.rs index d77f43e..13e217a 100644 --- a/salti/src/ui/frame.rs +++ b/salti/src/ui/frame.rs @@ -30,30 +30,44 @@ fn build_bottom_status_bar(alignment: Option<&AlignmentModel>, ui: &UiState) -> let theme = &ui.theme.styles; let mut parts = Vec::new(); - if let Some(alignment) = alignment.filter(|alignment| alignment.filter().is_active()) { - let visible_rows = alignment.view().row_count(); - let mut filter_text = String::from("Filters:"); - let mut counts = format!(" ({visible_rows} rows)"); - if let Some(pattern) = alignment.filter().pattern() { - filter_text.push_str(&format!(" [rows: {pattern}]")); - } - if let Some(max_gap_fraction) = alignment.filter().max_gap_fraction() { - filter_text.push_str(&format!( - " [gaps: <= {}%]", - format_percent(max_gap_fraction) - )); - } - if let Some(min_constant_fraction) = alignment.filter().min_constant_fraction() { - filter_text.push_str(&format!( - " [constant: >= {}%]", - format_percent(min_constant_fraction) - )); + if let Some(alignment) = alignment { + if alignment.filter().is_active() { + let visible_rows = alignment.view().row_count(); + let mut filter_text = String::from("Filters:"); + let mut counts = format!(" ({visible_rows} rows)"); + if let Some(pattern) = alignment.filter().pattern() { + filter_text.push_str(&format!(" [rows: {pattern}]")); + } + if let Some(max_gap_fraction) = alignment.filter().max_gap_fraction() { + filter_text.push_str(&format!( + " [gaps: <= {}%]", + format_percent(max_gap_fraction) + )); + } + if let Some(min_constant_fraction) = alignment.filter().min_constant_fraction() { + filter_text.push_str(&format!( + " [constant: >= {}%]", + format_percent(min_constant_fraction) + )); + } + if alignment.filter().has_column_filter() { + let visible_cols = alignment.view().column_count(); + counts.push_str(&format!(" ({visible_cols} cols)")); + } + parts.push(format!("{filter_text}{counts}").set_style(theme.warning)); } - if alignment.filter().has_column_filter() { - let visible_cols = alignment.view().column_count(); - counts.push_str(&format!(" ({visible_cols} cols)")); + + let translation_active = + alignment.translation().is_some() || alignment.is_reloaded_as_protein(); + if translation_active { + if !parts.is_empty() { + parts.push(Span::raw(" | ")); + } + parts.push( + format!("Translation frame: {}", alignment.translation_frame()) + .set_style(theme.text), + ); } - parts.push(format!("{filter_text}{counts}").set_style(theme.warning)); } // optional selection info building diff --git a/salti/src/ui/rows.rs b/salti/src/ui/rows.rs index d98ca6d..bb8dc9a 100644 --- a/salti/src/ui/rows.rs +++ b/salti/src/ui/rows.rs @@ -177,7 +177,7 @@ fn format_translated_spans( } /// Collects visible bytes from a sequence view for the given relative column range. -pub fn visible_bytes(sequence: libmsa::SequenceView<'_>, col_range: &Range) -> Vec { +pub fn visible_bytes(sequence: libmsa::RowView<'_>, col_range: &Range) -> Vec { if col_range.is_empty() { return Vec::new(); } From 0ffaa47e2b33a21a6ca985cce100232ea6c4af20 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sat, 11 Apr 2026 08:05:00 +0100 Subject: [PATCH 13/48] feat(salti): add gff parser module --- salti/src/core/gff.rs | 226 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 salti/src/core/gff.rs diff --git a/salti/src/core/gff.rs b/salti/src/core/gff.rs new file mode 100644 index 0000000..7ae604d --- /dev/null +++ b/salti/src/core/gff.rs @@ -0,0 +1,226 @@ +use std::fs::File; +use std::io::BufReader; +use std::path::Path; + +use anyhow::{Result, format_err}; +use noodles_gff as gff; + +#[derive(Debug)] +pub struct Feature { + pub name: String, + pub feature_type: String, + pub start: usize, + pub end: usize, + pub strand: char, + pub lane: usize, +} + +#[derive(Debug)] +pub struct Gff { + pub features: Vec, + pub row_count: usize, +} + +pub fn parse_gff(path: &Path) -> Result { + let file = File::open(path).map_err(|e| format_err!("failed to open gff file: {e}"))?; + let mut reader = gff::io::Reader::new(BufReader::new(file)); + + let mut features = Vec::new(); + + for result in reader.record_bufs() { + let record = result.map_err(|e| format_err!("failed to parse gff record: {e}"))?; + + if !is_supported_feature_type(record.ty().as_ref()) { + continue; + } + + let name = extract_name(&record); + let feature_type = record.ty().to_string(); + let start = usize::from(record.start()).saturating_sub(1); + let end = usize::from(record.end()).saturating_sub(1); + let strand = strand_char(record.strand()); + + features.push(Feature { + name, + feature_type, + start, + end, + strand, + lane: 0, + }); + } + + if features.is_empty() { + return Err(format_err!("no supported features found in gff file")); + } + + let row_count = assign_row(&mut features); + + Ok(Gff { + features, + row_count, + }) +} + +fn is_supported_feature_type(feature_type: &[u8]) -> bool { + feature_type.eq_ignore_ascii_case(b"gene") + || feature_type.eq_ignore_ascii_case(b"pseudogene") + || feature_type.eq_ignore_ascii_case(b"five_prime_UTR") + || feature_type.eq_ignore_ascii_case(b"three_prime_UTR") + || feature_type.eq_ignore_ascii_case(b"long_terminal_repeat") + || feature_type.eq_ignore_ascii_case(b"repeat_region") +} + +fn extract_name(record: &gff::feature::RecordBuf) -> String { + let attributes = record.attributes(); + for tag in &[b"Name" as &[u8], b"ID", b"gene_name", b"product"] { + if let Some(value) = attributes.get(tag) + && let Some(s) = value.as_string() + { + let text = s.to_string(); + if !text.is_empty() { + return text; + } + } + } + record.ty().to_string() +} + +fn strand_char(strand: gff::feature::record::Strand) -> char { + match strand { + gff::feature::record::Strand::Forward => '+', + gff::feature::record::Strand::Reverse => '-', + gff::feature::record::Strand::None => '.', + gff::feature::record::Strand::Unknown => '?', + } +} + +fn assign_row(features: &mut [Feature]) -> usize { + features.sort_by(|a, b| a.start.cmp(&b.start).then(b.end.cmp(&a.end))); + let mut lane_ends: Vec = Vec::new(); + + for feature in features.iter_mut() { + let mut assigned = false; + for (lane_idx, lane_end) in lane_ends.iter_mut().enumerate() { + if feature.start > *lane_end { + feature.lane = lane_idx; + *lane_end = feature.end; + assigned = true; + break; + } + } + if !assigned { + feature.lane = lane_ends.len(); + lane_ends.push(feature.end); + } + } + + lane_ends.len().max(1) +} + + + + + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Write; + + fn write_gff(content: &str) -> tempfile::NamedTempFile { + let mut file = tempfile::NamedTempFile::new().unwrap(); + file.write_all(content.as_bytes()).unwrap(); + file + } + + #[test] + fn parse_gff_extracts_supported_features_only() { + let gff = write_gff( + "##gff-version 3\n\ + chr1\t.\tgene\t1\t100\t.\t+\t.\tID=gene1;Name=gene1\n\ + chr1\t.\tCDS\t20\t80\t.\t+\t.\tID=cds1;Name=CDS1\n", + ); + let model = parse_gff(gff.path()).unwrap(); + + assert_eq!(model.features.len(), 1); + assert_eq!(model.features[0].name, "gene1"); + assert_eq!(model.features[0].feature_type, "gene"); + assert_eq!(model.features[0].start, 0); + assert_eq!(model.features[0].end, 99); + assert_eq!(model.features[0].strand, '+'); + } + + #[test] + fn assign_lanes_handles_overlapping_features() { + let gff = write_gff( + "##gff-version 3\n\ + chr1\t.\tgene\t1\t100\t.\t+\t.\tID=g1;Name=gene1\n\ + chr1\t.\tgene\t50\t150\t.\t+\t.\tID=g2;Name=gene2\n\ + chr1\t.\tgene\t120\t200\t.\t+\t.\tID=g3;Name=gene3\n", + ); + let model = parse_gff(gff.path()).unwrap(); + + assert_eq!(model.row_count, 2); + // Gene1 and Gene2 overlap, so they should be in different lanes. + let gene1 = model.features.iter().find(|f| f.name == "gene1").unwrap(); + let gene2 = model.features.iter().find(|f| f.name == "gene2").unwrap(); + assert_ne!(gene1.lane, gene2.lane); + // Gene3 starts after Gene1 ends, so it can share Gene1's lane. + let gene3 = model.features.iter().find(|f| f.name == "gene3").unwrap(); + assert_eq!(gene3.lane, gene1.lane); + } + + #[test] + fn parse_gff_falls_back_to_id_when_no_name() { + let gff = write_gff( + "##gff-version 3\n\ + chr1\t.\tgene\t1\t10\t.\t+\t.\tID=id1\n", + ); + let model = parse_gff(gff.path()).unwrap(); + + assert_eq!(model.features[0].name, "id1"); + } + + #[test] + fn parse_gff_no_supported_features_returns_error() { + let gff = write_gff( + "##gff-version 3\n\ + chr1\t.\tCDS\t1\t10\t.\t+\t.\tID=cds1\n", + ); + let result = parse_gff(gff.path()); + + assert_eq!( + result.unwrap_err().to_string(), + "no supported features found in gff file" + ); + } + + #[test] + fn parse_gff_accepts_requested_non_gene_feature_types() { + let gff = write_gff( + "##gff-version 3\n\ + chr1\t.\tpseudogene\t1\t10\t.\t+\t.\tID=ps1;Name=pseudogene1\n\ + chr1\t.\tfive_prime_UTR\t11\t20\t.\t+\t.\tID=utr5;Name=five_prime_UTR1\n\ + chr1\t.\tthree_prime_UTR\t21\t30\t.\t+\t.\tID=utr3;Name=three_prime_UTR1\n\ + chr1\t.\tlong_terminal_repeat\t31\t40\t.\t+\t.\tID=ltr;Name=long_terminal_repeat1\n\ + chr1\t.\trepeat_region\t41\t50\t.\t+\t.\tID=rep;Name=repeat_region1\n", + ); + let model = parse_gff(gff.path()).unwrap(); + + let feature_types: Vec<_> = model + .features + .iter() + .map(|feature| feature.feature_type.as_str()) + .collect(); + assert_eq!( + feature_types, + vec![ + "pseudogene", + "five_prime_UTR", + "three_prime_UTR", + "long_terminal_repeat", + "repeat_region", + ] + ); + } +} From 703f3a06cce4f2727f4b85b443daabd5202aca61 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sat, 11 Apr 2026 08:24:00 +0100 Subject: [PATCH 14/48] perf (libmsa): clean up allocations --- libmsa/src/model.rs | 1 + libmsa/src/translation.rs | 50 +++++++++++++++++++-------------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/libmsa/src/model.rs b/libmsa/src/model.rs index 60d2a12..7e45fe2 100644 --- a/libmsa/src/model.rs +++ b/libmsa/src/model.rs @@ -209,6 +209,7 @@ impl Alignment { } /// Returns an iterator over the visible rows absolute index. + #[cfg(test)] pub(crate) fn absolute_row_ids(&self) -> impl ExactSizeIterator + '_ { self.rows.iter() } diff --git a/libmsa/src/translation.rs b/libmsa/src/translation.rs index 8f0359e..d0b92bc 100644 --- a/libmsa/src/translation.rs +++ b/libmsa/src/translation.rs @@ -220,11 +220,14 @@ impl<'a> TranslatedAlignment<'a> { /// Returns any [`AlignmentError`] encountered while materialising the /// translated rows into a concrete alignment. pub fn to_alignment(&self) -> Result { - let absolute_rows = self.source.absolute_row_ids().collect::>(); - - let translated = absolute_rows - .par_iter() - .map(|&absolute_row| { + let translated = (0..self.source.rows.len()) + .into_par_iter() + .map(|relative_row| { + let absolute_row = self + .source + .rows + .absolute(relative_row) + .expect("out of bounds relative row index"); let sequence = self.source.data.sequences.get(absolute_row).ok_or( AlignmentError::RowOutOfBounds { index: absolute_row, @@ -395,26 +398,23 @@ fn translate_sequence(sequence: &[u8], frame: ReadingFrame, table: &TranslationT let translated_len = translated_length(sequence.len(), frame); let complete_codons = frame.complete_codons(sequence.len()); let complete_end = offset + (complete_codons * 3); - - let mut translated = vec![0; translated_len]; - - for (protein_col, codon) in sequence[offset..complete_end].chunks_exact(3).enumerate() { - let first = nucleotide_index(codon[0]); - let second = nucleotide_index(codon[1]); - let third = nucleotide_index(codon[2]); - - translated[protein_col] = if first == 4 || second == 4 || third == 4 { - b'X' - } else { - table.codons[first as usize][second as usize][third as usize] - }; - } - - if complete_codons < translated_len { - translated[complete_codons] = b'X'; - } - - translated + let has_incomplete_terminal_codon = complete_codons < translated_len; + + sequence[offset..complete_end] + .chunks_exact(3) + .map(|codon| { + let first = nucleotide_index(codon[0]); + let second = nucleotide_index(codon[1]); + let third = nucleotide_index(codon[2]); + + if first == 4 || second == 4 || third == 4 { + b'X' + } else { + table.codons[usize::from(first)][usize::from(second)][usize::from(third)] + } + }) + .chain(has_incomplete_terminal_codon.then_some(b'X')) + .collect() } pub(crate) fn translated_byte_at( From 4753699e5474f4bb06bdd9be1cfec300684a0067 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sat, 11 Apr 2026 09:31:00 +0100 Subject: [PATCH 15/48] feat(salti): add load-gff command wiring --- salti/src/command.rs | 1 + .../overlay/command_palette/command_definitions.rs | 14 +++++++++++--- .../src/overlay/command_palette/command_runners.rs | 7 +++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/salti/src/command.rs b/salti/src/command.rs index 9a5d21f..1a1aac4 100644 --- a/salti/src/command.rs +++ b/salti/src/command.rs @@ -36,4 +36,5 @@ pub enum Command { SetDiffMode(DiffMode), ToggleTranslationView, ReloadAsProtein { frame: Option }, + LoadGff { path: String }, } diff --git a/salti/src/overlay/command_palette/command_definitions.rs b/salti/src/overlay/command_palette/command_definitions.rs index 3e24ee9..6e448e2 100644 --- a/salti/src/overlay/command_palette/command_definitions.rs +++ b/salti/src/overlay/command_palette/command_definitions.rs @@ -1,9 +1,9 @@ use super::command_runners::{ run_check_update, run_clear_filter, run_clear_reference, run_consensus_method, run_diff_mode, run_filter_constant, run_filter_gaps, run_filter_rows, run_jump_position, run_jump_sequence, - run_load_alignment, run_pin_sequence, run_quit, run_reload_as_protein, run_set_active_type, - run_set_reference, run_theme, run_toggle_translation, run_translation_frame, - run_unpin_sequence, + run_load_alignment, run_load_gff, run_pin_sequence, run_quit, run_reload_as_protein, + run_set_active_type, run_set_reference, run_theme, run_toggle_translation, + run_translation_frame, run_unpin_sequence, }; use super::command_spec::{PaletteCommand, StaticCommand, TypableCommand}; use super::completers; @@ -177,4 +177,12 @@ pub(super) const COMMAND_SPECS: &[PaletteCommand] = &[ static_candidates: &["dna", "protein", "generic"], run: run_set_active_type, }), + PaletteCommand::Typable(TypableCommand { + name: "load-gff", + help_text: "Load a GFF annotation file to display features above the alignment.", + aliases: &[], + completer: Some(completers::filename), + static_candidates: &[], + run: run_load_gff, + }), ]; diff --git a/salti/src/overlay/command_palette/command_runners.rs b/salti/src/overlay/command_palette/command_runners.rs index 85cd81f..9e05b5a 100644 --- a/salti/src/overlay/command_palette/command_runners.rs +++ b/salti/src/overlay/command_palette/command_runners.rs @@ -321,6 +321,13 @@ pub(super) fn run_quit(_: &CommandPaletteState, arguments: &str) -> anyhow::Resu }) } +pub(super) fn run_load_gff(_: &CommandPaletteState, arguments: &str) -> anyhow::Result { + run_command("load-gff", arguments, || { + let path = require_argument(arguments)?; + Ok(Command::LoadGff { path }) + }) +} + #[cfg(test)] mod tests { use super::*; From c3f75210968b77b524ab7e8e71fe45bbf6672c1a Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sat, 11 Apr 2026 09:59:00 +0100 Subject: [PATCH 16/48] refactor(salti): split check for update into 2 commands rather than logic on bool --- salti/src/app.rs | 13 ++++++------- salti/src/command.rs | 3 ++- .../src/overlay/command_palette/command_runners.rs | 4 +--- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/salti/src/app.rs b/salti/src/app.rs index 38f4587..a03a9a5 100644 --- a/salti/src/app.rs +++ b/salti/src/app.rs @@ -110,9 +110,7 @@ impl App { self.event_tx = Some(event_tx); let mut needs_redraw = true; if Self::startup_update_check_enabled() { - self.execute_commands([Command::CheckForUpdate { - show_success_message: false, - }]); + self.execute_commands([Command::CheckForUpdate]); } else { debug!( env_var = UPDATE_CHECK_ENV_VAR, @@ -356,10 +354,11 @@ impl App { self.clear_mouse_selection(); self.start_load_job(input); } - Command::CheckForUpdate { - show_success_message, - } => { - self.spawn_update_check(show_success_message); + Command::CheckForUpdate => { + self.spawn_update_check(false); + } + Command::CheckForUpdateAndNotify => { + self.spawn_update_check(true); } Command::ScrollDown { amount } => self.ui.viewport.scroll_down(amount), diff --git a/salti/src/command.rs b/salti/src/command.rs index 1a1aac4..c17b288 100644 --- a/salti/src/command.rs +++ b/salti/src/command.rs @@ -11,7 +11,8 @@ pub enum Command { SetTheme(ThemeId), ShowNotification(Notification), LoadFile { input: String }, - CheckForUpdate { show_success_message: bool }, + CheckForUpdate, + CheckForUpdateAndNotify, ScrollDown { amount: usize }, ScrollUp { amount: usize }, ScrollLeft { amount: usize }, diff --git a/salti/src/overlay/command_palette/command_runners.rs b/salti/src/overlay/command_palette/command_runners.rs index 9e05b5a..d5fb5a9 100644 --- a/salti/src/overlay/command_palette/command_runners.rs +++ b/salti/src/overlay/command_palette/command_runners.rs @@ -308,9 +308,7 @@ pub(super) fn run_check_update( ) -> anyhow::Result { run_command("check-update", arguments, || { ensure_no_argument(arguments)?; - Ok(Command::CheckForUpdate { - show_success_message: true, - }) + Ok(Command::CheckForUpdateAndNotify) }) } From 5b801d5b4f68a9a696997dc67e274c5f64e97677 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sat, 11 Apr 2026 10:06:00 +0100 Subject: [PATCH 17/48] build(salti): add noodles-gff to deps --- Cargo.lock | 143 ++++++++++++++++++++++++++++++++++++++++++++++- salti/Cargo.toml | 1 + 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index f5de70e..b71ac31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,7 +170,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ - "bit-vec", + "bit-vec 0.6.3", ] [[package]] @@ -179,6 +179,15 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -200,6 +209,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -736,6 +755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", + "libz-rs-sys", "miniz_oxide", ] @@ -1394,6 +1414,63 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + [[package]] name = "libc" version = "0.2.181" @@ -1430,6 +1507,15 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "libz-rs-sys" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c10501e7805cee23da17c7790e59df2870c0d4043ec6d03f67d31e2b53e77415" +dependencies = [ + "zlib-rs", +] + [[package]] name = "line-clipping" version = "0.3.5" @@ -1616,6 +1702,54 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "noodles-bgzf" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37290f565045fd2775b549e62dffca7e1afadc70d8d5a3a2ef19609eb3d8193b" +dependencies = [ + "bytes", + "crossbeam-channel", + "flate2", +] + +[[package]] +name = "noodles-core" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e1e8a419dbba0e4000b0e60830b124138c7f2277ad556463506f1a81d32d17" +dependencies = [ + "bstr", +] + +[[package]] +name = "noodles-csi" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c846d8128bd80b18d891b13cb9e0bc1d364429d6ab3ec3c83939f3d32ba105" +dependencies = [ + "bit-vec 0.9.1", + "bstr", + "indexmap", + "noodles-bgzf", + "noodles-core", +] + +[[package]] +name = "noodles-gff" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76943d61e3b78feb7a248d254590aabd71a3429319fa046992f68a6e9c2e298" +dependencies = [ + "bstr", + "indexmap", + "lexical-core", + "noodles-bgzf", + "noodles-core", + "noodles-csi", + "percent-encoding", +] + [[package]] name = "ntapi" version = "0.4.3" @@ -2480,6 +2614,7 @@ dependencies = [ "human-panic", "insta", "libmsa", + "noodles-gff", "nucleo-matcher", "paraseq", "ratatui", @@ -4237,6 +4372,12 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "zlib-rs" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" + [[package]] name = "zmij" version = "1.0.20" diff --git a/salti/Cargo.toml b/salti/Cargo.toml index 300b08d..c525319 100644 --- a/salti/Cargo.toml +++ b/salti/Cargo.toml @@ -29,6 +29,7 @@ tracing = "0.1.41" tracing-appender = "0.2.3" tracing-subscriber = { version = "0.3.20", features = ["env-filter", "fmt"] } human-panic = "2" +noodles-gff = "0.56.0" [dev-dependencies] insta = "1.46.3" From c064041156de3b055ea3216cbd36160bb8bafa6f Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sun, 10 May 2026 08:57:40 +0100 Subject: [PATCH 18/48] feat(salti): make gff parsing more robust with types for features removes support for other features - only genes for now --- salti/src/core/gff.rs | 230 ++++++++++++++++++------------------------ 1 file changed, 100 insertions(+), 130 deletions(-) diff --git a/salti/src/core/gff.rs b/salti/src/core/gff.rs index 7ae604d..1d410c5 100644 --- a/salti/src/core/gff.rs +++ b/salti/src/core/gff.rs @@ -1,126 +1,133 @@ +use std::cmp::Reverse; +use std::fmt; use std::fs::File; use std::io::BufReader; +use std::ops::Range; use std::path::Path; use anyhow::{Result, format_err}; use noodles_gff as gff; -#[derive(Debug)] -pub struct Feature { - pub name: String, - pub feature_type: String, - pub start: usize, - pub end: usize, - pub strand: char, - pub lane: usize, -} - -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Gff { pub features: Vec, - pub row_count: usize, } -pub fn parse_gff(path: &Path) -> Result { - let file = File::open(path).map_err(|e| format_err!("failed to open gff file: {e}"))?; - let mut reader = gff::io::Reader::new(BufReader::new(file)); +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Feature { + pub name: String, + pub kind: FeatureType, + pub range: Range, + pub strand: Strand, +} - let mut features = Vec::new(); +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum FeatureType { + Gene, +} - for result in reader.record_bufs() { - let record = result.map_err(|e| format_err!("failed to parse gff record: {e}"))?; +impl FeatureType { + pub fn as_str(self) -> &'static str { + match self { + Self::Gene => "gene", + } + } - if !is_supported_feature_type(record.ty().as_ref()) { - continue; + fn parse(feature_type: &[u8]) -> Option { + if feature_type.eq_ignore_ascii_case(b"gene") { + return Some(Self::Gene); } - let name = extract_name(&record); - let feature_type = record.ty().to_string(); - let start = usize::from(record.start()).saturating_sub(1); - let end = usize::from(record.end()).saturating_sub(1); - let strand = strand_char(record.strand()); - - features.push(Feature { - name, - feature_type, - start, - end, - strand, - lane: 0, - }); + None } +} - if features.is_empty() { - return Err(format_err!("no supported features found in gff file")); +impl fmt::Display for FeatureType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) } - - let row_count = assign_row(&mut features); - - Ok(Gff { - features, - row_count, - }) } -fn is_supported_feature_type(feature_type: &[u8]) -> bool { - feature_type.eq_ignore_ascii_case(b"gene") - || feature_type.eq_ignore_ascii_case(b"pseudogene") - || feature_type.eq_ignore_ascii_case(b"five_prime_UTR") - || feature_type.eq_ignore_ascii_case(b"three_prime_UTR") - || feature_type.eq_ignore_ascii_case(b"long_terminal_repeat") - || feature_type.eq_ignore_ascii_case(b"repeat_region") +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Strand { + Forward, + Reverse, + Unknown, } -fn extract_name(record: &gff::feature::RecordBuf) -> String { - let attributes = record.attributes(); - for tag in &[b"Name" as &[u8], b"ID", b"gene_name", b"product"] { - if let Some(value) = attributes.get(tag) - && let Some(s) = value.as_string() - { - let text = s.to_string(); - if !text.is_empty() { - return text; - } +impl Strand { + pub fn as_str(self) -> &'static str { + match self { + Self::Forward => "Forward →", + Self::Reverse => "Reverse ←", + Self::Unknown => "Unknown strand", } } - record.ty().to_string() } -fn strand_char(strand: gff::feature::record::Strand) -> char { - match strand { - gff::feature::record::Strand::Forward => '+', - gff::feature::record::Strand::Reverse => '-', - gff::feature::record::Strand::None => '.', - gff::feature::record::Strand::Unknown => '?', +impl fmt::Display for Strand { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) } } -fn assign_row(features: &mut [Feature]) -> usize { - features.sort_by(|a, b| a.start.cmp(&b.start).then(b.end.cmp(&a.end))); - let mut lane_ends: Vec = Vec::new(); - - for feature in features.iter_mut() { - let mut assigned = false; - for (lane_idx, lane_end) in lane_ends.iter_mut().enumerate() { - if feature.start > *lane_end { - feature.lane = lane_idx; - *lane_end = feature.end; - assigned = true; - break; - } - } - if !assigned { - feature.lane = lane_ends.len(); - lane_ends.push(feature.end); +impl From for Strand { + fn from(strand: gff::feature::record::Strand) -> Self { + match strand { + gff::feature::record::Strand::Forward => Self::Forward, + gff::feature::record::Strand::Reverse => Self::Reverse, + _ => Self::Unknown, } } - - lane_ends.len().max(1) } +pub fn parse_gff(path: &Path) -> Result { + let file = File::open(path).map_err(|e| format_err!("failed to open gff file: {e}"))?; + let mut reader = gff::io::Reader::new(BufReader::new(file)); + let mut features: Vec = reader + .record_bufs() + .map(|result| { + let record = result.map_err(|e| format_err!("failed to parse gff record: {e}"))?; + let Some(kind) = FeatureType::parse(record.ty().as_ref()) else { + return Ok(None); + }; + let start = usize::from(record.start()) + .checked_sub(1) + .ok_or_else(|| format_err!("gff feature start must be one-based"))?; + let end = usize::from(record.end()); + + Ok(Some(Feature { + name: extract_name(&record), + kind, + range: start..end, + strand: record.strand().into(), + })) + }) + .filter_map(Result::transpose) + .collect::>()?; + if features.is_empty() { + return Err(format_err!("no supported features found in gff file")); + } + // GFFS are not always sorted + features.sort_by_key(|feature| (feature.range.start, Reverse(feature.range.end))); + + Ok(Gff { features }) +} + +fn extract_name(record: &gff::feature::RecordBuf) -> String { + const POSSIBLE_NAMES: [&[u8]; 4] = [b"Name", b"ID", b"gene_name", b"product"]; + + // try get names in order of preference, or falls back to record type so something is shown + POSSIBLE_NAMES + .iter() + .filter_map(|tag| record.attributes().get(*tag)) + .filter_map(|value| value.as_string()) + .find(|name| !name.is_empty()) + .map_or_else(|| record.ty().to_string(), |name| name.to_string()) +} #[cfg(test)] mod tests { @@ -144,30 +151,22 @@ mod tests { assert_eq!(model.features.len(), 1); assert_eq!(model.features[0].name, "gene1"); - assert_eq!(model.features[0].feature_type, "gene"); - assert_eq!(model.features[0].start, 0); - assert_eq!(model.features[0].end, 99); - assert_eq!(model.features[0].strand, '+'); + assert_eq!(model.features[0].kind, FeatureType::Gene); + assert_eq!(model.features[0].range, 0..100); + assert_eq!(model.features[0].strand, Strand::Forward); } #[test] - fn assign_lanes_handles_overlapping_features() { + fn parse_gff_sorts_features_by_start() { let gff = write_gff( "##gff-version 3\n\ - chr1\t.\tgene\t1\t100\t.\t+\t.\tID=g1;Name=gene1\n\ chr1\t.\tgene\t50\t150\t.\t+\t.\tID=g2;Name=gene2\n\ - chr1\t.\tgene\t120\t200\t.\t+\t.\tID=g3;Name=gene3\n", + chr1\t.\tgene\t1\t100\t.\t+\t.\tID=g1;Name=gene1\n", ); let model = parse_gff(gff.path()).unwrap(); - assert_eq!(model.row_count, 2); - // Gene1 and Gene2 overlap, so they should be in different lanes. - let gene1 = model.features.iter().find(|f| f.name == "gene1").unwrap(); - let gene2 = model.features.iter().find(|f| f.name == "gene2").unwrap(); - assert_ne!(gene1.lane, gene2.lane); - // Gene3 starts after Gene1 ends, so it can share Gene1's lane. - let gene3 = model.features.iter().find(|f| f.name == "gene3").unwrap(); - assert_eq!(gene3.lane, gene1.lane); + assert_eq!(model.features[0].name, "gene1"); + assert_eq!(model.features[1].name, "gene2"); } #[test] @@ -194,33 +193,4 @@ mod tests { "no supported features found in gff file" ); } - - #[test] - fn parse_gff_accepts_requested_non_gene_feature_types() { - let gff = write_gff( - "##gff-version 3\n\ - chr1\t.\tpseudogene\t1\t10\t.\t+\t.\tID=ps1;Name=pseudogene1\n\ - chr1\t.\tfive_prime_UTR\t11\t20\t.\t+\t.\tID=utr5;Name=five_prime_UTR1\n\ - chr1\t.\tthree_prime_UTR\t21\t30\t.\t+\t.\tID=utr3;Name=three_prime_UTR1\n\ - chr1\t.\tlong_terminal_repeat\t31\t40\t.\t+\t.\tID=ltr;Name=long_terminal_repeat1\n\ - chr1\t.\trepeat_region\t41\t50\t.\t+\t.\tID=rep;Name=repeat_region1\n", - ); - let model = parse_gff(gff.path()).unwrap(); - - let feature_types: Vec<_> = model - .features - .iter() - .map(|feature| feature.feature_type.as_str()) - .collect(); - assert_eq!( - feature_types, - vec![ - "pseudogene", - "five_prime_UTR", - "three_prime_UTR", - "long_terminal_repeat", - "repeat_region", - ] - ); - } } From ebd8a53765991eb2e8bac75d6e2bf361654423d7 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sun, 10 May 2026 08:59:29 +0100 Subject: [PATCH 19/48] style(salti): cargo fmt --- salti/src/core/parser.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/salti/src/core/parser.rs b/salti/src/core/parser.rs index 6edcdcb..101f50c 100644 --- a/salti/src/core/parser.rs +++ b/salti/src/core/parser.rs @@ -100,8 +100,8 @@ mod tests { #[test] fn parse_fasta_file_success() { - let sequences = parse_temp_fasta(">seq1\nA-CG\n>seq2\nTGCA\n", &CancellationToken::new()) - .unwrap(); + let sequences = + parse_temp_fasta(">seq1\nA-CG\n>seq2\nTGCA\n", &CancellationToken::new()).unwrap(); assert_eq!( sequences, @@ -120,24 +120,21 @@ mod tests { #[test] fn parse_fasta_file_errors_missing_input() { - let error = parse_fasta_file("idontexist.fasta", &CancellationToken::new()) - .unwrap_err(); + let error = parse_fasta_file("idontexist.fasta", &CancellationToken::new()).unwrap_err(); assert!(error.to_string().starts_with("Failed to open input:")); } #[test] fn parse_fasta_file_errors_empty_file() { - let error = parse_temp_fasta("", &CancellationToken::new()) - .unwrap_err(); + let error = parse_temp_fasta("", &CancellationToken::new()).unwrap_err(); assert!(error.to_string().starts_with("Failed to open input:")); } #[test] fn parse_fasta_file_errors_zero_length_sequences() { - let error = parse_temp_fasta(">seq1\n>seq2\n", &CancellationToken::new()) - .unwrap_err(); + let error = parse_temp_fasta(">seq1\n>seq2\n", &CancellationToken::new()).unwrap_err(); assert_eq!(error.to_string(), "Sequence has zero length for id seq1"); } @@ -155,8 +152,8 @@ mod tests { #[test] fn parse_fasta_file_errors_invalid_fasta() { - let error = parse_temp_fasta("imaninvalidfasta\nfile\n", &CancellationToken::new()) - .unwrap_err(); + let error = + parse_temp_fasta("imaninvalidfasta\nfile\n", &CancellationToken::new()).unwrap_err(); let message = error.to_string(); assert!( From ab153a3f13ef35caca474090ea4a0ff715106038 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sun, 10 May 2026 13:50:54 +0100 Subject: [PATCH 20/48] feat(salti): add generic movement function in input and move minimap to use it Future gff pane can now re-use same function --- salti/src/input/mod.rs | 1 + salti/src/input/movement.rs | 59 ++++++++++++++++++++++++++ salti/src/overlay/minimap.rs | 81 +++++++----------------------------- 3 files changed, 74 insertions(+), 67 deletions(-) create mode 100644 salti/src/input/movement.rs diff --git a/salti/src/input/mod.rs b/salti/src/input/mod.rs index 6aefa1c..f0f5dc8 100644 --- a/salti/src/input/mod.rs +++ b/salti/src/input/mod.rs @@ -1,5 +1,6 @@ mod key; mod mouse; +pub(crate) mod movement; mod route; pub(crate) use key::handle_key_event; diff --git a/salti/src/input/movement.rs b/salti/src/input/movement.rs new file mode 100644 index 0000000..0f41199 --- /dev/null +++ b/salti/src/input/movement.rs @@ -0,0 +1,59 @@ +use std::ops::Range; + +use crossterm::event::{MouseButton, MouseEvent, MouseEventKind}; +use ratatui::layout::Rect; + +use crate::command::Command; + +#[derive(Debug, Clone, Copy, Default)] +pub(crate) struct HorizontalDrag { + anchor: Option, +} + +impl HorizontalDrag { + pub(crate) fn is_dragging(&self) -> bool { + self.anchor.is_some() + } + + pub(crate) fn handle_mouse( + &mut self, + mouse: MouseEvent, + area: Rect, + viewport_col_range: &Range, + total_columns: usize, + position_from_mouse: impl Fn(u16, Rect, usize) -> usize, + ) -> Option { + let viewport_span = viewport_col_range.len(); + let in_area = area.contains((mouse.column, mouse.row).into()); + + let (anchor, column) = match mouse.kind { + MouseEventKind::Down(MouseButton::Left) if in_area => { + let column = position_from_mouse(mouse.column, area, total_columns); + let anchor = if viewport_col_range.contains(&column) { + column - viewport_col_range.start + } else { + viewport_span / 2 + }; + self.anchor = Some(anchor); + (anchor, column) + } + MouseEventKind::Drag(MouseButton::Left) => { + let anchor = self.anchor?; + let column = position_from_mouse(mouse.column, area, total_columns); + (anchor, column) + } + MouseEventKind::Up(MouseButton::Left) => { + let anchor = self.anchor.take()?; + if !in_area { + return None; + } + let column = position_from_mouse(mouse.column, area, total_columns); + (anchor, column) + } + _ => return None, + }; + + let visible_target = column.saturating_sub(anchor); + Some(Command::JumpToPosition(visible_target)) + } +} diff --git a/salti/src/overlay/minimap.rs b/salti/src/overlay/minimap.rs index bbc98c2..b71e72f 100644 --- a/salti/src/overlay/minimap.rs +++ b/salti/src/overlay/minimap.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use crossterm::event::{MouseButton, MouseEvent, MouseEventKind}; +use crossterm::event::MouseEvent; use ratatui::Frame; use ratatui::layout::Rect; use ratatui::style::Color; @@ -10,6 +10,7 @@ use ratatui::widgets::{Block, Clear, Paragraph, Widget}; use crate::command::Command; use crate::config::theme::Theme; use crate::core::model::AlignmentModel; +use crate::input::movement::HorizontalDrag; use crate::ui::ui_state::UiState; /// maximum height of the minimap in rows @@ -29,12 +30,12 @@ pub struct MinimapLayout { #[derive(Debug, Clone, Copy, Default)] pub struct MinimapState { - anchor_columns: Option, + pan_drag: HorizontalDrag, } impl MinimapState { pub fn is_dragging(&self) -> bool { - self.anchor_columns.is_some() + self.pan_drag.is_dragging() } pub fn contains_mouse(&self, mouse: MouseEvent, overlay_area: Rect) -> bool { @@ -43,21 +44,10 @@ impl MinimapState { } fn position_from_mouse(mouse_x: u16, track_area: Rect, total_columns: usize) -> usize { - let offset = usize::from(mouse_x - track_area.x); + let offset = usize::from(mouse_x.saturating_sub(track_area.x)); let width = usize::from(track_area.width); - let column = offset * total_columns / width; - column.min(total_columns - 1) - } - - fn pan_action( - mouse_x: u16, - track_area: Rect, - total_columns: usize, - drag_anchor: usize, - ) -> Command { - let column = Self::position_from_mouse(mouse_x, track_area, total_columns); - let visible_target = column.saturating_sub(drag_anchor); - Command::JumpToPosition(visible_target) + let column = offset.saturating_mul(total_columns) / width; + column.min(total_columns.saturating_sub(1)) } pub fn handle_mouse( @@ -67,57 +57,14 @@ impl MinimapState { viewport_column_range: &Range, total_columns: usize, ) -> Option { - if total_columns == 0 { - return None; - } - - let viewport_cols = viewport_column_range - .end - .saturating_sub(viewport_column_range.start); let track_area = layout(overlay_area).track_area; - let in_track = self.contains_mouse(mouse, overlay_area); - - match mouse.kind { - MouseEventKind::Down(MouseButton::Left) if in_track => { - let column = Self::position_from_mouse(mouse.column, track_area, total_columns); - let drag_anchor = if viewport_column_range.contains(&column) { - column - viewport_column_range.start - } else { - viewport_cols / 2 - }; - - self.anchor_columns = Some(drag_anchor); - Some(Self::pan_action( - mouse.column, - track_area, - total_columns, - drag_anchor, - )) - } - MouseEventKind::Drag(MouseButton::Left) if in_track => { - let drag_anchor = self.anchor_columns?; - Some(Self::pan_action( - mouse.column, - track_area, - total_columns, - drag_anchor, - )) - } - MouseEventKind::Up(MouseButton::Left) => { - let drag_anchor = self.anchor_columns.take()?; - if in_track { - Some(Self::pan_action( - mouse.column, - track_area, - total_columns, - drag_anchor, - )) - } else { - None - } - } - _ => None, - } + self.pan_drag.handle_mouse( + mouse, + track_area, + viewport_column_range, + total_columns, + Self::position_from_mouse, + ) } } From aebf908f821e4df0d87ee60abfdceb7efd35a016 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sun, 10 May 2026 16:01:15 +0100 Subject: [PATCH 21/48] refactor(salti): impl widget for minimap --- salti/src/overlay/minimap.rs | 100 +++++++++++++++++++---------------- salti/src/overlay/render.rs | 4 +- 2 files changed, 55 insertions(+), 49 deletions(-) diff --git a/salti/src/overlay/minimap.rs b/salti/src/overlay/minimap.rs index b71e72f..8d829f3 100644 --- a/salti/src/overlay/minimap.rs +++ b/salti/src/overlay/minimap.rs @@ -1,7 +1,7 @@ use std::ops::Range; use crossterm::event::MouseEvent; -use ratatui::Frame; +use ratatui::buffer::Buffer; use ratatui::layout::Rect; use ratatui::style::Color; use ratatui::text::{Line, Span}; @@ -28,6 +28,56 @@ pub struct MinimapLayout { pub track_area: Rect, } +pub struct Minimap<'a> { + input_area: Rect, + alignment: &'a AlignmentModel, + ui: &'a UiState, +} + +impl<'a> Minimap<'a> { + pub fn new(input_area: Rect, alignment: &'a AlignmentModel, ui: &'a UiState) -> Self { + Self { + input_area, + alignment, + ui, + } + } +} + +impl Widget for Minimap<'_> { + fn render(self, area: Rect, buffer: &mut Buffer) { + let minimap_layout = layout(area); + let theme = &self.ui.theme.theme; + let styles = &self.ui.theme.styles; + let total_columns = self.alignment.view().column_count(); + + Clear.render(minimap_layout.area, buffer); + Block::bordered() + .border_style(styles.border) + .style(styles.panel_block) + .render(minimap_layout.area, buffer); + render_minimap_track( + buffer, + minimap_layout.track_area, + self.alignment, + theme, + total_columns, + ); + + if let Some(viewport_box) = highlight_box( + minimap_layout.track_area, + self.ui.viewport.window().col_range, + total_columns, + ) { + shade_highlight_box(buffer, viewport_box, theme); + } + + Paragraph::new(Line::from(Span::styled("Drag to pan", styles.text_dim))) + .style(styles.base_block) + .render(self.input_area, buffer); + } +} + #[derive(Debug, Clone, Copy, Default)] pub struct MinimapState { pan_drag: HorizontalDrag, @@ -119,8 +169,7 @@ fn calculate_block_colour( .unwrap_or(theme.panel_bg_dim) } -fn shade_highlight_box(f: &mut Frame, viewport_box: Rect, theme: &Theme) { - let buffer = f.buffer_mut(); +fn shade_highlight_box(buffer: &mut Buffer, viewport_box: Rect, theme: &Theme) { for position in viewport_box.positions() { if let Some(cell) = buffer.cell_mut(position) { cell.set_char('▒'); @@ -150,14 +199,13 @@ pub fn highlight_box(track_area: Rect, window: Range, total_columns: usiz } fn render_minimap_track( - f: &mut Frame, + buffer: &mut Buffer, area: Rect, alignment: &AlignmentModel, theme: &Theme, total_columns: usize, ) { let total_width = usize::from(area.width); - let buffer = f.buffer_mut(); // render empty block if alignment is empty if total_columns == 0 { @@ -195,45 +243,3 @@ pub fn layout(overlay_area: Rect) -> MinimapLayout { let track_area = Block::bordered().inner(area); MinimapLayout { area, track_area } } - -pub fn render( - f: &mut Frame, - overlay_area: Rect, - input_area: Rect, - alignment: &AlignmentModel, - ui: &UiState, -) { - let minimap_layout = layout(overlay_area); - let theme = &ui.theme.theme; - let styles = &ui.theme.styles; - let total_columns = alignment.view().column_count(); - - Clear.render(minimap_layout.area, f.buffer_mut()); - f.render_widget( - Block::bordered() - .border_style(styles.border) - .style(styles.panel_block), - minimap_layout.area, - ); - render_minimap_track( - f, - minimap_layout.track_area, - alignment, - theme, - total_columns, - ); - - if let Some(viewport_box) = highlight_box( - minimap_layout.track_area, - ui.viewport.window().col_range, - total_columns, - ) { - shade_highlight_box(f, viewport_box, theme); - } - - f.render_widget( - Paragraph::new(Line::from(Span::styled("Drag to pan", styles.text_dim))) - .style(styles.base_block), - input_area, - ); -} diff --git a/salti/src/overlay/render.rs b/salti/src/overlay/render.rs index 39a6b96..3ae8a30 100644 --- a/salti/src/overlay/render.rs +++ b/salti/src/overlay/render.rs @@ -5,7 +5,7 @@ use ratatui::Frame; use ratatui::layout::Rect; use ratatui::widgets::Block; -use super::minimap; +use super::minimap::Minimap; use super::overlay_state::ActiveOverlay; pub fn render_overlays( @@ -18,7 +18,7 @@ pub fn render_overlays( match &ui.overlay.active_overlay { Some(ActiveOverlay::Minimap(_)) => { if let Some(alignment) = alignment { - minimap::render(f, content_area, input_area, alignment, ui); + f.render_widget(Minimap::new(input_area, alignment, ui), content_area); } } Some(ActiveOverlay::Palette(palette)) => { From 43499e1bec943fc802e1da3c8273364ce98563d6 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Sun, 10 May 2026 17:46:22 +0100 Subject: [PATCH 22/48] refactor(salti): rename overlays into layers and create a panes module --- salti/src/command.rs | 2 +- salti/src/input/key.rs | 10 +- salti/src/main.rs | 1 - salti/src/overlay/mod.rs | 4 - salti/src/overlay/overlay_state.rs | 30 --- salti/src/{overlay => ui/layers}/minimap.rs | 0 salti/src/ui/layers/mod.rs | 5 + salti/src/ui/{ => layers}/notification.rs | 0 .../layers/palette}/command_definitions.rs | 2 +- .../layers/palette}/command_runners.rs | 0 .../layers/palette}/command_spec.rs | 0 .../layers/palette}/completers.rs | 0 .../layers/palette}/input.rs | 2 +- .../layers/palette}/mod.rs | 0 .../layers/palette}/ui.rs | 0 .../layers/palette}/utils.rs | 0 salti/src/{overlay => ui/layers}/render.rs | 15 +- salti/src/ui/layers/state.rs | 30 +++ salti/src/ui/mod.rs | 8 +- .../{alignment_pane.rs => panes/alignment.rs} | 13 +- .../{consensus_pane.rs => panes/consensus.rs} | 4 +- .../sequence_id.rs} | 5 +- ...ignment__tests__alignment_pane_basic.snap} | 0 ...lignment_pane_dense_fragmented_ruler.snap} | 0 ...alignment_pane_pinned_and_fragmented.snap} | 0 ...ent_pane_pinned_with_vertical_scroll.snap} | 0 ...s__alignment_pane_raw_diff_consensus.snap} | 0 ...ment_pane_raw_diff_consensus_loading.snap} | 0 ...s__alignment_pane_raw_diff_reference.snap} | 0 ...raw_diff_reference_without_reference.snap} | 0 ...ignment_pane_scrolled_with_scrollbar.snap} | 0 ...nt__tests__alignment_pane_translated.snap} | 0 ...nment_pane_translated_diff_reference.snap} | 0 ...us_pane_generic_without_conservation.snap} | 0 ...consensus__tests__consensus_pane_raw.snap} | 0 ...s__tests__consensus_pane_raw_loading.snap} | 0 ...sts__consensus_pane_raw_no_reference.snap} | 0 ...us__tests__consensus_pane_translated.snap} | 0 ...s__consensus_pane_translated_loading.snap} | 0 ...nsensus_pane_translated_no_reference.snap} | 0 ...ce_id__tests__sequence_id_pane_basic.snap} | 0 ..._tests__sequence_id_pane_name_scroll.snap} | 0 ...e_id__tests__sequence_id_pane_pinned.snap} | 0 salti/src/ui/selection.rs | 194 +++++++++++++++++- ...render__tests__render_command_palette.snap | 13 +- salti/src/ui/{frame.rs => status_bars.rs} | 36 ++-- 46 files changed, 285 insertions(+), 89 deletions(-) delete mode 100644 salti/src/overlay/mod.rs delete mode 100644 salti/src/overlay/overlay_state.rs rename salti/src/{overlay => ui/layers}/minimap.rs (100%) create mode 100644 salti/src/ui/layers/mod.rs rename salti/src/ui/{ => layers}/notification.rs (100%) rename salti/src/{overlay/command_palette => ui/layers/palette}/command_definitions.rs (99%) rename salti/src/{overlay/command_palette => ui/layers/palette}/command_runners.rs (100%) rename salti/src/{overlay/command_palette => ui/layers/palette}/command_spec.rs (100%) rename salti/src/{overlay/command_palette => ui/layers/palette}/completers.rs (100%) rename salti/src/{overlay/command_palette => ui/layers/palette}/input.rs (99%) rename salti/src/{overlay/command_palette => ui/layers/palette}/mod.rs (100%) rename salti/src/{overlay/command_palette => ui/layers/palette}/ui.rs (100%) rename salti/src/{overlay/command_palette => ui/layers/palette}/utils.rs (100%) rename salti/src/{overlay => ui/layers}/render.rs (74%) create mode 100644 salti/src/ui/layers/state.rs rename salti/src/ui/{alignment_pane.rs => panes/alignment.rs} (98%) rename salti/src/ui/{consensus_pane.rs => panes/consensus.rs} (99%) rename salti/src/ui/{sequence_id_pane.rs => panes/sequence_id.rs} (98%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_basic.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_basic.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_dense_fragmented_ruler.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_dense_fragmented_ruler.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_and_fragmented.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_and_fragmented.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_with_vertical_scroll.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_with_vertical_scroll.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus_loading.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus_loading.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference_without_reference.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference_without_reference.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_scrolled_with_scrollbar.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_scrolled_with_scrollbar.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated_diff_reference.snap => panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated_diff_reference.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__consensus_pane__tests__consensus_pane_generic_without_conservation.snap => panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_generic_without_conservation.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw.snap => panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_loading.snap => panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_loading.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_no_reference.snap => panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_no_reference.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated.snap => panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_loading.snap => panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_loading.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_no_reference.snap => panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_no_reference.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_basic.snap => panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_basic.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_name_scroll.snap => panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_name_scroll.snap} (100%) rename salti/src/ui/{snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_pinned.snap => panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_pinned.snap} (100%) rename salti/src/ui/{frame.rs => status_bars.rs} (92%) diff --git a/salti/src/command.rs b/salti/src/command.rs index c17b288..5312046 100644 --- a/salti/src/command.rs +++ b/salti/src/command.rs @@ -1,6 +1,6 @@ use crate::config::theme::ThemeId; use crate::core::model::DiffMode; -use crate::ui::notification::Notification; +use crate::ui::layers::notification::Notification; #[derive(Debug, Clone, PartialEq)] pub enum Command { diff --git a/salti/src/input/key.rs b/salti/src/input/key.rs index 3c74ae8..341a98e 100644 --- a/salti/src/input/key.rs +++ b/salti/src/input/key.rs @@ -3,13 +3,13 @@ use crossterm::event::KeyEvent; use crate::command::Command; use crate::config::keybindings; use crate::input::route::{KeyRoute, route_key}; -use crate::overlay::overlay_state::ActiveOverlay; +use crate::ui::layers::state::ActiveLayer; use crate::ui::ui_state::UiState; pub(crate) fn handle_key_event(ui: &mut UiState, key: KeyEvent) -> Vec { match route_key(ui) { - KeyRoute::Palette => match ui.overlay.active_overlay.as_mut() { - Some(ActiveOverlay::Palette(palette)) => palette.handle_key_event(key), + KeyRoute::Palette => match ui.layers.active.as_mut() { + Some(ActiveLayer::Palette(palette)) => palette.handle_key_event(key), _ => Vec::new(), }, KeyRoute::Global => match keybindings::lookup(key.code, key.modifiers) { @@ -25,7 +25,7 @@ mod tests { use super::*; use crate::cli::StartupState; - use crate::overlay::command_palette::CommandPaletteState; + use crate::ui::layers::palette::CommandPaletteState; fn ui_state() -> UiState { UiState::new(StartupState { @@ -46,7 +46,7 @@ mod tests { #[test] fn palette_keys_are_routed_to_palette_state() { let mut ui = ui_state(); - ui.overlay.open_palette(CommandPaletteState::empty()); + ui.layers.open_palette(CommandPaletteState::empty()); let commands = handle_key_event(&mut ui, KeyEvent::from(KeyCode::Esc)); diff --git a/salti/src/main.rs b/salti/src/main.rs index 658e2e4..a7855d2 100644 --- a/salti/src/main.rs +++ b/salti/src/main.rs @@ -5,7 +5,6 @@ mod config; mod core; mod input; mod logging; -mod overlay; mod ui; mod update; diff --git a/salti/src/overlay/mod.rs b/salti/src/overlay/mod.rs deleted file mode 100644 index e132e5f..0000000 --- a/salti/src/overlay/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub(crate) mod command_palette; -pub(crate) mod minimap; -pub(crate) mod overlay_state; -pub(crate) mod render; diff --git a/salti/src/overlay/overlay_state.rs b/salti/src/overlay/overlay_state.rs deleted file mode 100644 index a3d091d..0000000 --- a/salti/src/overlay/overlay_state.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::command_palette::CommandPaletteState; -use super::minimap::MinimapState; - -#[derive(Debug)] -pub enum ActiveOverlay { - Palette(Box), - Minimap(MinimapState), -} - -#[derive(Debug, Default)] -pub struct OverlayState { - pub active_overlay: Option, -} - -impl OverlayState { - pub fn open_palette(&mut self, palette: CommandPaletteState) { - self.active_overlay = Some(ActiveOverlay::Palette(Box::new(palette))); - } - - pub fn toggle_minimap(&mut self) { - self.active_overlay = match self.active_overlay.take() { - Some(ActiveOverlay::Minimap(_)) => None, - _ => Some(ActiveOverlay::Minimap(MinimapState::default())), - }; - } - - pub fn close(&mut self) { - self.active_overlay = None; - } -} diff --git a/salti/src/overlay/minimap.rs b/salti/src/ui/layers/minimap.rs similarity index 100% rename from salti/src/overlay/minimap.rs rename to salti/src/ui/layers/minimap.rs diff --git a/salti/src/ui/layers/mod.rs b/salti/src/ui/layers/mod.rs new file mode 100644 index 0000000..ed22c7b --- /dev/null +++ b/salti/src/ui/layers/mod.rs @@ -0,0 +1,5 @@ +pub(crate) mod minimap; +pub(crate) mod notification; +pub(crate) mod palette; +pub(crate) mod render; +pub(crate) mod state; diff --git a/salti/src/ui/notification.rs b/salti/src/ui/layers/notification.rs similarity index 100% rename from salti/src/ui/notification.rs rename to salti/src/ui/layers/notification.rs diff --git a/salti/src/overlay/command_palette/command_definitions.rs b/salti/src/ui/layers/palette/command_definitions.rs similarity index 99% rename from salti/src/overlay/command_palette/command_definitions.rs rename to salti/src/ui/layers/palette/command_definitions.rs index 6e448e2..c3516d4 100644 --- a/salti/src/overlay/command_palette/command_definitions.rs +++ b/salti/src/ui/layers/palette/command_definitions.rs @@ -20,7 +20,7 @@ use super::completers; /// - `completer`: a function that provides autocompletion suggestions for the command's argument /// These are only used for typable commands. /// - `run`: the function that is called to execute the command. These are defined in -/// `overlay/command_palette/command_runners` +/// `ui/layers/palette/command_runners` pub(super) const COMMAND_SPECS: &[PaletteCommand] = &[ PaletteCommand::Typable(TypableCommand { name: "jump-position", diff --git a/salti/src/overlay/command_palette/command_runners.rs b/salti/src/ui/layers/palette/command_runners.rs similarity index 100% rename from salti/src/overlay/command_palette/command_runners.rs rename to salti/src/ui/layers/palette/command_runners.rs diff --git a/salti/src/overlay/command_palette/command_spec.rs b/salti/src/ui/layers/palette/command_spec.rs similarity index 100% rename from salti/src/overlay/command_palette/command_spec.rs rename to salti/src/ui/layers/palette/command_spec.rs diff --git a/salti/src/overlay/command_palette/completers.rs b/salti/src/ui/layers/palette/completers.rs similarity index 100% rename from salti/src/overlay/command_palette/completers.rs rename to salti/src/ui/layers/palette/completers.rs diff --git a/salti/src/overlay/command_palette/input.rs b/salti/src/ui/layers/palette/input.rs similarity index 99% rename from salti/src/overlay/command_palette/input.rs rename to salti/src/ui/layers/palette/input.rs index 7586946..21f7279 100644 --- a/salti/src/overlay/command_palette/input.rs +++ b/salti/src/ui/layers/palette/input.rs @@ -7,7 +7,7 @@ use libmsa::AlignmentType; use crate::command::Command; use crate::core::model::AlignmentModel; use crate::core::search::{Direction, FilterMode, SearchableList}; -use crate::ui::notification::{Notification, NotificationLevel}; +use crate::ui::layers::notification::{Notification, NotificationLevel}; use super::command_definitions::COMMAND_SPECS; use super::command_spec::{PaletteCommand, TypableCommand}; diff --git a/salti/src/overlay/command_palette/mod.rs b/salti/src/ui/layers/palette/mod.rs similarity index 100% rename from salti/src/overlay/command_palette/mod.rs rename to salti/src/ui/layers/palette/mod.rs diff --git a/salti/src/overlay/command_palette/ui.rs b/salti/src/ui/layers/palette/ui.rs similarity index 100% rename from salti/src/overlay/command_palette/ui.rs rename to salti/src/ui/layers/palette/ui.rs diff --git a/salti/src/overlay/command_palette/utils.rs b/salti/src/ui/layers/palette/utils.rs similarity index 100% rename from salti/src/overlay/command_palette/utils.rs rename to salti/src/ui/layers/palette/utils.rs diff --git a/salti/src/overlay/render.rs b/salti/src/ui/layers/render.rs similarity index 74% rename from salti/src/overlay/render.rs rename to salti/src/ui/layers/render.rs index 3ae8a30..2585b1b 100644 --- a/salti/src/overlay/render.rs +++ b/salti/src/ui/layers/render.rs @@ -1,13 +1,12 @@ use crate::core::model::AlignmentModel; -use crate::ui::notification::render_notification; +use crate::ui::layers::minimap::Minimap; +use crate::ui::layers::notification::render_notification; +use crate::ui::layers::state::ActiveLayer; use crate::ui::ui_state::UiState; use ratatui::Frame; use ratatui::layout::Rect; use ratatui::widgets::Block; -use super::minimap::Minimap; -use super::overlay_state::ActiveOverlay; - pub fn render_overlays( f: &mut Frame, content_area: Rect, @@ -15,19 +14,19 @@ pub fn render_overlays( alignment: Option<&AlignmentModel>, ui: &UiState, ) { - match &ui.overlay.active_overlay { - Some(ActiveOverlay::Minimap(_)) => { + match &ui.layers.active { + Some(ActiveLayer::Minimap(_)) => { if let Some(alignment) = alignment { f.render_widget(Minimap::new(input_area, alignment, ui), content_area); } } - Some(ActiveOverlay::Palette(palette)) => { + Some(ActiveLayer::Palette(palette)) => { palette.render(f, content_area, input_area, &ui.theme.styles); } None => (), } - if ui.overlay.active_overlay.is_none() { + if ui.layers.active.is_none() { match ui.notification.as_ref() { Some(notification) => { render_notification(f, input_area, notification, &ui.theme.styles); diff --git a/salti/src/ui/layers/state.rs b/salti/src/ui/layers/state.rs new file mode 100644 index 0000000..7b4c4d6 --- /dev/null +++ b/salti/src/ui/layers/state.rs @@ -0,0 +1,30 @@ +use crate::ui::layers::minimap::MinimapState; +use crate::ui::layers::palette::CommandPaletteState; + +#[derive(Debug)] +pub enum ActiveLayer { + Palette(Box), + Minimap(MinimapState), +} + +#[derive(Debug, Default)] +pub struct LayerState { + pub active: Option, +} + +impl LayerState { + pub fn open_palette(&mut self, palette: CommandPaletteState) { + self.active = Some(ActiveLayer::Palette(Box::new(palette))); + } + + pub fn toggle_minimap(&mut self) { + self.active = match self.active.take() { + Some(ActiveLayer::Minimap(_)) => None, + _ => Some(ActiveLayer::Minimap(MinimapState::default())), + }; + } + + pub fn close_active(&mut self) { + self.active = None; + } +} diff --git a/salti/src/ui/mod.rs b/salti/src/ui/mod.rs index 84a59d2..5a2481f 100644 --- a/salti/src/ui/mod.rs +++ b/salti/src/ui/mod.rs @@ -1,11 +1,9 @@ -pub(crate) mod alignment_pane; -pub(crate) mod consensus_pane; -pub(crate) mod frame; +pub(crate) mod status_bars; +pub(crate) mod layers; pub(crate) mod layout; -pub(crate) mod notification; +pub(crate) mod panes; pub(crate) mod render; pub(crate) mod rows; pub(crate) mod selection; -pub(crate) mod sequence_id_pane; pub(crate) mod ui_state; pub(crate) mod utils; diff --git a/salti/src/ui/alignment_pane.rs b/salti/src/ui/panes/alignment.rs similarity index 98% rename from salti/src/ui/alignment_pane.rs rename to salti/src/ui/panes/alignment.rs index 4e6da85..257f08d 100644 --- a/salti/src/ui/alignment_pane.rs +++ b/salti/src/ui/panes/alignment.rs @@ -505,7 +505,6 @@ pub fn render_alignment_pane( theme: &ThemeState, ) { let block = Block::bordered() - .title(Line::from("Alignment".set_style(theme.styles.accent))) .border_style(theme.styles.border) .style(theme.styles.base_block) .merge_borders(MergeStrategy::Exact); @@ -532,9 +531,9 @@ mod tests { use super::*; use crate::core::model::StatsView; use crate::core::stats_cache::StatsJobResult; + use ratatui::Terminal; use ratatui::backend::TestBackend; use ratatui::buffer::Buffer; - use ratatui::Terminal; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -593,7 +592,7 @@ mod tests { ) -> String { let backend = TestBackend::new(area.width, area.height); let mut terminal = Terminal::new(backend).unwrap(); - let layout = AppLayout::new(area); + let layout = AppLayout::new(area, 0); let mut viewport = Viewport::default(); viewport.update_dimensions( layout.alignment_pane_sequence_rows.width as usize, @@ -701,7 +700,9 @@ mod tests { raw("seq2", b"CATCATCATCATCATCAT"), raw("seq3", b"CATCATCATCATCATCAT"), ]); - alignment.set_translation(Some(libmsa::ReadingFrame::Frame1)).unwrap(); + alignment + .set_translation(Some(libmsa::ReadingFrame::Frame1)) + .unwrap(); insta::assert_snapshot!( "alignment_pane_translated", @@ -745,7 +746,9 @@ mod tests { raw("seq3", b"CATCATCATCATGATCAT"), ]); alignment.set_reference(0).unwrap(); - alignment.set_translation(Some(libmsa::ReadingFrame::Frame1)).unwrap(); + alignment + .set_translation(Some(libmsa::ReadingFrame::Frame1)) + .unwrap(); alignment.diff_mode = DiffMode::Reference; insta::assert_snapshot!( diff --git a/salti/src/ui/consensus_pane.rs b/salti/src/ui/panes/consensus.rs similarity index 99% rename from salti/src/ui/consensus_pane.rs rename to salti/src/ui/panes/consensus.rs index b259d2b..2fd96a3 100644 --- a/salti/src/ui/consensus_pane.rs +++ b/salti/src/ui/panes/consensus.rs @@ -300,10 +300,10 @@ mod tests { use super::*; use crate::core::model::StatsView; use crate::core::stats_cache::StatsJobResult; + use ratatui::Terminal; use ratatui::backend::TestBackend; use ratatui::buffer::Buffer; use ratatui::layout::Rect; - use ratatui::Terminal; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -360,7 +360,7 @@ mod tests { ) -> String { let backend = TestBackend::new(area.width, area.height); let mut terminal = Terminal::new(backend).unwrap(); - let layout = AppLayout::new(area); + let layout = AppLayout::new(area, 0); let window = ViewportWindow { row_range: 0..alignment.view().row_count(), col_range: 0..alignment.view().column_count(), diff --git a/salti/src/ui/sequence_id_pane.rs b/salti/src/ui/panes/sequence_id.rs similarity index 98% rename from salti/src/ui/sequence_id_pane.rs rename to salti/src/ui/panes/sequence_id.rs index 5a50a59..3807cb7 100644 --- a/salti/src/ui/sequence_id_pane.rs +++ b/salti/src/ui/panes/sequence_id.rs @@ -119,7 +119,6 @@ pub fn render_sequence_id_pane( theme: &ThemeState, ) { let block = Block::bordered() - .title(Line::from("Sequence Name".set_style(theme.styles.accent))) .border_style(theme.styles.border) .style(theme.styles.base_block) .merge_borders(MergeStrategy::Exact); @@ -132,10 +131,10 @@ pub fn render_sequence_id_pane( #[cfg(test)] mod tests { use super::*; + use ratatui::Terminal; use ratatui::backend::TestBackend; use ratatui::buffer::Buffer; use ratatui::layout::Rect; - use ratatui::Terminal; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -153,7 +152,7 @@ mod tests { let area = Rect::new(0, 0, 150, 12); let backend = TestBackend::new(area.width, area.height); let mut terminal = Terminal::new(backend).unwrap(); - let layout = AppLayout::new(area); + let layout = AppLayout::new(area, 0); terminal .draw(|frame| { diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_basic.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_basic.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_basic.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_basic.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_dense_fragmented_ruler.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_dense_fragmented_ruler.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_dense_fragmented_ruler.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_dense_fragmented_ruler.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_and_fragmented.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_and_fragmented.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_and_fragmented.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_and_fragmented.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_with_vertical_scroll.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_with_vertical_scroll.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_pinned_with_vertical_scroll.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_with_vertical_scroll.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus_loading.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus_loading.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_consensus_loading.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus_loading.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference_without_reference.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference_without_reference.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_raw_diff_reference_without_reference.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference_without_reference.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_scrolled_with_scrollbar.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_scrolled_with_scrollbar.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_scrolled_with_scrollbar.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_scrolled_with_scrollbar.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated.snap diff --git a/salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated_diff_reference.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated_diff_reference.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__alignment_pane__tests__alignment_pane_translated_diff_reference.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated_diff_reference.snap diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_generic_without_conservation.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_generic_without_conservation.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_generic_without_conservation.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_generic_without_conservation.snap diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw.snap diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_loading.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_loading.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_loading.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_loading.snap diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_no_reference.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_no_reference.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_raw_no_reference.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_no_reference.snap diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated.snap diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_loading.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_loading.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_loading.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_loading.snap diff --git a/salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_no_reference.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_no_reference.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__consensus_pane__tests__consensus_pane_translated_no_reference.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_no_reference.snap diff --git a/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_basic.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_basic.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_basic.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_basic.snap diff --git a/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_name_scroll.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_name_scroll.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_name_scroll.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_name_scroll.snap diff --git a/salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_pinned.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_pinned.snap similarity index 100% rename from salti/src/ui/snapshots/salti__ui__sequence_id_pane__tests__sequence_id_pane_pinned.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_pinned.snap diff --git a/salti/src/ui/selection.rs b/salti/src/ui/selection.rs index 8c55478..d88714f 100644 --- a/salti/src/ui/selection.rs +++ b/salti/src/ui/selection.rs @@ -1,12 +1,22 @@ use std::ops::Range; +use ratatui::Frame; use ratatui::layout::Rect; +use ratatui::style::Color::Rgb; +use ratatui::widgets::Block; use crate::{ core::{Viewport, codon::TranslationOverlay, model::AlignmentModel}, - ui::{layout::pinned_section_layout, ui_state::MouseSelection}, + ui::{ + layout::{AppLayout, RULER_HEIGHT_ROWS, pinned_section_layout}, + ui_state::{MouseSelection, UiState}, + }, }; +const SELECTION_ROW_HIGHLIGHT_ALPHA: f32 = 0.3; +const SELECTION_ROW_TINT_ALPHA: f32 = 0.22; +const SELECTION_COL_HIGHLIGHT_ALPHA: f32 = 0.28; + /// Maps a screen-space mouse position to `(absolute_row, absolute_column)`. /// /// Returns `None` when the click falls outside `sequence_rows_area`, on the @@ -57,6 +67,132 @@ pub fn selection_row_bounds(selection: MouseSelection) -> (usize, usize) { (start.min(end), start.max(end)) } +pub fn render_mouse_selection( + f: &mut Frame, + layout: &AppLayout, + alignment: &AlignmentModel, + ui: &UiState, + viewport: &Viewport, +) { + let Some(selection) = ui.selection else { + return; + }; + + let window = viewport.window(); + let id_inner_area = Block::bordered().inner(layout.sequence_id_pane); + let sequence_rows_area = layout.alignment_pane_sequence_rows; + let id_content_y = id_inner_area.y + RULER_HEIGHT_ROWS; + let id_end_x = id_inner_area.x.saturating_add(id_inner_area.width); + let sequence_end_x = sequence_rows_area + .x + .saturating_add(sequence_rows_area.width); + let band_layout = pinned_section_layout( + alignment.rows().pinned().len(), + sequence_rows_area.height as usize, + ); + let (row_min, row_max) = selection_row_bounds(selection); + + for (row_offset, &absolute_row) in alignment + .rows() + .pinned() + .iter() + .take(band_layout.pinned_rendered) + .enumerate() + { + if !(row_min..=row_max).contains(&absolute_row) { + continue; + } + + let row_y = sequence_rows_area.y + row_offset as u16; + shader( + f, + id_inner_area, + Rect::new( + id_inner_area.x, + id_content_y + row_offset as u16, + id_end_x.saturating_sub(id_inner_area.x), + 1, + ), + ui.theme.theme.accent, + SELECTION_ROW_HIGHLIGHT_ALPHA, + ); + shader( + f, + sequence_rows_area, + Rect::new( + sequence_rows_area.x, + row_y, + sequence_end_x.saturating_sub(sequence_rows_area.x), + 1, + ), + ui.theme.theme.surface_bg, + SELECTION_ROW_TINT_ALPHA, + ); + } + + let scroll_start_y = sequence_rows_area.y + + band_layout.pinned_rendered as u16 + + band_layout.divider_height as u16; + for (row_offset, relative_row) in window.row_range.clone().enumerate() { + let Some(absolute_row) = alignment.view().absolute_row_id(relative_row) else { + continue; + }; + if !(row_min..=row_max).contains(&absolute_row) { + continue; + } + + let row_y = scroll_start_y + row_offset as u16; + shader( + f, + id_inner_area, + Rect::new( + id_inner_area.x, + id_content_y + + band_layout.pinned_rendered as u16 + + band_layout.divider_height as u16 + + row_offset as u16, + id_end_x.saturating_sub(id_inner_area.x), + 1, + ), + ui.theme.theme.accent, + SELECTION_ROW_HIGHLIGHT_ALPHA, + ); + shader( + f, + sequence_rows_area, + Rect::new( + sequence_rows_area.x, + row_y, + sequence_end_x.saturating_sub(sequence_rows_area.x), + 1, + ), + ui.theme.theme.surface_bg, + SELECTION_ROW_TINT_ALPHA, + ); + } + + if let Some(visible_col_range) = + selection_visible_col_range(selection, alignment, &window.col_range) + { + let start_x = + sequence_rows_area.x + (visible_col_range.start - window.col_range.start) as u16; + let end_x_exclusive = + sequence_rows_area.x + (visible_col_range.end - window.col_range.start) as u16; + shader( + f, + sequence_rows_area, + Rect::new( + start_x, + sequence_rows_area.y, + end_x_exclusive.saturating_sub(start_x), + sequence_rows_area.height, + ), + ui.theme.theme.panel_bg, + SELECTION_COL_HIGHLIGHT_ALPHA, + ); + } +} + /// Converts a selection (absolute columns) to a visible-column range clipped /// to `visible_col_range`. In translation mode, expands to full codon /// boundaries. Returns `None` when the selection does not overlap the viewport. @@ -76,6 +212,62 @@ pub fn selection_visible_col_range( } } +fn interpolate(from: u8, to: u8, alpha: f32) -> u8 { + let from = f32::from(from); + let to = f32::from(to); + (from + (to - from) * alpha).round().clamp(0.0, 255.0) as u8 +} + +fn blend_background( + base: ratatui::style::Color, + tint: ratatui::style::Color, + alpha: f32, +) -> ratatui::style::Color { + match (base, tint) { + (Rgb(red, green, blue), Rgb(red_tint, green_tint, blue_tint)) => Rgb( + interpolate(red, red_tint, alpha), + interpolate(green, green_tint, alpha), + interpolate(blue, blue_tint, alpha), + ), + _ => tint, + } +} + +fn shader( + f: &mut Frame, + clip_area: Rect, + tint_area: Rect, + tint: ratatui::style::Color, + alpha: f32, +) { + if alpha <= 0.0 || clip_area.width == 0 || clip_area.height == 0 { + return; + } + + let x_start = tint_area.x.max(clip_area.x); + let x_end = tint_area + .x + .saturating_add(tint_area.width) + .min(clip_area.x.saturating_add(clip_area.width)); + let y_start = tint_area.y.max(clip_area.y); + let y_end = tint_area + .y + .saturating_add(tint_area.height) + .min(clip_area.y.saturating_add(clip_area.height)); + if x_start >= x_end || y_start >= y_end { + return; + } + + let buffer = f.buffer_mut(); + for y in y_start..y_end { + for x in x_start..x_end { + if let Some(cell) = buffer.cell_mut((x, y)) { + cell.set_bg(blend_background(cell.bg, tint, alpha)); + } + } + } +} + fn raw_selection_visible_col_range( selection: MouseSelection, alignment: &AlignmentModel, diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap index 23c0db7..9657962 100644 --- a/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap @@ -1,6 +1,5 @@ --- source: salti/src/ui/render.rs -assertion_line: 544 expression: "render_text(Some(&alignment), &ui, &metrics, area)" --- File: Unknown | Status: Loaded | 2 alignments | Length: 18 | Positions: 1-18 @@ -20,10 +19,10 @@ expression: "render_text(Some(&alignment), &ui, &metrics, area)" │ │ │ │ │ │ │ │ │ -├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ -jump-position clear-filter toggle-translate load-alignment -jump-sequence filter-gaps reload-as-protein set-consensus-method -pin-sequence filter-constant check-update set-translation-frame -unpin-sequence set-reference quit set-theme -filter-rows clear-reference set-diff-mode set-sequence-type +jump-position filter-gaps check-update set-theme +jump-sequence filter-constant quit set-sequence-type +pin-sequence set-reference set-diff-mode load-gff +unpin-sequence clear-reference load-alignment +filter-rows toggle-translate set-consensus-method +clear-filter reload-as-protein set-translation-frame :█ diff --git a/salti/src/ui/frame.rs b/salti/src/ui/status_bars.rs similarity index 92% rename from salti/src/ui/frame.rs rename to salti/src/ui/status_bars.rs index 13e217a..e10119e 100644 --- a/salti/src/ui/frame.rs +++ b/salti/src/ui/status_bars.rs @@ -1,3 +1,5 @@ +use std::fmt::Write as _; + use crate::{ core::model::AlignmentModel, ui::{ @@ -36,23 +38,25 @@ fn build_bottom_status_bar(alignment: Option<&AlignmentModel>, ui: &UiState) -> let mut filter_text = String::from("Filters:"); let mut counts = format!(" ({visible_rows} rows)"); if let Some(pattern) = alignment.filter().pattern() { - filter_text.push_str(&format!(" [rows: {pattern}]")); + let _ = write!(filter_text, " [rows: {pattern}]"); } if let Some(max_gap_fraction) = alignment.filter().max_gap_fraction() { - filter_text.push_str(&format!( + let _ = write!( + filter_text, " [gaps: <= {}%]", format_percent(max_gap_fraction) - )); + ); } if let Some(min_constant_fraction) = alignment.filter().min_constant_fraction() { - filter_text.push_str(&format!( + let _ = write!( + filter_text, " [constant: >= {}%]", format_percent(min_constant_fraction) - )); + ); } if alignment.filter().has_column_filter() { let visible_cols = alignment.view().column_count(); - counts.push_str(&format!(" ({visible_cols} cols)")); + let _ = write!(counts, " ({visible_cols} cols)"); } parts.push(format!("{filter_text}{counts}").set_style(theme.warning)); } @@ -261,16 +265,17 @@ mod tests { filtered_alignment .set_filter("seq1|seq2".to_string()) .unwrap(); - filtered_alignment - .set_gap_filter(Some(0.5)) - .unwrap(); + filtered_alignment.set_gap_filter(Some(0.5)).unwrap(); filtered_alignment .set_translation(Some(libmsa::ReadingFrame::Frame2)) .unwrap(); insta::assert_snapshot!( "frame_bottom_status_filters_translation", - status_text(&build_bottom_status_bar(Some(&filtered_alignment), &ui_state())) + status_text(&build_bottom_status_bar( + Some(&filtered_alignment), + &ui_state() + )) ); let mut constant_filter_alignment = alignment_model(vec![ @@ -290,10 +295,8 @@ mod tests { )) ); - let selected_alignment = alignment_model(vec![ - raw("seq1", b"ACGTACGT"), - raw("seq2", b"ACGTACGT"), - ]); + let selected_alignment = + alignment_model(vec![raw("seq1", b"ACGTACGT"), raw("seq2", b"ACGTACGT")]); let mut single_selection_ui = ui_state(); single_selection_ui.selection = Some(MouseSelection { sequence_id: 0, @@ -304,7 +307,10 @@ mod tests { insta::assert_snapshot!( "frame_bottom_status_single_selection", - status_text(&build_bottom_status_bar(Some(&selected_alignment), &single_selection_ui)) + status_text(&build_bottom_status_bar( + Some(&selected_alignment), + &single_selection_ui + )) ); let mut multi_selection_ui = ui_state(); From 4057ed964e96e953a73e7943f4422748d48e9851 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Mon, 11 May 2026 18:06:00 +0100 Subject: [PATCH 23/48] refactor(salti): move status bars into panes module --- salti/src/ui/{ => panes}/status_bars.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename salti/src/ui/{ => panes}/status_bars.rs (100%) diff --git a/salti/src/ui/status_bars.rs b/salti/src/ui/panes/status_bars.rs similarity index 100% rename from salti/src/ui/status_bars.rs rename to salti/src/ui/panes/status_bars.rs From b486fe1d2a8f24e8e46c5a8f13bd40eb268b5bc7 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Mon, 11 May 2026 18:30:00 +0100 Subject: [PATCH 24/48] refactor(salti): consensus pane impl widget trait --- salti/src/ui/panes/consensus.rs | 159 +++++++++++++++----------------- salti/src/ui/render.rs | 30 ++++-- 2 files changed, 99 insertions(+), 90 deletions(-) diff --git a/salti/src/ui/panes/consensus.rs b/salti/src/ui/panes/consensus.rs index 2fd96a3..0beb899 100644 --- a/salti/src/ui/panes/consensus.rs +++ b/salti/src/ui/panes/consensus.rs @@ -1,9 +1,9 @@ -use ratatui::Frame; +use ratatui::buffer::Buffer; use ratatui::layout::Rect; use ratatui::style::{Styled, Stylize}; use ratatui::symbols::merge::MergeStrategy; use ratatui::text::Line; -use ratatui::widgets::{Block, Paragraph}; +use ratatui::widgets::{Block, Paragraph, Widget}; use crate::{ core::{ @@ -13,7 +13,6 @@ use crate::{ viewport::ViewportWindow, }, ui::{ - layout::AppLayout, rows::{ RowRenderMode, format_row_spans, format_translated_byte_range_spans, format_translated_row_spans, visible_bytes, @@ -24,6 +23,63 @@ use crate::{ const CONSERVATION_SPARK_STRS: [&str; 8] = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]; +pub(crate) struct ConsensusAlignmentPane<'a> { + pub(crate) alignment: &'a AlignmentModel, + pub(crate) window: &'a ViewportWindow, + pub(crate) metrics: &'a ColumnStatsCache, + pub(crate) theme: &'a ThemeState, +} + +impl Widget for ConsensusAlignmentPane<'_> { + fn render(self, area: Rect, buf: &mut Buffer) { + let block = Block::bordered() + .border_style(self.theme.styles.border) + .style(self.theme.styles.base_block) + .merge_borders(MergeStrategy::Exact); + let inner_area = block.inner(area); + block.render(area, buf); + + let lines = + consensus_alignment_lines(self.alignment, self.window, self.metrics, self.theme); + Paragraph::new(lines) + .style(self.theme.styles.base_block) + .render(inner_area, buf); + } +} + +pub(crate) struct ConsensusSequenceIdPane<'a> { + pub(crate) alignment: &'a AlignmentModel, + pub(crate) theme: &'a ThemeState, +} + +impl Widget for ConsensusSequenceIdPane<'_> { + fn render(self, area: Rect, buf: &mut Buffer) { + let block = Block::bordered() + .border_style(self.theme.styles.border) + .style(self.theme.styles.base_block) + .merge_borders(MergeStrategy::Exact); + let inner_area = block.inner(area); + block.render(area, buf); + + let lines = if shows_conservation_line(self.alignment) { + vec![ + Line::from("Reference Sequence:".set_style(self.theme.styles.accent)), + Line::from("Consensus Sequence:".set_style(self.theme.styles.accent)), + Line::from("Conservation:".set_style(self.theme.styles.accent)), + ] + } else { + vec![ + Line::from("Reference Sequence:".set_style(self.theme.styles.accent)), + Line::from("Consensus Sequence:".set_style(self.theme.styles.accent)), + ] + }; + + Paragraph::new(lines) + .style(self.theme.styles.base_block) + .render(inner_area, buf); + } +} + fn conservation_to_spark(value: f32) -> &'static str { let value = value.clamp(0.0, 1.0); let max_idx = CONSERVATION_SPARK_STRS.len() - 1; @@ -197,28 +253,6 @@ fn consensus_alignment_lines( } } -fn render_consensus_alignment_pane( - f: &mut Frame, - area: Rect, - alignment: &AlignmentModel, - window: &ViewportWindow, - metrics: &ColumnStatsCache, - theme: &ThemeState, -) { - let block = Block::bordered() - .border_style(theme.styles.border) - .style(theme.styles.base_block) - .merge_borders(MergeStrategy::Exact); - let inner_area = block.inner(area); - f.render_widget(block, area); - - let lines = consensus_alignment_lines(alignment, window, metrics, theme); - f.render_widget( - Paragraph::new(lines).style(theme.styles.base_block), - inner_area, - ); -} - fn build_conservation_line( metrics: &ColumnStatsCache, window: &ViewportWindow, @@ -244,62 +278,12 @@ fn build_conservation_line( Line::from(sparkline).set_style(theme.styles.accent_alt) } -fn render_consensus_sequence_id_pane( - f: &mut Frame, - area: Rect, - alignment: &AlignmentModel, - theme: &ThemeState, -) { - let block = Block::bordered() - .border_style(theme.styles.border) - .style(theme.styles.base_block) - .merge_borders(MergeStrategy::Exact); - let inner_area = block.inner(area); - f.render_widget(block, area); - - let lines = if shows_conservation_line(alignment) { - vec![ - Line::from("Reference Sequence:".set_style(theme.styles.accent)), - Line::from("Consensus Sequence:".set_style(theme.styles.accent)), - Line::from("Conservation:".set_style(theme.styles.accent)), - ] - } else { - vec![ - Line::from("Reference Sequence:".set_style(theme.styles.accent)), - Line::from("Consensus Sequence:".set_style(theme.styles.accent)), - ] - }; - - f.render_widget( - Paragraph::new(lines).style(theme.styles.base_block), - inner_area, - ); -} - -pub fn render_consensus_pane( - f: &mut Frame, - layout: &AppLayout, - alignment: &AlignmentModel, - window: &ViewportWindow, - metrics: &ColumnStatsCache, - theme: &ThemeState, -) { - render_consensus_sequence_id_pane(f, layout.consensus_sequence_id_pane, alignment, theme); - render_consensus_alignment_pane( - f, - layout.consensus_alignment_pane, - alignment, - window, - metrics, - theme, - ); -} - #[cfg(test)] mod tests { use super::*; use crate::core::model::StatsView; use crate::core::stats_cache::StatsJobResult; + use crate::ui::layout::AppLayout; use ratatui::Terminal; use ratatui::backend::TestBackend; use ratatui::buffer::Buffer; @@ -369,13 +353,22 @@ mod tests { terminal .draw(|frame| { - render_consensus_pane( - frame, - &layout, - alignment, - &window, - metrics, - &ThemeState::default(), + let theme = ThemeState::default(); + frame.render_widget( + ConsensusSequenceIdPane { + alignment, + theme: &theme, + }, + layout.consensus_sequence_id_pane, + ); + frame.render_widget( + ConsensusAlignmentPane { + alignment, + window: &window, + metrics, + theme: &theme, + }, + layout.consensus_alignment_pane, ); }) .unwrap(); diff --git a/salti/src/ui/render.rs b/salti/src/ui/render.rs index b07ce77..98a00a0 100644 --- a/salti/src/ui/render.rs +++ b/salti/src/ui/render.rs @@ -2,12 +2,13 @@ use crate::{ core::{model::AlignmentModel, stats_cache::ColumnStatsCache}, overlay::render::render_overlays, ui::{ - alignment_pane::render_alignment_pane, - consensus_pane::render_consensus_pane, - frame::render_frame, - layout::{AppLayout, FrameLayout, RULER_HEIGHT_ROWS, pinned_section_layout}, - selection::{selection_row_bounds, selection_visible_col_range}, - sequence_id_pane::render_sequence_id_pane, + layout::{AppLayout, FrameLayout}, + panes::alignment::render_alignment_pane, + panes::consensus::{ConsensusAlignmentPane, ConsensusSequenceIdPane}, + panes::gff::{FeatureMap, render as render_gff_pane}, + panes::sequence_id::render_sequence_id_pane, + panes::status_bars::render_frame, + selection::render_mouse_selection, ui_state::{LoadingState, UiState}, }, }; @@ -293,7 +294,22 @@ pub fn render( render_alignment_pane(f, layout, alignment, &ui.viewport, stats_cache, &ui.theme); - render_consensus_pane(f, layout, alignment, &window, stats_cache, &ui.theme); + f.render_widget( + ConsensusSequenceIdPane { + alignment, + theme: &ui.theme, + }, + layout.consensus_sequence_id_pane, + ); + f.render_widget( + ConsensusAlignmentPane { + alignment, + window: &window, + metrics: stats_cache, + theme: &ui.theme, + }, + layout.consensus_alignment_pane, + ); render_mouse_selection(f, layout, alignment, ui, &ui.viewport); render_overlays( From 9fd07970d569d82a3725b0c32792e62e4729ca73 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Mon, 11 May 2026 18:55:00 +0100 Subject: [PATCH 25/48] refactor(salti): impl widget for seq id pane --- salti/src/ui/panes/sequence_id.rs | 67 ++++++++++++++++++------------- salti/src/ui/render.rs | 12 +++++- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/salti/src/ui/panes/sequence_id.rs b/salti/src/ui/panes/sequence_id.rs index 3807cb7..d48a79d 100644 --- a/salti/src/ui/panes/sequence_id.rs +++ b/salti/src/ui/panes/sequence_id.rs @@ -1,15 +1,36 @@ use crate::{ core::{model::AlignmentModel, viewport::ViewportWindow}, ui::{ - layout::{AppLayout, RULER_HEIGHT_ROWS, pinned_section_layout}, + layout::{RULER_HEIGHT_ROWS, pinned_section_layout}, ui_state::ThemeState, }, }; -use ratatui::Frame; +use ratatui::buffer::Buffer; +use ratatui::layout::Rect; use ratatui::style::{Style, Styled}; use ratatui::symbols::merge::MergeStrategy; use ratatui::text::Line; -use ratatui::widgets::{Block, Paragraph}; +use ratatui::widgets::{Block, Paragraph, Widget}; + +pub(crate) struct SequenceIdPane<'a> { + pub(crate) alignment: &'a AlignmentModel, + pub(crate) window: &'a ViewportWindow, + pub(crate) theme: &'a ThemeState, +} + +impl Widget for SequenceIdPane<'_> { + fn render(self, area: Rect, buf: &mut Buffer) { + let block = Block::bordered() + .title("Sequence Name") + .border_style(self.theme.styles.border) + .style(self.theme.styles.base_block) + .merge_borders(MergeStrategy::Exact); + let inner_area = block.inner(area); + block.render(area, buf); + + render_sequence_id_rows(self.alignment, self.window, self.theme, inner_area, buf); + } +} fn build_sequence_id_line( theme: &ThemeState, @@ -35,11 +56,11 @@ fn build_pinned_divider_line(width: usize, style: Style) -> Line<'static> { } fn render_sequence_id_rows( - f: &mut Frame, alignment: &AlignmentModel, window: &ViewportWindow, theme: &ThemeState, - area: ratatui::layout::Rect, + area: Rect, + buf: &mut Buffer, ) { let ruler_height = usize::from(RULER_HEIGHT_ROWS); let available_content_height = area.height.saturating_sub(RULER_HEIGHT_ROWS) as usize; @@ -103,34 +124,16 @@ fn render_sequence_id_rows( )); } - f.render_widget( - Paragraph::new(lines) - .alignment(ratatui::layout::HorizontalAlignment::Left) - .style(theme.styles.base_block), - area, - ); -} - -pub fn render_sequence_id_pane( - f: &mut Frame, - layout: &AppLayout, - alignment: &AlignmentModel, - window: &ViewportWindow, - theme: &ThemeState, -) { - let block = Block::bordered() - .border_style(theme.styles.border) + Paragraph::new(lines) + .alignment(ratatui::layout::HorizontalAlignment::Left) .style(theme.styles.base_block) - .merge_borders(MergeStrategy::Exact); - let inner_area = block.inner(layout.sequence_id_pane); - f.render_widget(block, layout.sequence_id_pane); - - render_sequence_id_rows(f, alignment, window, theme, inner_area); + .render(area, buf); } #[cfg(test)] mod tests { use super::*; + use crate::ui::layout::AppLayout; use ratatui::Terminal; use ratatui::backend::TestBackend; use ratatui::buffer::Buffer; @@ -156,7 +159,15 @@ mod tests { terminal .draw(|frame| { - render_sequence_id_pane(frame, &layout, alignment, window, &ThemeState::default()); + let theme = ThemeState::default(); + frame.render_widget( + SequenceIdPane { + alignment, + window, + theme: &theme, + }, + layout.sequence_id_pane, + ); }) .unwrap(); diff --git a/salti/src/ui/render.rs b/salti/src/ui/render.rs index 98a00a0..3874509 100644 --- a/salti/src/ui/render.rs +++ b/salti/src/ui/render.rs @@ -6,7 +6,7 @@ use crate::{ panes::alignment::render_alignment_pane, panes::consensus::{ConsensusAlignmentPane, ConsensusSequenceIdPane}, panes::gff::{FeatureMap, render as render_gff_pane}, - panes::sequence_id::render_sequence_id_pane, + panes::sequence_id::SequenceIdPane, panes::status_bars::render_frame, selection::render_mouse_selection, ui_state::{LoadingState, UiState}, @@ -290,7 +290,15 @@ pub fn render( }; let window = ui.viewport.window(); - render_sequence_id_pane(f, layout, alignment, &window, &ui.theme); + + f.render_widget( + SequenceIdPane { + alignment, + window: &window, + theme: &ui.theme, + }, + layout.sequence_id_pane, + ); render_alignment_pane(f, layout, alignment, &ui.viewport, stats_cache, &ui.theme); From f4ada087aa49bd1a57a479b8cd58b9b6b89d7f8e Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Mon, 11 May 2026 19:23:00 +0100 Subject: [PATCH 26/48] refactor(salti): impl widget for alignment pane --- salti/src/ui/panes/alignment.rs | 122 +++++++++++++++++--------------- salti/src/ui/render.rs | 12 +++- 2 files changed, 74 insertions(+), 60 deletions(-) diff --git a/salti/src/ui/panes/alignment.rs b/salti/src/ui/panes/alignment.rs index 257f08d..67725fa 100644 --- a/salti/src/ui/panes/alignment.rs +++ b/salti/src/ui/panes/alignment.rs @@ -1,10 +1,10 @@ -use ratatui::Frame; +use ratatui::buffer::Buffer; use ratatui::layout::Rect; use ratatui::macros::vertical; use ratatui::style::Styled; use ratatui::symbols::merge::MergeStrategy; use ratatui::text::{Line, Span}; -use ratatui::widgets::{Block, Paragraph}; +use ratatui::widgets::{Block, Paragraph, Widget}; use crate::{ core::{ @@ -14,7 +14,7 @@ use crate::{ viewport::{Viewport, ViewportWindow}, }, ui::{ - layout::{AppLayout, PinnedSectionLayout, RULER_HEIGHT_ROWS, pinned_section_layout}, + layout::{PinnedSectionLayout, RULER_HEIGHT_ROWS, pinned_section_layout}, rows::{RowRenderMode, format_row_spans, format_translated_row_spans, visible_bytes}, ui_state::ThemeState, }, @@ -23,6 +23,47 @@ use crate::{ const SCROLLBAR_THUMB_WIDTH: usize = 3; const SCROLLBAR_THUMB_MIN_WIDTH: usize = 1; +pub(crate) struct AlignmentPane<'a> { + pub(crate) alignment: &'a AlignmentModel, + pub(crate) viewport: &'a Viewport, + pub(crate) metrics: &'a ColumnStatsCache, + pub(crate) theme: &'a ThemeState, +} + +impl Widget for AlignmentPane<'_> { + fn render(self, area: Rect, buf: &mut Buffer) { + let block = Block::bordered() + .title("Alignment") + .border_style(self.theme.styles.border) + .style(self.theme.styles.base_block) + .merge_borders(MergeStrategy::Exact); + let inner_area = block.inner(area); + block.render(area, buf); + + let [ruler_area, sequence_rows_area] = + inner_area.layout(&vertical![==RULER_HEIGHT_ROWS, *=1]); + let window = self.viewport.window(); + + render_ruler(self.alignment, &window, ruler_area, self.theme, buf); + render_sequence_rows( + self.alignment, + &window, + self.metrics, + sequence_rows_area, + self.theme, + buf, + ); + render_scrollbar( + self.alignment, + self.viewport, + &window, + self.theme, + area, + buf, + ); + } +} + fn raw_render_mode<'a>( alignment: &AlignmentModel, reference_bytes: Option<&'a [u8]>, @@ -202,24 +243,26 @@ fn build_sequence_row_lines( } fn render_sequence_rows( - f: &mut Frame, alignment: &AlignmentModel, window: &ViewportWindow, metrics: &ColumnStatsCache, area: Rect, theme: &ThemeState, + buf: &mut Buffer, ) { let lines = build_sequence_row_lines(alignment, window, metrics, area, theme); - f.render_widget(Paragraph::new(lines).style(theme.styles.base_block), area); + Paragraph::new(lines) + .style(theme.styles.base_block) + .render(area, buf); } fn render_scrollbar( - f: &mut Frame, alignment: &AlignmentModel, viewport: &Viewport, window: &ViewportWindow, theme: &ThemeState, area: Rect, + buf: &mut Buffer, ) { if area.width < 2 || area.height == 0 { return; @@ -262,7 +305,7 @@ fn render_scrollbar( for offset in thumb_start..thumb_end { let thumb_x = scrollbar_area.x + offset as u16; - if let Some(cell) = f.buffer_mut().cell_mut((thumb_x, thumb_y)) { + if let Some(cell) = buf.cell_mut((thumb_x, thumb_y)) { let track_colour = cell.fg; cell.set_char('▬'); cell.set_fg(thumb_colour); @@ -462,11 +505,11 @@ fn build_ruler( } fn render_ruler( - f: &mut Frame, alignment: &AlignmentModel, window: &ViewportWindow, area: Rect, theme: &ThemeState, + buf: &mut Buffer, ) { let absolute_columns: Vec = window .col_range @@ -490,40 +533,9 @@ fn render_ruler( filtered_trailing, theme, ); - f.render_widget( - Paragraph::new(vec![number_line, marker_line]).style(theme.styles.base_block), - area, - ); -} - -pub fn render_alignment_pane( - f: &mut Frame, - layout: &AppLayout, - alignment: &AlignmentModel, - viewport: &Viewport, - metrics: &ColumnStatsCache, - theme: &ThemeState, -) { - let block = Block::bordered() - .border_style(theme.styles.border) + Paragraph::new(vec![number_line, marker_line]) .style(theme.styles.base_block) - .merge_borders(MergeStrategy::Exact); - let inner_area = block.inner(layout.alignment_pane); - f.render_widget(block, layout.alignment_pane); - - let [ruler_area, sequence_rows_area] = inner_area.layout(&vertical![==RULER_HEIGHT_ROWS, *=1]); - let window = viewport.window(); - - render_ruler(f, alignment, &window, ruler_area, theme); - render_sequence_rows(f, alignment, &window, metrics, sequence_rows_area, theme); - render_scrollbar( - f, - alignment, - viewport, - &window, - theme, - layout.alignment_pane, - ); + .render(area, buf); } #[cfg(test)] @@ -531,8 +543,7 @@ mod tests { use super::*; use crate::core::model::StatsView; use crate::core::stats_cache::StatsJobResult; - use ratatui::Terminal; - use ratatui::backend::TestBackend; + use crate::ui::layout::AppLayout; use ratatui::buffer::Buffer; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { @@ -590,8 +601,7 @@ mod tests { row_offset: usize, col_offset: usize, ) -> String { - let backend = TestBackend::new(area.width, area.height); - let mut terminal = Terminal::new(backend).unwrap(); + let mut buffer = Buffer::empty(area); let layout = AppLayout::new(area, 0); let mut viewport = Viewport::default(); viewport.update_dimensions( @@ -607,20 +617,16 @@ mod tests { viewport.offsets.rows = row_offset; viewport.offsets.cols = col_offset; - terminal - .draw(|frame| { - render_alignment_pane( - frame, - &layout, - alignment, - &viewport, - stats_cache, - &ThemeState::default(), - ); - }) - .unwrap(); + let theme = ThemeState::default(); + AlignmentPane { + alignment, + viewport: &viewport, + metrics: stats_cache, + theme: &theme, + } + .render(layout.alignment_pane, &mut buffer); - buffer_text(terminal.backend().buffer(), layout.alignment_pane) + buffer_text(&buffer, layout.alignment_pane) } fn buffer_text(buffer: &Buffer, area: Rect) -> String { diff --git a/salti/src/ui/render.rs b/salti/src/ui/render.rs index 3874509..d63dfc5 100644 --- a/salti/src/ui/render.rs +++ b/salti/src/ui/render.rs @@ -3,7 +3,7 @@ use crate::{ overlay::render::render_overlays, ui::{ layout::{AppLayout, FrameLayout}, - panes::alignment::render_alignment_pane, + panes::alignment::AlignmentPane, panes::consensus::{ConsensusAlignmentPane, ConsensusSequenceIdPane}, panes::gff::{FeatureMap, render as render_gff_pane}, panes::sequence_id::SequenceIdPane, @@ -300,7 +300,15 @@ pub fn render( layout.sequence_id_pane, ); - render_alignment_pane(f, layout, alignment, &ui.viewport, stats_cache, &ui.theme); + f.render_widget( + AlignmentPane { + alignment, + viewport: &ui.viewport, + metrics: stats_cache, + theme: &ui.theme, + }, + layout.alignment_pane, + ); f.render_widget( ConsensusSequenceIdPane { From 2ef2001c1a9ca0bf22ab8d89be0cffdc6d1fb56c Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Mon, 11 May 2026 19:48:00 +0100 Subject: [PATCH 27/48] tests(salti): update tests to use terminal buffers --- salti/src/ui/panes/consensus.rs | 41 +++++++++++-------------------- salti/src/ui/panes/sequence_id.rs | 27 +++++++------------- 2 files changed, 24 insertions(+), 44 deletions(-) diff --git a/salti/src/ui/panes/consensus.rs b/salti/src/ui/panes/consensus.rs index 0beb899..5f7dd7c 100644 --- a/salti/src/ui/panes/consensus.rs +++ b/salti/src/ui/panes/consensus.rs @@ -284,8 +284,6 @@ mod tests { use crate::core::model::StatsView; use crate::core::stats_cache::StatsJobResult; use crate::ui::layout::AppLayout; - use ratatui::Terminal; - use ratatui::backend::TestBackend; use ratatui::buffer::Buffer; use ratatui::layout::Rect; @@ -342,8 +340,7 @@ mod tests { metrics: &ColumnStatsCache, area: Rect, ) -> String { - let backend = TestBackend::new(area.width, area.height); - let mut terminal = Terminal::new(backend).unwrap(); + let mut buffer = Buffer::empty(area); let layout = AppLayout::new(area, 0); let window = ViewportWindow { row_range: 0..alignment.view().row_count(), @@ -351,29 +348,21 @@ mod tests { name_range: 0..0, }; - terminal - .draw(|frame| { - let theme = ThemeState::default(); - frame.render_widget( - ConsensusSequenceIdPane { - alignment, - theme: &theme, - }, - layout.consensus_sequence_id_pane, - ); - frame.render_widget( - ConsensusAlignmentPane { - alignment, - window: &window, - metrics, - theme: &theme, - }, - layout.consensus_alignment_pane, - ); - }) - .unwrap(); + let theme = ThemeState::default(); + ConsensusSequenceIdPane { + alignment, + theme: &theme, + } + .render(layout.consensus_sequence_id_pane, &mut buffer); + ConsensusAlignmentPane { + alignment, + window: &window, + metrics, + theme: &theme, + } + .render(layout.consensus_alignment_pane, &mut buffer); - buffer_text(terminal.backend().buffer()) + buffer_text(&buffer) } fn buffer_text(buffer: &Buffer) -> String { diff --git a/salti/src/ui/panes/sequence_id.rs b/salti/src/ui/panes/sequence_id.rs index d48a79d..707a31a 100644 --- a/salti/src/ui/panes/sequence_id.rs +++ b/salti/src/ui/panes/sequence_id.rs @@ -134,8 +134,6 @@ fn render_sequence_id_rows( mod tests { use super::*; use crate::ui::layout::AppLayout; - use ratatui::Terminal; - use ratatui::backend::TestBackend; use ratatui::buffer::Buffer; use ratatui::layout::Rect; @@ -153,25 +151,18 @@ mod tests { fn render_sequence_id_pane_text(alignment: &AlignmentModel, window: &ViewportWindow) -> String { let area = Rect::new(0, 0, 150, 12); - let backend = TestBackend::new(area.width, area.height); - let mut terminal = Terminal::new(backend).unwrap(); + let mut buffer = Buffer::empty(area); let layout = AppLayout::new(area, 0); + let theme = ThemeState::default(); - terminal - .draw(|frame| { - let theme = ThemeState::default(); - frame.render_widget( - SequenceIdPane { - alignment, - window, - theme: &theme, - }, - layout.sequence_id_pane, - ); - }) - .unwrap(); + SequenceIdPane { + alignment, + window, + theme: &theme, + } + .render(layout.sequence_id_pane, &mut buffer); - buffer_text(terminal.backend().buffer()) + buffer_text(&buffer) } fn buffer_text(buffer: &Buffer) -> String { From cb0367b19d62d131dc7df585da9565b0dd317c0e Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Mon, 11 May 2026 20:20:00 +0100 Subject: [PATCH 28/48] feat(libmsa): add relative_column_range_intersecting function --- libmsa/src/model.rs | 45 ++++++++++++++++++++++++++++++++++++++++ libmsa/src/projection.rs | 32 +++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/libmsa/src/model.rs b/libmsa/src/model.rs index 7e45fe2..d140e20 100644 --- a/libmsa/src/model.rs +++ b/libmsa/src/model.rs @@ -229,6 +229,19 @@ impl Alignment { self.columns.relative(absolute) } + /// Returns the visible relative column range covered by `absolute_range`. + /// + /// The returned range uses this view's visible column indices and includes every visible + /// column whose absolute ID is inside `absolute_range`. + /// + /// Returns `None` when none of the columns in `absolute_range` are visible. + pub fn relative_column_range_intersecting( + &self, + absolute_range: Range, + ) -> Option> { + self.columns.relative_range_intersecting(absolute_range) + } + /// Returns the type currently used to interpret this alignment. pub fn active_type(&self) -> AlignmentType { self.active_type @@ -656,6 +669,38 @@ mod alignment_projection_tests { assert_eq!(filtered.absolute_column_id(2), None); } + #[test] + fn relative_column_range_intersecting_full() { + let alignment = Alignment::new(vec![raw("s1", b"ACGT")]).unwrap(); + + assert_eq!( + alignment.relative_column_range_intersecting(1..3), + Some(1..3) + ); + assert_eq!( + alignment.relative_column_range_intersecting(2..99), + Some(2..4) + ); + assert_eq!(alignment.relative_column_range_intersecting(4..8), None); + } + + #[test] + fn relative_column_range_intersecting_filtered() { + let alignment = Alignment::new(vec![raw("s1", b"ACGTACGT")]).unwrap(); + let filtered = alignment.with_projections( + Projection::Full { + len: alignment.row_count(), + }, + Projection::Filtered(Arc::from(vec![1usize, 3, 4, 7])), + ); + + assert_eq!( + filtered.relative_column_range_intersecting(2..6), + Some(1..3) + ); + assert_eq!(filtered.relative_column_range_intersecting(5..6), None); + } + #[test] fn unfiltered_matches_sequence() { let alignment = Alignment::new(vec![raw("s1", b"ACGT"), raw("s2", b"TGCA")]).unwrap(); diff --git a/libmsa/src/projection.rs b/libmsa/src/projection.rs index 5ed3d5a..9cd4d76 100644 --- a/libmsa/src/projection.rs +++ b/libmsa/src/projection.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{ops::Range, sync::Arc}; #[derive(Debug, Clone)] pub(crate) enum Projection { @@ -33,6 +33,18 @@ impl Projection { } } + pub(crate) fn relative_range_intersecting(&self, range: Range) -> Option> { + let range = match self { + Self::Full { len } => range.start.min(*len)..range.end.min(*len), + Self::Filtered(ids) => { + let start = ids.partition_point(|&column| column < range.start); + let end = ids.partition_point(|&column| column < range.end); + start..end + } + }; + (!range.is_empty()).then_some(range) + } + pub(crate) fn iter(&self) -> ProjectionIter<'_> { match self { Self::Full { len } => ProjectionIter::Full(0..*len), @@ -151,6 +163,24 @@ mod tests { assert_eq!(filtered.relative(0), None); } + #[test] + fn full_projection_relative_range_intersecting() { + let proj = Projection::Full { len: 5 }; + assert_eq!(proj.relative_range_intersecting(2..5), Some(2..5)); + assert_eq!(proj.relative_range_intersecting(2..99), Some(2..5)); + assert_eq!(proj.relative_range_intersecting(5..8), None); + assert_eq!(proj.relative_range_intersecting(3..3), None); + } + + #[test] + fn filtered_projection_relative_range_intersecting() { + let proj = Projection::Filtered(Arc::from([1, 3, 4, 7].as_slice())); + assert_eq!(proj.relative_range_intersecting(2..6), Some(1..3)); + assert_eq!(proj.relative_range_intersecting(1..8), Some(0..4)); + assert_eq!(proj.relative_range_intersecting(5..6), None); + assert_eq!(proj.relative_range_intersecting(3..3), None); + } + #[test] fn relative_absolute_round_trip() { let proj = Projection::Filtered(Arc::from([2, 5, 8].as_slice())); From 0dbdcbea5ccc3c8014978403ec983f38796843c4 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Mon, 11 May 2026 20:22:00 +0100 Subject: [PATCH 29/48] style(salti): cargo fmt --- salti/src/core/model.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/salti/src/core/model.rs b/salti/src/core/model.rs index 079a065..c6bca47 100644 --- a/salti/src/core/model.rs +++ b/salti/src/core/model.rs @@ -246,7 +246,8 @@ impl AlignmentModel { self.update_current_view() } - pub fn set_filter(&mut self, pattern: String) -> Result<(), libmsa::AlignmentError> { + pub fn set_filter(&mut self, pattern: impl Into) -> Result<(), libmsa::AlignmentError> { + let pattern = pattern.into(); let next_pattern = if pattern.is_empty() { None } else { @@ -862,7 +863,10 @@ mod tests { #[test] fn reload_as_protein_preserves_filter_and_restores_dna() { - let mut model = alignment_model(vec![raw("seq1", b"CATCATCATCAT"), raw("seq2", b"CATCATCATCAT")]); + let mut model = alignment_model(vec![ + raw("seq1", b"CATCATCATCAT"), + raw("seq2", b"CATCATCATCAT"), + ]); model.set_filter("seq1".to_string()).unwrap(); model .set_translation(Some(libmsa::ReadingFrame::Frame2)) From d037c82ac6aa3ea6e5e5ba9b4f041eecbc092fcc Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Tue, 12 May 2026 19:20:00 +0100 Subject: [PATCH 30/48] feat(salti): add basic gff parsing --- salti/src/app.rs | 58 ++- salti/src/core/mod.rs | 1 + salti/src/input/mouse.rs | 109 ++++- salti/src/input/route.rs | 90 +++- salti/src/ui/layout.rs | 30 +- salti/src/ui/mod.rs | 1 - salti/src/ui/panes/alignment.rs | 1 - salti/src/ui/panes/gff.rs | 661 ++++++++++++++++++++++++++++++ salti/src/ui/panes/mod.rs | 5 + salti/src/ui/panes/sequence_id.rs | 1 - salti/src/ui/render.rs | 260 +++--------- salti/src/ui/rows.rs | 1 - salti/src/ui/selection.rs | 16 - salti/src/ui/ui_state.rs | 21 +- 14 files changed, 973 insertions(+), 282 deletions(-) create mode 100644 salti/src/ui/panes/gff.rs create mode 100644 salti/src/ui/panes/mod.rs diff --git a/salti/src/app.rs b/salti/src/app.rs index a03a9a5..eed4004 100644 --- a/salti/src/app.rs +++ b/salti/src/app.rs @@ -1,4 +1,4 @@ -use std::{env, time::Duration}; +use std::{env, path::Path, time::Duration}; use anyhow::{Result, format_err}; use crossterm::event::{Event as TermEvent, EventStream, KeyEvent, MouseEvent}; @@ -14,14 +14,16 @@ use tracing::{debug, error, info, warn}; use crate::cli::StartupState; use crate::command::Command; +use crate::core::gff::{self, Gff}; use crate::core::model::{AlignmentModel, StatsView}; use crate::core::parser; use crate::core::stats_cache::{ColumnStatsCache, StatsJobRequest, StatsJobResult}; use crate::input; use crate::input::MouseTracker; -use crate::overlay::command_palette::CommandPaletteState; -use crate::ui::layout::{AppLayout, FrameLayout, pinned_section_layout}; -use crate::ui::notification::{Notification, NotificationLevel}; +use crate::ui::layers::notification::{Notification, NotificationLevel}; +use crate::ui::layers::palette::CommandPaletteState; +use crate::ui::layout::{AppLayout, FrameLayout, gff_pane_height, pinned_section_layout}; +use crate::ui::panes::gff::feature_row_count; use crate::ui::render::render; use crate::ui::ui_state::{LoadingState, UiState}; use crate::update::UpdateResult; @@ -46,6 +48,7 @@ struct AsyncJob { #[derive(Debug)] pub(crate) struct App { alignment: Option, + gff: Option, ui: UiState, mouse_tracker: MouseTracker, stats_cache: ColumnStatsCache, @@ -64,9 +67,10 @@ impl App { pub(crate) fn new(startup: StartupState) -> Self { let layout_area = Rect::default(); let frame_layout = FrameLayout::new(layout_area); - let app_layout = AppLayout::new(frame_layout.content_area); + let app_layout = AppLayout::new(frame_layout.content_area, 0); Self { alignment: None, + gff: None, ui: UiState::new(startup), mouse_tracker: MouseTracker::default(), stats_cache: ColumnStatsCache::default(), @@ -127,6 +131,7 @@ impl App { render( frame, self.alignment.as_ref(), + self.gff.as_ref(), &self.ui, &self.stats_cache, &self.frame_layout, @@ -240,7 +245,19 @@ impl App { self.layout_area = area; self.frame_layout = FrameLayout::new(area); - self.app_layout = AppLayout::new(self.frame_layout.content_area); + // hides the gff pane if we dont have one loaded + // if loaded the height is dynamic to the number of rows the features spill on to + let gff_height = self.gff.as_ref().map_or(0, |gff| { + let Some(alignment) = self.alignment.as_ref() else { + return 0; + }; + // create a temp applayout with a gff height of 1 to get a value for width + let probe_layout = AppLayout::new(self.frame_layout.content_area, gff_pane_height(1)); + let width = usize::from(probe_layout.gff_pane_rows.width); + gff_pane_height(feature_row_count(gff, alignment, width).max(1)) + }); + // set the real layout once we know the height of the gff + self.app_layout = AppLayout::new(self.frame_layout.content_area, gff_height); let visible_width = self.app_layout.alignment_pane.width.saturating_sub(2) as usize; let available_sequence_rows = self.app_layout.alignment_pane_sequence_rows.height as usize; @@ -291,6 +308,7 @@ impl App { let commands = input::handle_mouse_event( &mut self.mouse_tracker, self.alignment.as_ref(), + self.gff.as_ref(), &mut self.ui, &self.frame_layout, &self.app_layout, @@ -339,10 +357,10 @@ impl App { self.open_command_palette(); } Command::CloseOverlay => { - self.ui.overlay.close(); + self.ui.layers.close_active(); } Command::ToggleMinimap => { - self.ui.overlay.toggle_minimap(); + self.ui.layers.toggle_minimap(); } Command::SetTheme(theme_id) => { self.ui.set_theme(theme_id); @@ -354,6 +372,17 @@ impl App { self.clear_mouse_selection(); self.start_load_job(input); } + Command::LoadGff { path } => match gff::parse_gff(Path::new(&path)) { + Ok(model) => { + self.gff = Some(model); + self.ui.gff_pane = Default::default(); + self.force_relayout(); + self.show_info(format!("Loaded GFF file: {path}")); + } + Err(error) => { + return Err(error); + } + }, Command::CheckForUpdate => { self.spawn_update_check(false); } @@ -485,8 +514,9 @@ impl App { let viewport_target = self.reload_as_protein_viewport_target(frame); self.alignment_mut()?.toggle_reload_as_protein(frame)?; self.clear_mouse_selection(); - self.on_view_rebuilt(); + self.force_relayout(); self.jump_to_reloaded_viewport_target(viewport_target); + self.invalidate_all_stats(); return Ok(()); } Command::SetTranslationFrame(frame) => { @@ -524,11 +554,11 @@ impl App { .as_ref() .map(CommandPaletteState::from_alignment) .unwrap_or_else(CommandPaletteState::empty); - self.ui.overlay.open_palette(palette); + self.ui.layers.open_palette(palette); } fn on_view_rebuilt(&mut self) { - self.refresh_viewport_bounds(); + self.force_relayout(); self.invalidate_all_stats(); } @@ -594,6 +624,12 @@ impl App { ); } + fn force_relayout(&mut self) { + let area = self.layout_area; + self.layout_area = Rect::default(); + self.update_layout(area); + } + fn alignment_mut(&mut self) -> Result<&mut AlignmentModel> { self.alignment .as_mut() diff --git a/salti/src/core/mod.rs b/salti/src/core/mod.rs index 5397e7d..3101f4a 100644 --- a/salti/src/core/mod.rs +++ b/salti/src/core/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod codon; +pub(crate) mod gff; pub mod model; pub mod parser; pub mod search; diff --git a/salti/src/input/mouse.rs b/salti/src/input/mouse.rs index a151266..54f8fea 100644 --- a/salti/src/input/mouse.rs +++ b/salti/src/input/mouse.rs @@ -1,25 +1,20 @@ use crossterm::event::{KeyModifiers, MouseButton, MouseEvent, MouseEventKind}; use crate::command::Command; +use crate::core::gff::Gff; use crate::core::model::AlignmentModel; use crate::input::route::{MouseRoute, route_mouse}; -use crate::overlay::minimap::MinimapState; -use crate::overlay::overlay_state::ActiveOverlay; +use crate::ui::layers::minimap::MinimapState; +use crate::ui::layers::state::ActiveLayer; use crate::ui::layout::{AppLayout, FrameLayout}; +use crate::ui::panes::gff; use crate::ui::selection::selection_point_crosshair; use crate::ui::ui_state::{MouseSelection, UiState}; -/// Snapshot of a mouse click position in absolute coordinates. -/// -/// In translation mode, `column` and `end_column` span the full codon -/// (three nucleotide columns). In raw mode they are identical. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) struct MouseAnchor { - /// Absolute row index. sequence_id: usize, - /// Absolute column of the codon/cell start. column: usize, - /// Absolute column of the codon/cell end (inclusive). end_column: usize, } @@ -69,23 +64,25 @@ impl MouseTracker { } } +#[allow(clippy::too_many_arguments)] pub(crate) fn handle_mouse_event( tracker: &mut MouseTracker, alignment: Option<&AlignmentModel>, + gff: Option<&Gff>, ui: &mut UiState, frame_layout: &FrameLayout, app_layout: &AppLayout, mouse: MouseEvent, ) -> Vec { let mut commands = Vec::new(); - match route_mouse(ui, frame_layout, mouse) { + ui.gff_tooltip = None; + + match route_mouse(ui, frame_layout, app_layout, mouse, gff.is_some()) { MouseRoute::Palette => (), MouseRoute::Minimap => { if let Some(alignment) = alignment { let viewport_col_range = ui.viewport.window().col_range; - if let Some(ActiveOverlay::Minimap(minimap_state)) = - ui.overlay.active_overlay.as_mut() - { + if let Some(ActiveLayer::Minimap(minimap_state)) = ui.layers.active.as_mut() { handle_minimap_mouse_event( &mut commands, alignment, @@ -97,6 +94,11 @@ pub(crate) fn handle_mouse_event( } } } + MouseRoute::GffPane => { + if let (Some(gff), Some(alignment)) = (gff, alignment) { + handle_gff_mouse_event(&mut commands, gff, alignment, ui, app_layout, mouse); + } + } MouseRoute::Alignment => { if let Some(alignment) = alignment { handle_alignment_mouse_event( @@ -131,6 +133,27 @@ fn handle_minimap_mouse_event( } } +fn handle_gff_mouse_event( + commands: &mut Vec, + gff: &Gff, + alignment: &AlignmentModel, + ui: &mut UiState, + app_layout: &AppLayout, + mouse: MouseEvent, +) { + let viewport_col_range = ui.viewport.window().col_range; + let gff_pane_rows = app_layout.gff_pane_rows; + + if let Some(cmd) = + ui.gff_pane + .handle_mouse(mouse, gff_pane_rows, &viewport_col_range, alignment) + { + commands.push(cmd); + } + + ui.gff_tooltip = gff::tooltip_at(gff, alignment, gff_pane_rows, mouse.column, mouse.row); +} + fn handle_alignment_mouse_event( commands: &mut Vec, tracker: &mut MouseTracker, @@ -156,8 +179,7 @@ fn handle_alignment_mouse_event( tracker.clear_anchors(); return; }; - let store_anchor = alignment.translation().is_some() - || mouse.modifiers.contains(KeyModifiers::CONTROL); + let store_anchor = mouse.modifiers.contains(KeyModifiers::CONTROL); tracker.box_anchor = if store_anchor { Some(anchor) } else { None }; ui.selection = Some(selection_from_anchors(anchor, anchor)); @@ -238,7 +260,7 @@ mod tests { use super::*; use crate::cli::StartupState; - use crate::overlay::command_palette::CommandPaletteState; + use crate::ui::layers::palette::CommandPaletteState; use crate::ui::layout::{AppLayout, FrameLayout}; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { @@ -248,6 +270,17 @@ mod tests { } } + fn gff(start: usize, end: usize) -> Gff { + Gff { + features: vec![crate::core::gff::Feature { + name: "gene".to_string(), + kind: crate::core::gff::FeatureType::Gene, + range: start..end, + strand: crate::core::gff::Strand::Forward, + }], + } + } + fn ui_state() -> UiState { UiState::new(StartupState { file_path: None, @@ -259,9 +292,9 @@ mod tests { fn palette_route_masks_mouse_commands() { let mut tracker = MouseTracker::default(); let mut ui = ui_state(); - ui.overlay.open_palette(CommandPaletteState::empty()); + ui.layers.open_palette(CommandPaletteState::empty()); let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); - let app_layout = AppLayout::new(frame_layout.content_area); + let app_layout = AppLayout::new(frame_layout.content_area, 0); let mouse = MouseEvent { kind: MouseEventKind::Down(MouseButton::Left), column: 10, @@ -272,6 +305,7 @@ mod tests { let commands = handle_mouse_event( &mut tracker, None, + None, &mut ui, &frame_layout, &app_layout, @@ -295,10 +329,10 @@ mod tests { let mut tracker = MouseTracker::default(); let mut ui = ui_state(); let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); - let app_layout = AppLayout::new(frame_layout.content_area); + let app_layout = AppLayout::new(frame_layout.content_area, 0); ui.viewport.update_dimensions(78, 10, 20); ui.viewport.set_bounds(2, 200, 4); - ui.overlay.toggle_minimap(); + ui.layers.toggle_minimap(); let mouse = MouseEvent { kind: MouseEventKind::Down(MouseButton::Left), column: frame_layout.overlay_area.x + frame_layout.overlay_area.width - 2, @@ -309,6 +343,7 @@ mod tests { let commands = handle_mouse_event( &mut tracker, Some(&model), + None, &mut ui, &frame_layout, &app_layout, @@ -317,4 +352,38 @@ mod tests { assert!(matches!(commands.as_slice(), [Command::JumpToPosition(_)])); } + + #[test] + fn moved_event_in_gff_pane_sets_tooltip_without_mouse_down() { + let alignment = libmsa::Alignment::new(vec![raw("row1", &[b'A'; 20])]) + .expect("alignment should be valid"); + let model = crate::core::model::AlignmentModel::new(alignment) + .expect("alignment model should be valid"); + let gff = gff(0, 10); + let mut tracker = MouseTracker::default(); + let mut ui = ui_state(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new(frame_layout.content_area, 4); + ui.viewport.update_dimensions(20, 10, 20); + ui.viewport.set_bounds(1, 20, 4); + let mouse = MouseEvent { + kind: MouseEventKind::Moved, + column: app_layout.gff_pane_rows.x, + row: app_layout.gff_pane_rows.y, + modifiers: KeyModifiers::empty(), + }; + + let commands = handle_mouse_event( + &mut tracker, + Some(&model), + Some(&gff), + &mut ui, + &frame_layout, + &app_layout, + mouse, + ); + + assert!(commands.is_empty()); + assert_eq!(ui.gff_tooltip.as_deref(), Some("gene (gene) — Forward →\n1-10 • 10 nt")); + } } diff --git a/salti/src/input/route.rs b/salti/src/input/route.rs index 9538c09..a07adc2 100644 --- a/salti/src/input/route.rs +++ b/salti/src/input/route.rs @@ -1,7 +1,7 @@ use crossterm::event::{MouseButton, MouseEvent, MouseEventKind}; -use crate::overlay::overlay_state::ActiveOverlay; -use crate::ui::layout::FrameLayout; +use crate::ui::layers::state::ActiveLayer; +use crate::ui::layout::{AppLayout, FrameLayout}; use crate::ui::ui_state::UiState; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -14,12 +14,13 @@ pub(super) enum KeyRoute { pub(super) enum MouseRoute { Palette, Minimap, + GffPane, Alignment, } pub(super) fn route_key(ui: &UiState) -> KeyRoute { - match &ui.overlay.active_overlay { - Some(ActiveOverlay::Palette(_)) => KeyRoute::Palette, + match &ui.layers.active { + Some(ActiveLayer::Palette(_)) => KeyRoute::Palette, _ => KeyRoute::Global, } } @@ -27,11 +28,13 @@ pub(super) fn route_key(ui: &UiState) -> KeyRoute { pub(super) fn route_mouse( ui: &UiState, frame_layout: &FrameLayout, + app_layout: &AppLayout, mouse: MouseEvent, + has_gff: bool, ) -> MouseRoute { - match &ui.overlay.active_overlay { - Some(ActiveOverlay::Palette(_)) => MouseRoute::Palette, - Some(ActiveOverlay::Minimap(minimap_state)) => { + match &ui.layers.active { + Some(ActiveLayer::Palette(_)) => return MouseRoute::Palette, + Some(ActiveLayer::Minimap(minimap_state)) => { let left_mouse = matches!( mouse.kind, MouseEventKind::Down(MouseButton::Left) @@ -39,15 +42,76 @@ pub(super) fn route_mouse( | MouseEventKind::Up(MouseButton::Left) ); + let is_minimap_drag = minimap_state.is_dragging() + && matches!( + mouse.kind, + MouseEventKind::Drag(MouseButton::Left) | MouseEventKind::Up(MouseButton::Left) + ); + if (left_mouse && minimap_state.contains_mouse(mouse, frame_layout.overlay_area)) - || (matches!(mouse.kind, MouseEventKind::Up(MouseButton::Left)) - && minimap_state.is_dragging()) + || is_minimap_drag { - MouseRoute::Minimap - } else { - MouseRoute::Alignment + return MouseRoute::Minimap; } } - None => MouseRoute::Alignment, + None => (), + } + + if has_gff && app_layout.gff_pane_rows.height > 0 { + let in_gff = app_layout + .gff_pane_rows + .contains((mouse.column, mouse.row).into()); + let is_left_mouse = matches!( + mouse.kind, + MouseEventKind::Down(MouseButton::Left) + | MouseEventKind::Drag(MouseButton::Left) + | MouseEventKind::Up(MouseButton::Left) + ); + let is_hover = matches!(mouse.kind, MouseEventKind::Moved); + let is_drag = ui.gff_pane.is_dragging() + && matches!( + mouse.kind, + MouseEventKind::Drag(MouseButton::Left) | MouseEventKind::Up(MouseButton::Left) + ); + + if (in_gff && (is_left_mouse || is_hover)) || is_drag { + return MouseRoute::GffPane; + } + } + + MouseRoute::Alignment +} + +#[cfg(test)] +mod tests { + use crossterm::event::{KeyModifiers, MouseButton, MouseEvent, MouseEventKind}; + use ratatui::layout::Rect; + + use super::*; + use crate::cli::StartupState; + + fn ui_state() -> UiState { + UiState::new(StartupState { + file_path: None, + initial_position: 0, + }) + } + + #[test] + fn minimap_falls_through_to_gff_pane_outside_track() { + let mut ui = ui_state(); + ui.layers.toggle_minimap(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new(frame_layout.content_area, 5); + let mouse = MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: app_layout.gff_pane_rows.x, + row: app_layout.gff_pane_rows.y, + modifiers: KeyModifiers::empty(), + }; + + let route = route_mouse(&ui, &frame_layout, &app_layout, mouse, true); + + assert_eq!(route, MouseRoute::GffPane); } } diff --git a/salti/src/ui/layout.rs b/salti/src/ui/layout.rs index 0521d00..7ca83b1 100644 --- a/salti/src/ui/layout.rs +++ b/salti/src/ui/layout.rs @@ -68,11 +68,17 @@ pub struct AppLayout { pub alignment_pane_sequence_rows: Rect, pub consensus_sequence_id_pane: Rect, pub consensus_alignment_pane: Rect, + pub gff_info_pane: Rect, + pub gff_pane: Rect, + pub gff_pane_rows: Rect, } impl AppLayout { - pub fn new(content_area: Rect) -> Self { - let [alignment_area, consensus_area] = content_area + pub fn new(content_area: Rect, gff_height: u16) -> Self { + let [gff_area, main_area] = + content_area.layout(&vertical![==gff_height, *=1].spacing(Spacing::Overlap(1))); + + let [alignment_area, consensus_area] = main_area .layout(&vertical![*=1, ==CONSENSUS_PANE_HEIGHT_ROWS].spacing(Spacing::Overlap(1))); let [sequence_id_pane_area, alignment_pane_area] = alignment_area.layout( @@ -88,12 +94,32 @@ impl AppLayout { .inner(alignment_pane_area) .layout(&vertical![==RULER_HEIGHT_ROWS, *=1]); + let [gff_info_pane_area, gff_pane_area] = gff_area.layout( + &horizontal![==SEQUENCE_ID_PANE_WIDTH_PERCENT%, *=1].spacing(Spacing::Overlap(1)), + ); + let gff_pane_rows = if gff_pane_area.width > 2 && gff_pane_area.height > 2 { + ratatui::widgets::Block::bordered().inner(gff_pane_area) + } else { + Rect::default() + }; + Self { sequence_id_pane: sequence_id_pane_area, alignment_pane: alignment_pane_area, alignment_pane_sequence_rows: sequence_rows_area, consensus_sequence_id_pane: consensus_sequence_id_pane_area, consensus_alignment_pane: consensus_alignment_pane_area, + gff_info_pane: gff_info_pane_area, + gff_pane: gff_pane_area, + gff_pane_rows, } } } + +pub fn gff_pane_height(feature_row_count: usize) -> u16 { + if feature_row_count == 0 { + return 0; + } + let inner = u16::try_from(feature_row_count).unwrap_or(u16::MAX.saturating_sub(3)); + inner.saturating_add(3) +} diff --git a/salti/src/ui/mod.rs b/salti/src/ui/mod.rs index 5a2481f..62d6e33 100644 --- a/salti/src/ui/mod.rs +++ b/salti/src/ui/mod.rs @@ -1,4 +1,3 @@ -pub(crate) mod status_bars; pub(crate) mod layers; pub(crate) mod layout; pub(crate) mod panes; diff --git a/salti/src/ui/panes/alignment.rs b/salti/src/ui/panes/alignment.rs index 67725fa..22bc7e6 100644 --- a/salti/src/ui/panes/alignment.rs +++ b/salti/src/ui/panes/alignment.rs @@ -33,7 +33,6 @@ pub(crate) struct AlignmentPane<'a> { impl Widget for AlignmentPane<'_> { fn render(self, area: Rect, buf: &mut Buffer) { let block = Block::bordered() - .title("Alignment") .border_style(self.theme.styles.border) .style(self.theme.styles.base_block) .merge_borders(MergeStrategy::Exact); diff --git a/salti/src/ui/panes/gff.rs b/salti/src/ui/panes/gff.rs new file mode 100644 index 0000000..f03baa7 --- /dev/null +++ b/salti/src/ui/panes/gff.rs @@ -0,0 +1,661 @@ +use std::ops::Range; + +use crossterm::event::MouseEvent; +use ratatui::{ + buffer::Buffer, + layout::Rect, + style::Styled, + symbols::merge::MergeStrategy, + text::{Line, Span}, + widgets::{Block, Paragraph, Widget}, +}; + +use crate::{ + command::Command, + core::{ + gff::{Feature, Gff, Strand}, + model::AlignmentModel, + }, + input::movement::HorizontalDrag, + ui::ui_state::ThemeState, +}; + +const MIN_LABEL_WIDTH: usize = 2; +const NUCLEOTIDE_POSITIONS_PER_COL: usize = 1; +const PROTEIN_POSITIONS_PER_COL: usize = 3; + +pub(crate) struct GffPane<'a> { + pub(crate) gff: &'a Gff, + pub(crate) alignment: &'a AlignmentModel, + pub(crate) viewport_col_range: &'a Range, + pub(crate) theme: &'a ThemeState, +} + +impl Widget for GffPane<'_> { + fn render(self, area: Rect, buf: &mut Buffer) { + let block = Block::bordered() + .border_style(self.theme.styles.border) + .style(self.theme.styles.base_block) + .merge_borders(MergeStrategy::Exact); + let inner_area = if area.width > 2 && area.height > 2 { + block.inner(area) + } else { + Rect::default() + }; + block.render(area, buf); + + let track = + FeatureTrack::for_alignment(self.gff, self.alignment, usize::from(inner_area.width)); + let content_rows = Rect { + width: u16::try_from(track.width()).unwrap_or(u16::MAX), + ..inner_area + }; + if content_rows.width == 0 || content_rows.height == 0 || track.total_columns() == 0 { + return; + } + + let feature_rows = Rect { + height: content_rows.height.saturating_sub(1), + ..content_rows + }; + let navigation_row = Rect::new( + content_rows.x, + content_rows.y + feature_rows.height, + content_rows.width, + 1, + ); + + render_features(&track, feature_rows, self.theme, buf); + + let line = generate_scroll_line( + usize::from(navigation_row.width), + self.viewport_col_range, + track.total_columns(), + self.theme, + ); + Paragraph::new(line) + .style(self.theme.styles.base_block) + .render(navigation_row, buf); + } +} + +pub(crate) struct GffInfoPane<'a> { + pub(crate) tooltip: Option<&'a str>, + pub(crate) theme: &'a ThemeState, +} + +impl Widget for GffInfoPane<'_> { + fn render(self, area: Rect, buf: &mut Buffer) { + let block = Block::bordered() + .title(Line::from( + "Feature Info".set_style(self.theme.styles.text_muted), + )) + .border_style(self.theme.styles.border) + .style(self.theme.styles.base_block) + .merge_borders(MergeStrategy::Exact); + let inner_area = if area.width > 2 && area.height > 2 { + block.inner(area) + } else { + Rect::default() + }; + block.render(area, buf); + if inner_area.width == 0 || inner_area.height == 0 { + return; + } + + let lines: Vec> = match self.tooltip { + Some(tooltip) => tooltip + .lines() + .map(|line| Line::from(line.set_style(self.theme.styles.text))) + .collect(), + None => vec![Line::from( + "Hover over a feature".set_style(self.theme.styles.text_muted), + )], + }; + + Paragraph::new(lines) + .style(self.theme.styles.base_block) + .render(inner_area, buf); + } +} + +#[derive(Debug, Clone, Copy, Default)] +pub(crate) struct GffPaneState { + pan_drag: HorizontalDrag, +} + +impl GffPaneState { + pub(crate) fn handle_mouse( + &mut self, + mouse: MouseEvent, + gff_inner: Rect, + viewport_col_range: &Range, + alignment: &AlignmentModel, + ) -> Option { + let total_columns = FeatureTrack::total_columns_for_alignment(alignment); + self.pan_drag.handle_mouse( + mouse, + gff_content_area(gff_inner, total_columns), + viewport_col_range, + total_columns, + position_from_mouse, + ) + } + + pub(crate) fn is_dragging(&self) -> bool { + self.pan_drag.is_dragging() + } +} + +#[derive(Debug, Clone)] +struct FeatureMap { + total_columns: usize, + absolute_total_columns: usize, + offset: usize, + // proteins use three nucleotide positions per displayed column; nucleotides use one. + positions_to_col: usize, +} + +impl FeatureMap { + fn for_alignment(alignment: &AlignmentModel) -> Self { + let visible_columns = alignment.view().column_count(); + let absolute_total_columns = alignment.base().column_count(); + let frame_offset = alignment.translation_frame().offset(); + + if alignment.is_reloaded_as_protein() { + Self::protein(visible_columns, absolute_total_columns, frame_offset) + } else { + Self::nucleotide(visible_columns, absolute_total_columns) + } + } + + fn nucleotide(total_columns: usize, absolute_total_columns: usize) -> Self { + Self { + total_columns, + absolute_total_columns, + offset: 0, + positions_to_col: NUCLEOTIDE_POSITIONS_PER_COL, + } + } + + fn protein(total_columns: usize, absolute_total_columns: usize, frame_offset: usize) -> Self { + Self { + total_columns, + absolute_total_columns, + offset: frame_offset, + positions_to_col: PROTEIN_POSITIONS_PER_COL, + } + } + + fn map_feature(&self, view: &libmsa::Alignment, feature: &Feature) -> Option> { + let start = if feature.range.start < self.offset { + 0 + } else { + (feature.range.start - self.offset) / self.positions_to_col + }; + let end = if feature.range.end <= self.offset { + 0 + } else { + (feature.range.end - self.offset).div_ceil(self.positions_to_col) + }; + let clipped_range = + start.min(self.absolute_total_columns)..end.min(self.absolute_total_columns); + (!clipped_range.is_empty()).then_some(())?; + + view.relative_column_range_intersecting(clipped_range) + } +} + +pub(crate) fn tooltip_at( + gff: &Gff, + alignment: &AlignmentModel, + gff_inner: Rect, + mouse_x: u16, + mouse_y: u16, +) -> Option { + let track = FeatureTrack::for_alignment(gff, alignment, usize::from(gff_inner.width)); + if gff_inner.width == 0 || gff_inner.height == 0 || track.total_columns() == 0 { + return None; + } + let content_rows = Rect { + width: u16::try_from(track.width()).unwrap_or(u16::MAX), + ..gff_inner + }; + if !content_rows.contains((mouse_x, mouse_y).into()) { + return None; + } + + let feature_rows = Rect { + height: content_rows.height.saturating_sub(1), + ..content_rows + }; + if !feature_rows.contains((mouse_x, mouse_y).into()) { + return None; + } + + let row = usize::from(mouse_y - feature_rows.y); + let x = usize::from(mouse_x - feature_rows.x); + + track.feature_at(x, row).map(format_tooltip) +} + +pub(crate) fn feature_row_count(gff: &Gff, alignment: &AlignmentModel, width: usize) -> usize { + FeatureTrack::for_alignment(gff, alignment, width).row_count() +} + +fn gff_content_area(area: Rect, total_columns: usize) -> Rect { + let width = area + .width + .min(u16::try_from(total_columns).unwrap_or(u16::MAX)); + Rect { width, ..area } +} + +fn format_tooltip(feature: &Feature) -> String { + let length = feature.range.end.saturating_sub(feature.range.start); + format!( + "{} ({}) — {}\n{}-{} • {} nt", + feature.name, + feature.kind, + feature.strand, + feature.range.start + 1, + feature.range.end, + length, + ) +} + +fn render_features(track: &FeatureTrack<'_>, inner: Rect, theme: &ThemeState, buf: &mut Buffer) { + let width = usize::from(inner.width); + let max_row = usize::from(inner.height); + let foreground = theme.theme.sequence.foreground; + let dna = theme.theme.sequence.dna; + let palette = [dna.a, dna.t, dna.c, dna.g]; + let blank = (' ', theme.styles.base_block); + let mut cells = vec![blank; width * max_row]; + let mut feature_idx = 0; + + for placed_feature in track.placed_features() { + if placed_feature.row >= max_row { + continue; + } + + let feature = placed_feature.feature; + let feature_span = placed_feature.span.clone(); + let colour = palette[feature_idx % palette.len()]; + let feature_style = theme.styles.base_block.bg(colour); + let text_style = feature_style.fg(foreground); + feature_idx += 1; + + for x in feature_span.clone() { + let idx = placed_feature.row * width + x; + cells[idx] = (' ', feature_style); + } + + let available = feature_span.end - feature_span.start; + let (label_x, label_width, strand_arrow) = match feature.strand { + Strand::Forward if 0 < available => ( + feature_span.start, + available.saturating_sub(1), + Some((available - 1, '→')), + ), + Strand::Reverse if 0 < available => ( + feature_span.start + 1, + available.saturating_sub(1), + Some((0, '←')), + ), + Strand::Unknown | Strand::Forward | Strand::Reverse => { + (feature_span.start, available, None) + } + }; + + if let Some((arrow_offset, arrow)) = strand_arrow { + let x = feature_span.start + arrow_offset; + let idx = placed_feature.row * width + x; + cells[idx] = (arrow, text_style); + } + + if label_width >= MIN_LABEL_WIDTH { + let truncated_len = feature.name.chars().take(label_width).count(); + let label_offset = (label_width - truncated_len) / 2; + let label_start = label_x + label_offset; + for (i, ch) in feature.name.chars().take(label_width).enumerate() { + let x = label_start + i; + let idx = placed_feature.row * width + x; + cells[idx] = (ch, text_style); + } + } + } + + let lines: Vec> = cells + .chunks(width) + .map(|row| { + Line::from( + row.iter() + .map(|&(ch, style)| Span::styled(ch.to_string(), style)) + .collect::>(), + ) + }) + .collect(); + Paragraph::new(lines) + .style(theme.styles.base_block) + .render(inner, buf); +} + +#[derive(Debug, Clone)] +struct FeatureTrack<'a> { + placed_features: Vec>, + total_columns: usize, + width: usize, +} + +impl<'a> FeatureTrack<'a> { + fn for_alignment(gff: &'a Gff, alignment: &AlignmentModel, available_width: usize) -> Self { + let mapping = FeatureMap::for_alignment(alignment); + let width = available_width.min(mapping.total_columns); + let placed_features = placed_features(gff, alignment.view(), &mapping, width); + Self { + placed_features, + total_columns: mapping.total_columns, + width, + } + } + + fn total_columns_for_alignment(alignment: &AlignmentModel) -> usize { + FeatureMap::for_alignment(alignment).total_columns + } + + fn total_columns(&self) -> usize { + self.total_columns + } + + fn width(&self) -> usize { + self.width + } + + fn placed_features(&self) -> &[PlacedFeature<'a>] { + &self.placed_features + } + + fn row_count(&self) -> usize { + self.placed_features + .iter() + .map(|placed_feature| placed_feature.row + 1) + .max() + .unwrap_or(0) + } + + fn feature_at(&self, x: usize, row: usize) -> Option<&'a Feature> { + self.placed_features + .iter() + .find(|placed_feature| placed_feature.row == row && placed_feature.span.contains(&x)) + .map(|placed_feature| placed_feature.feature) + } +} + +#[derive(Debug, Clone)] +struct PlacedFeature<'a> { + feature: &'a Feature, + span: Range, + row: usize, +} + +fn placed_features<'a>( + gff: &'a Gff, + view: &libmsa::Alignment, + mapping: &FeatureMap, + width: usize, +) -> Vec> { + let mut res = Vec::new(); + let mut previous_span = None; + let mut alternating_row = 0; + let mut stack_offset = 0; + + for feature in &gff.features { + let Some(span) = feature_drawn_span(feature, view, mapping, width) else { + continue; + }; + + let row = match previous_span { + Some(previous_span) if previous_span == span => { + stack_offset += 1; + alternating_row + stack_offset + } + Some(_) | None => { + alternating_row = res.len() % 2; + stack_offset = 0; + alternating_row + } + }; + previous_span = Some(span.clone()); + res.push(PlacedFeature { feature, span, row }); + } + + res +} + +fn feature_drawn_span( + feature: &Feature, + view: &libmsa::Alignment, + mapping: &FeatureMap, + width: usize, +) -> Option> { + let screen_span = feature_screen_span(feature, view, mapping, width)?; + let drawn_width = if 1 < screen_span.end - screen_span.start { + screen_span.end - screen_span.start - 1 + } else { + screen_span.end - screen_span.start + }; + Some(screen_span.start..screen_span.start + drawn_width) +} + +fn feature_screen_span( + feature: &Feature, + view: &libmsa::Alignment, + mapping: &FeatureMap, + width: usize, +) -> Option> { + let total_columns = mapping.total_columns; + if width == 0 || total_columns == 0 { + return None; + } + + let mapped_span = mapping.map_feature(view, feature)?; + let x_start = mapped_span.start.saturating_mul(width) / total_columns; + let x_end = mapped_span + .end + .saturating_mul(width) + .div_ceil(total_columns) + .max(x_start + 1) + .min(width); + Some(x_start..x_end) +} + +fn scroll_bar_span( + width: usize, + viewport_col_range: &Range, + total_columns: usize, +) -> Option> { + if total_columns == 0 || width == 0 { + return None; + } + + let viewport_span = viewport_col_range + .end + .saturating_sub(viewport_col_range.start); + let thumb_width = viewport_span + .saturating_mul(width) + .div_ceil(total_columns) + .max(1) + .min(width); + let thumb_start = + (viewport_col_range.start.saturating_mul(width) / total_columns).min(width - thumb_width); + + Some(thumb_start..thumb_start + thumb_width) +} + +fn generate_scroll_line( + width: usize, + viewport_col_range: &Range, + total_columns: usize, + theme: &ThemeState, +) -> Line<'static> { + let thumb_span = scroll_bar_span(width, viewport_col_range, total_columns); + let spans: Vec> = (0..width) + .map(|x| { + if thumb_span.as_ref().is_some_and(|span| span.contains(&x)) { + Span::styled("▁", theme.styles.accent) + } else { + Span::styled(" ", theme.styles.base_block) + } + }) + .collect(); + Line::from(spans) +} + +fn position_from_mouse(mouse_x: u16, area: Rect, total_columns: usize) -> usize { + let offset = usize::from(mouse_x.saturating_sub(area.x)); + let width = usize::from(area.width); + let column = offset.saturating_mul(total_columns) / width; + column.min(total_columns.saturating_sub(1)) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn feature(start: usize, end: usize) -> Feature { + feature_with_name("gene", start, end) + } + + fn feature_with_name(name: &str, start: usize, end: usize) -> Feature { + Feature { + name: name.to_string(), + kind: crate::core::gff::FeatureType::Gene, + range: start..end + 1, + strand: Strand::Forward, + } + } + + fn raw(sequence: &[u8]) -> libmsa::RawSequence { + libmsa::RawSequence { + id: "seq".to_string(), + sequence: sequence.to_vec(), + } + } + + fn model_with_sequence(sequence: &[u8]) -> AlignmentModel { + let alignment = libmsa::Alignment::new(vec![raw(sequence)]).unwrap(); + AlignmentModel::new(alignment).unwrap() + } + + fn model_with_len(len: usize) -> AlignmentModel { + model_with_sequence(&vec![b'A'; len]) + } + + #[test] + fn filtered_nucleotide_mapping_collapses_hidden_columns() { + let mut model = model_with_sequence(b"-A-CC--G"); + model.set_gap_filter(Some(0.0)).unwrap(); + let mapping = FeatureMap::for_alignment(&model); + + assert_eq!( + model.view().absolute_column_ids().collect::>(), + vec![1, 3, 4, 7] + ); + assert_eq!( + mapping.map_feature(model.view(), &feature(2, 6)), + Some(1..3) + ); + } + + #[test] + fn filtered_nucleotide_mapping_hides_fully_filtered_feature() { + let mut model = model_with_sequence(b"-A-CC--G"); + model.set_gap_filter(Some(0.0)).unwrap(); + let mapping = FeatureMap::for_alignment(&model); + + assert_eq!(mapping.map_feature(model.view(), &feature(5, 6)), None); + } + + #[test] + fn filtered_protein_mapping_uses_projected_protein_columns() { + let mut model = model_with_sequence(b"M-M-M"); + model.set_gap_filter(Some(0.0)).unwrap(); + let mapping = FeatureMap::protein(3, 5, 0); + + assert_eq!( + model.view().absolute_column_ids().collect::>(), + vec![0, 2, 4] + ); + assert_eq!( + mapping.map_feature(model.view(), &feature(3, 8)), + Some(1..2) + ); + } + + #[test] + fn mapping_clips_feature_that_extends_past_alignment_end() { + let model = model_with_len(8); + let mapping = FeatureMap::for_alignment(&model); + + assert_eq!( + mapping.map_feature(model.view(), &feature(6, 10)), + Some(6..8) + ); + } + + #[test] + fn mapping_hides_feature_after_alignment_end() { + let model = model_with_len(8); + let mapping = FeatureMap::for_alignment(&model); + + assert_eq!(mapping.map_feature(model.view(), &feature(10, 12)), None); + } + + #[test] + fn placed_features_alternate_rows() { + let gff = Gff { + features: vec![feature(0, 1), feature(2, 3), feature(4, 5)], + }; + let model = model_with_len(6); + let mapping = FeatureMap::for_alignment(&model); + let rows: Vec = placed_features(&gff, model.view(), &mapping, 6) + .into_iter() + .map(|placed_feature| placed_feature.row) + .collect(); + + assert_eq!(rows, vec![0, 1, 0]); + assert_eq!(feature_row_count(&gff, &model, 6), 2); + } + + #[test] + fn tooltip_uses_stacked_feature_rows() { + let gff = Gff { + features: vec![ + feature_with_name("gene1", 0, 0), + feature_with_name("gene2", 1, 1), + ], + }; + let model = model_with_len(100); + let rows = Rect::new(10, 5, 1, 3); + + let tooltip = tooltip_at(&gff, &model, rows, 10, 6).unwrap(); + + assert!(tooltip.starts_with("gene2 ")); + } + + #[test] + fn content_area_shrinks_to_visible_columns() { + let area = Rect::new(10, 5, 100, 3); + + assert_eq!(gff_content_area(area, 12), Rect::new(10, 5, 12, 3)); + assert_eq!(gff_content_area(area, 120), area); + } + + #[test] + fn viewport_thumb_scales_with_visible_coordinate_span() { + let nucleotide = scroll_bar_span(12, &(0..4), 12).unwrap(); + let protein = scroll_bar_span(12, &(0..4), 6).unwrap(); + + assert!(nucleotide.len() < protein.len()); + } +} diff --git a/salti/src/ui/panes/mod.rs b/salti/src/ui/panes/mod.rs new file mode 100644 index 0000000..b41e104 --- /dev/null +++ b/salti/src/ui/panes/mod.rs @@ -0,0 +1,5 @@ +pub(crate) mod alignment; +pub(crate) mod consensus; +pub(crate) mod gff; +pub(crate) mod sequence_id; +pub(crate) mod status_bars; diff --git a/salti/src/ui/panes/sequence_id.rs b/salti/src/ui/panes/sequence_id.rs index 707a31a..7fa2004 100644 --- a/salti/src/ui/panes/sequence_id.rs +++ b/salti/src/ui/panes/sequence_id.rs @@ -21,7 +21,6 @@ pub(crate) struct SequenceIdPane<'a> { impl Widget for SequenceIdPane<'_> { fn render(self, area: Rect, buf: &mut Buffer) { let block = Block::bordered() - .title("Sequence Name") .border_style(self.theme.styles.border) .style(self.theme.styles.base_block) .merge_borders(MergeStrategy::Exact); diff --git a/salti/src/ui/render.rs b/salti/src/ui/render.rs index d63dfc5..d235509 100644 --- a/salti/src/ui/render.rs +++ b/salti/src/ui/render.rs @@ -1,11 +1,11 @@ use crate::{ - core::{model::AlignmentModel, stats_cache::ColumnStatsCache}, - overlay::render::render_overlays, + core::{gff::Gff, model::AlignmentModel, stats_cache::ColumnStatsCache}, + ui::layers::render::render_overlays, ui::{ layout::{AppLayout, FrameLayout}, panes::alignment::AlignmentPane, panes::consensus::{ConsensusAlignmentPane, ConsensusSequenceIdPane}, - panes::gff::{FeatureMap, render as render_gff_pane}, + panes::gff::{GffInfoPane, GffPane}, panes::sequence_id::SequenceIdPane, panes::status_bars::render_frame, selection::render_mouse_selection, @@ -14,196 +14,9 @@ use crate::{ }; use ratatui::Frame; use ratatui::layout::Rect; -use ratatui::style::Color::Rgb; use ratatui::style::{Styled, Stylize}; use ratatui::text::Line; -use ratatui::widgets::{Block, Paragraph}; - -const SELECTION_ROW_HIGHLIGHT_ALPHA: f32 = 0.3; -const SELECTION_ROW_TINT_ALPHA: f32 = 0.22; -const SELECTION_COL_HIGHLIGHT_ALPHA: f32 = 0.28; - -fn interpolate(from: u8, to: u8, alpha: f32) -> u8 { - let from = f32::from(from); - let to = f32::from(to); - (from + (to - from) * alpha).round().clamp(0.0, 255.0) as u8 -} - -fn blend_background( - base: ratatui::style::Color, - tint: ratatui::style::Color, - alpha: f32, -) -> ratatui::style::Color { - match (base, tint) { - (Rgb(red, green, blue), Rgb(red_tint, green_tint, blue_tint)) => Rgb( - interpolate(red, red_tint, alpha), - interpolate(green, green_tint, alpha), - interpolate(blue, blue_tint, alpha), - ), - _ => tint, - } -} - -fn shader( - f: &mut Frame, - clip_area: Rect, - tint_area: Rect, - tint: ratatui::style::Color, - alpha: f32, -) { - if alpha <= 0.0 || clip_area.width == 0 || clip_area.height == 0 { - return; - } - - let x_start = tint_area.x.max(clip_area.x); - let x_end = tint_area - .x - .saturating_add(tint_area.width) - .min(clip_area.x.saturating_add(clip_area.width)); - let y_start = tint_area.y.max(clip_area.y); - let y_end = tint_area - .y - .saturating_add(tint_area.height) - .min(clip_area.y.saturating_add(clip_area.height)); - if x_start >= x_end || y_start >= y_end { - return; - } - - let buffer = f.buffer_mut(); - for y in y_start..y_end { - for x in x_start..x_end { - if let Some(cell) = buffer.cell_mut((x, y)) { - cell.set_bg(blend_background(cell.bg, tint, alpha)); - } - } - } -} - -fn render_mouse_selection( - f: &mut Frame, - layout: &AppLayout, - alignment: &AlignmentModel, - ui: &UiState, - viewport: &crate::core::Viewport, -) { - let Some(selection) = ui.selection else { - return; - }; - - let window = viewport.window(); - let id_inner_area = Block::bordered().inner(layout.sequence_id_pane); - let sequence_rows_area = layout.alignment_pane_sequence_rows; - let id_content_y = id_inner_area.y + RULER_HEIGHT_ROWS; - let id_end_x = id_inner_area.x.saturating_add(id_inner_area.width); - let sequence_end_x = sequence_rows_area - .x - .saturating_add(sequence_rows_area.width); - let band_layout = pinned_section_layout( - alignment.rows().pinned().len(), - sequence_rows_area.height as usize, - ); - let (row_min, row_max) = selection_row_bounds(selection); - - for (row_offset, &absolute_row) in alignment - .rows() - .pinned() - .iter() - .take(band_layout.pinned_rendered) - .enumerate() - { - if !(row_min..=row_max).contains(&absolute_row) { - continue; - } - - let row_y = sequence_rows_area.y + row_offset as u16; - shader( - f, - id_inner_area, - Rect::new( - id_inner_area.x, - id_content_y + row_offset as u16, - id_end_x.saturating_sub(id_inner_area.x), - 1, - ), - ui.theme.theme.accent, - SELECTION_ROW_HIGHLIGHT_ALPHA, - ); - shader( - f, - sequence_rows_area, - Rect::new( - sequence_rows_area.x, - row_y, - sequence_end_x.saturating_sub(sequence_rows_area.x), - 1, - ), - ui.theme.theme.surface_bg, - SELECTION_ROW_TINT_ALPHA, - ); - } - - let scroll_start_y = sequence_rows_area.y - + band_layout.pinned_rendered as u16 - + band_layout.divider_height as u16; - for (row_offset, relative_row) in window.row_range.clone().enumerate() { - let Some(absolute_row) = alignment.view().absolute_row_id(relative_row) else { - continue; - }; - if !(row_min..=row_max).contains(&absolute_row) { - continue; - } - - let row_y = scroll_start_y + row_offset as u16; - shader( - f, - id_inner_area, - Rect::new( - id_inner_area.x, - id_content_y - + band_layout.pinned_rendered as u16 - + band_layout.divider_height as u16 - + row_offset as u16, - id_end_x.saturating_sub(id_inner_area.x), - 1, - ), - ui.theme.theme.accent, - SELECTION_ROW_HIGHLIGHT_ALPHA, - ); - shader( - f, - sequence_rows_area, - Rect::new( - sequence_rows_area.x, - row_y, - sequence_end_x.saturating_sub(sequence_rows_area.x), - 1, - ), - ui.theme.theme.surface_bg, - SELECTION_ROW_TINT_ALPHA, - ); - } - - if let Some(visible_col_range) = - selection_visible_col_range(selection, alignment, &window.col_range) - { - let start_x = - sequence_rows_area.x + (visible_col_range.start - window.col_range.start) as u16; - let end_x_exclusive = - sequence_rows_area.x + (visible_col_range.end - window.col_range.start) as u16; - shader( - f, - sequence_rows_area, - Rect::new( - start_x, - sequence_rows_area.y, - end_x_exclusive.saturating_sub(start_x), - sequence_rows_area.height, - ), - ui.theme.theme.panel_bg, - SELECTION_COL_HIGHLIGHT_ALPHA, - ); - } -} +use ratatui::widgets::Paragraph; fn render_empty_state_with_ui(f: &mut Frame, area: Rect, ui: &UiState) { let theme = &ui.theme; @@ -262,6 +75,7 @@ fn render_empty_state_with_ui(f: &mut Frame, area: Rect, ui: &UiState) { pub fn render( f: &mut Frame, alignment: Option<&AlignmentModel>, + gff: Option<&Gff>, ui: &UiState, stats_cache: &ColumnStatsCache, frame_layout: &FrameLayout, @@ -291,6 +105,25 @@ pub fn render( let window = ui.viewport.window(); + if let Some(gff) = gff { + f.render_widget( + GffInfoPane { + tooltip: ui.gff_tooltip.as_deref(), + theme: &ui.theme, + }, + layout.gff_info_pane, + ); + f.render_widget( + GffPane { + gff, + alignment, + viewport_col_range: &window.col_range, + theme: &ui.theme, + }, + layout.gff_pane, + ); + } + f.render_widget( SequenceIdPane { alignment, @@ -343,12 +176,12 @@ mod tests { use crate::cli::StartupState; use crate::core::model::{DiffMode, StatsView}; use crate::core::stats_cache::StatsJobResult; - use crate::overlay::command_palette::CommandPaletteState; - use crate::ui::notification::{Notification, NotificationLevel}; + use crate::ui::layers::notification::{Notification, NotificationLevel}; + use crate::ui::layers::palette::CommandPaletteState; use crate::ui::ui_state::MouseSelection; + use ratatui::Terminal; use ratatui::backend::TestBackend; use ratatui::buffer::Buffer; - use ratatui::Terminal; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -413,11 +246,19 @@ mod tests { let backend = TestBackend::new(area.width, area.height); let mut terminal = Terminal::new(backend).unwrap(); let frame_layout = FrameLayout::new(area); - let layout = AppLayout::new(frame_layout.content_area); + let layout = AppLayout::new(frame_layout.content_area, 0); terminal .draw(|frame| { - render(frame, alignment, ui, stats_cache, &frame_layout, &layout); + render( + frame, + alignment, + None, + ui, + stats_cache, + &frame_layout, + &layout, + ); }) .unwrap(); @@ -452,7 +293,7 @@ mod tests { fn set_viewport(ui: &mut UiState, alignment: &AlignmentModel, area: Rect) { let frame_layout = FrameLayout::new(area); - let layout = AppLayout::new(frame_layout.content_area); + let layout = AppLayout::new(frame_layout.content_area, 0); ui.viewport.update_dimensions( layout.alignment_pane_sequence_rows.width as usize, layout.alignment_pane_sequence_rows.height as usize, @@ -503,7 +344,10 @@ mod tests { let mut ui = ui_state(); set_viewport(&mut ui, &alignment, area); - insta::assert_snapshot!("render_loaded_basic", render_text(Some(&alignment), &ui, &metrics, area)); + insta::assert_snapshot!( + "render_loaded_basic", + render_text(Some(&alignment), &ui, &metrics, area) + ); let mut selection_ui = ui_state(); set_viewport(&mut selection_ui, &alignment, area); @@ -528,9 +372,15 @@ mod tests { raw("seq3", b"CATCATCATCATGATCAT"), ]); alignment.set_reference(0).unwrap(); - alignment.set_translation(Some(libmsa::ReadingFrame::Frame1)).unwrap(); + alignment + .set_translation(Some(libmsa::ReadingFrame::Frame1)) + .unwrap(); alignment.diff_mode = DiffMode::Reference; - let metrics = metrics_with(StatsView::Translated(libmsa::ReadingFrame::Frame1), b"HHHHHH", Some(1.0)); + let metrics = metrics_with( + StatsView::Translated(libmsa::ReadingFrame::Frame1), + b"HHHHHH", + Some(1.0), + ); let mut ui = ui_state(); set_viewport(&mut ui, &alignment, area); @@ -571,7 +421,7 @@ mod tests { let metrics = metrics_with(StatsView::Raw, b"CATCATCATCATCATCAT", Some(1.0)); let mut ui = ui_state(); set_viewport(&mut ui, &alignment, area); - ui.overlay.open_palette(CommandPaletteState::empty()); + ui.layers.open_palette(CommandPaletteState::empty()); insta::assert_snapshot!( "render_command_palette", @@ -587,10 +437,14 @@ mod tests { raw("seq2", b"CATCATCATCATCATCATCATCATCATCATCATCAT"), raw("seq3", b"CATCATCATCATCATCATCATCATCATCATCATCAT"), ]); - let metrics = metrics_with(StatsView::Raw, b"CATCATCATCATCATCATCATCATCATCATCATCAT", Some(1.0)); + let metrics = metrics_with( + StatsView::Raw, + b"CATCATCATCATCATCATCATCATCATCATCATCAT", + Some(1.0), + ); let mut ui = ui_state(); set_viewport(&mut ui, &alignment, area); - ui.overlay.toggle_minimap(); + ui.layers.toggle_minimap(); insta::assert_snapshot!( "render_minimap", diff --git a/salti/src/ui/rows.rs b/salti/src/ui/rows.rs index bb8dc9a..9004ff7 100644 --- a/salti/src/ui/rows.rs +++ b/salti/src/ui/rows.rs @@ -176,7 +176,6 @@ fn format_translated_spans( spans } -/// Collects visible bytes from a sequence view for the given relative column range. pub fn visible_bytes(sequence: libmsa::RowView<'_>, col_range: &Range) -> Vec { if col_range.is_empty() { return Vec::new(); diff --git a/salti/src/ui/selection.rs b/salti/src/ui/selection.rs index d88714f..3978b37 100644 --- a/salti/src/ui/selection.rs +++ b/salti/src/ui/selection.rs @@ -17,10 +17,6 @@ const SELECTION_ROW_HIGHLIGHT_ALPHA: f32 = 0.3; const SELECTION_ROW_TINT_ALPHA: f32 = 0.22; const SELECTION_COL_HIGHLIGHT_ALPHA: f32 = 0.28; -/// Maps a screen-space mouse position to `(absolute_row, absolute_column)`. -/// -/// Returns `None` when the click falls outside `sequence_rows_area`, on the -/// pinned-row divider, or beyond the alignment bounds. pub fn selection_point_crosshair( alignment: &AlignmentModel, viewport: &Viewport, @@ -193,9 +189,6 @@ pub fn render_mouse_selection( } } -/// Converts a selection (absolute columns) to a visible-column range clipped -/// to `visible_col_range`. In translation mode, expands to full codon -/// boundaries. Returns `None` when the selection does not overlap the viewport. pub fn selection_visible_col_range( selection: MouseSelection, alignment: &AlignmentModel, @@ -510,11 +503,9 @@ mod tests { viewport.set_bounds(3, 4, 2); let area = Rect::new(0, 0, 4, 3); - // No pinned rows, so row 0 maps to absolute row 0. let result = selection_point_crosshair(&model, &viewport, area, 0, 0); assert_eq!(result, Some((0, 0))); - // Row 2, col 3. let result = selection_point_crosshair(&model, &viewport, area, 3, 2); assert_eq!(result, Some((2, 3))); } @@ -523,25 +514,18 @@ mod tests { fn crosshair_handles_pinned_band() { let mut model = alignment_model(&["s1", "s2", "s3", "s4"]); model.pin(0).expect("should pin"); - // View now has rows [1, 2, 3] (row 0 excluded). - // Pinned band: 1 row (row 0). - // Divider: 1 row. - // Scrollable: remaining rows. let mut viewport = Viewport::default(); viewport.update_dimensions(4, 2, 2); viewport.set_bounds(3, 4, 2); let area = Rect::new(0, 0, 4, 4); - // Row offset 0 -> pinned row 0 -> absolute row 0. let result = selection_point_crosshair(&model, &viewport, area, 0, 0); assert_eq!(result, Some((0, 0))); - // Row offset 1 -> divider -> None. let result = selection_point_crosshair(&model, &viewport, area, 0, 1); assert!(result.is_none()); - // Row offset 2 -> scrollable row 0 -> view relative 0 -> absolute row 1. let result = selection_point_crosshair(&model, &viewport, area, 0, 2); assert_eq!(result, Some((1, 0))); } diff --git a/salti/src/ui/ui_state.rs b/salti/src/ui/ui_state.rs index 4392c96..7b4b264 100644 --- a/salti/src/ui/ui_state.rs +++ b/salti/src/ui/ui_state.rs @@ -4,8 +4,7 @@ use crate::{ EVERFOREST_DARK, Theme, ThemeId, ThemeStyles, build_theme_styles, theme_from_id, }, core::Viewport, - overlay::overlay_state::OverlayState, - ui::notification::Notification, + ui::{layers::notification::Notification, layers::state::LayerState, panes::gff::GffPaneState}, }; #[derive(Debug, Clone, PartialEq, Eq, Default)] @@ -45,19 +44,11 @@ impl From for MetaState { } } -/// Mouse selection stored in absolute row and absolute column coordinates. -/// -/// These survive filter and view changes because they refer to the underlying -/// alignment data, not the current projection. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct MouseSelection { - /// Absolute row index of the selection anchor. pub sequence_id: usize, - /// Absolute column index of the selection anchor. pub column: usize, - /// Absolute row index of the selection end-point. pub end_sequence_id: usize, - /// Absolute column index of the selection end-point. pub end_column: usize, } @@ -79,23 +70,27 @@ impl Default for ThemeState { #[derive(Debug)] pub struct UiState { - pub(crate) overlay: OverlayState, + pub(crate) layers: LayerState, + pub(crate) gff_pane: GffPaneState, pub notification: Option, pub selection: Option, pub theme: ThemeState, pub viewport: Viewport, pub meta: MetaState, + pub gff_tooltip: Option, } impl UiState { pub fn new(startup: StartupState) -> Self { Self { - overlay: OverlayState::default(), + layers: LayerState::default(), + gff_pane: GffPaneState::default(), notification: None, selection: None, theme: ThemeState::default(), viewport: Viewport::default(), meta: MetaState::from(startup), + gff_tooltip: None, } } @@ -109,7 +104,7 @@ impl UiState { pub fn clear_transient_state(&mut self) { self.selection = None; - self.overlay.close(); + self.layers.close_active(); self.notification = None; } } From 3edc6fac96fa7474f6c5ab54e448193911b21f6c Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Tue, 12 May 2026 22:49:00 +0100 Subject: [PATCH 31/48] feat(salti): add jump-feature command --- salti/src/app.rs | 2 +- salti/src/input/mouse.rs | 5 +- .../ui/layers/palette/command_definitions.rs | 16 +- .../src/ui/layers/palette/command_runners.rs | 165 +++++++++++++++++- salti/src/ui/layers/palette/completers.rs | 55 ++++++ salti/src/ui/layers/palette/input.rs | 115 +++++++++--- salti/src/ui/panes/gff.rs | 108 +++++++----- 7 files changed, 384 insertions(+), 82 deletions(-) diff --git a/salti/src/app.rs b/salti/src/app.rs index eed4004..8eaa2f5 100644 --- a/salti/src/app.rs +++ b/salti/src/app.rs @@ -552,7 +552,7 @@ impl App { let palette = self .alignment .as_ref() - .map(CommandPaletteState::from_alignment) + .map(|alignment| CommandPaletteState::from_alignment(alignment, self.gff.as_ref())) .unwrap_or_else(CommandPaletteState::empty); self.ui.layers.open_palette(palette); } diff --git a/salti/src/input/mouse.rs b/salti/src/input/mouse.rs index 54f8fea..2d490f0 100644 --- a/salti/src/input/mouse.rs +++ b/salti/src/input/mouse.rs @@ -384,6 +384,9 @@ mod tests { ); assert!(commands.is_empty()); - assert_eq!(ui.gff_tooltip.as_deref(), Some("gene (gene) — Forward →\n1-10 • 10 nt")); + assert_eq!( + ui.gff_tooltip.as_deref(), + Some("gene (gene) — Forward →\n1-10 • 10 nt") + ); } } diff --git a/salti/src/ui/layers/palette/command_definitions.rs b/salti/src/ui/layers/palette/command_definitions.rs index c3516d4..9bd5267 100644 --- a/salti/src/ui/layers/palette/command_definitions.rs +++ b/salti/src/ui/layers/palette/command_definitions.rs @@ -1,9 +1,9 @@ use super::command_runners::{ run_check_update, run_clear_filter, run_clear_reference, run_consensus_method, run_diff_mode, - run_filter_constant, run_filter_gaps, run_filter_rows, run_jump_position, run_jump_sequence, - run_load_alignment, run_load_gff, run_pin_sequence, run_quit, run_reload_as_protein, - run_set_active_type, run_set_reference, run_theme, run_toggle_translation, - run_translation_frame, run_unpin_sequence, + run_filter_constant, run_filter_gaps, run_filter_rows, run_jump_feature, run_jump_position, + run_jump_sequence, run_load_alignment, run_load_gff, run_pin_sequence, run_quit, + run_reload_as_protein, run_set_active_type, run_set_reference, run_theme, + run_toggle_translation, run_translation_frame, run_unpin_sequence, }; use super::command_spec::{PaletteCommand, StaticCommand, TypableCommand}; use super::completers; @@ -38,6 +38,14 @@ pub(super) const COMMAND_SPECS: &[PaletteCommand] = &[ static_candidates: &[], run: run_jump_sequence, }), + PaletteCommand::Typable(TypableCommand { + name: "jump-feature", + help_text: "Jump to a GFF feature by name.", + aliases: &["jf"], + completer: Some(completers::features), + static_candidates: &[], + run: run_jump_feature, + }), PaletteCommand::Typable(TypableCommand { name: "pin-sequence", help_text: "Pin a sequence to the top of the alignment pane.", diff --git a/salti/src/ui/layers/palette/command_runners.rs b/salti/src/ui/layers/palette/command_runners.rs index d5fb5a9..5db25dc 100644 --- a/salti/src/ui/layers/palette/command_runners.rs +++ b/salti/src/ui/layers/palette/command_runners.rs @@ -188,6 +188,30 @@ pub(super) fn run_jump_sequence( }) } +pub(super) fn run_jump_feature( + state: &CommandPaletteState, + arguments: &str, +) -> anyhow::Result { + run_command("jump-feature", arguments, || { + let feature_name = require_argument(arguments)?; + let Some(gff_feature_targets) = state.gff_feature_targets.as_ref() else { + return Err(format_err!("No GFF file loaded")); + }; + let Some(feature_target) = gff_feature_targets + .iter() + .find(|feature_target| feature_target.feature_name.as_ref() == feature_name) + else { + return Err(format_err!("Feature not found: {feature_name}")); + }; + let Some(target_col) = feature_target.target_col else { + return Err(format_err!( + "No visible column at or after the requested position", + )); + }; + Ok(Command::JumpToPosition(target_col)) + }) +} + pub(super) fn run_pin_sequence( state: &CommandPaletteState, arguments: &str, @@ -328,16 +352,145 @@ pub(super) fn run_load_gff(_: &CommandPaletteState, arguments: &str) -> anyhow:: #[cfg(test)] mod tests { + use std::ops::Range; + + use crate::core::gff::{Feature, FeatureType, Gff, Strand}; + use crate::core::model::AlignmentModel; + use crate::ui::layers::palette::input::{CommandPaletteSnapshot, GffFeatureTarget}; + use super::*; + fn raw(sequence: &[u8]) -> libmsa::RawSequence { + libmsa::RawSequence { + id: "seq".to_string(), + sequence: sequence.to_vec(), + } + } + + fn gff_feature(name: &str, range: Range) -> Feature { + Feature { + name: name.to_string(), + kind: FeatureType::Gene, + range, + strand: Strand::Forward, + } + } + + fn model_with_sequence(sequence: &[u8]) -> AlignmentModel { + let alignment = libmsa::Alignment::new(vec![raw(sequence)]).unwrap(); + AlignmentModel::new(alignment).unwrap() + } + fn palette_state_with_columns(visible_columns: Vec) -> CommandPaletteState { - CommandPaletteState::new( - Vec::new(), - Vec::new(), - libmsa::AlignmentType::Dna, - false, + CommandPaletteState::new(CommandPaletteSnapshot { + selectable_sequences: Vec::new(), + pinned_sequences: Vec::new(), + active_type: libmsa::AlignmentType::Dna, + is_reloaded_as_protein: false, visible_columns, - ) + gff_feature_targets: None, + }) + } + + fn palette_state_with_gff_features(gff_features: Vec) -> CommandPaletteState { + CommandPaletteState::new(CommandPaletteSnapshot { + selectable_sequences: Vec::new(), + pinned_sequences: Vec::new(), + active_type: libmsa::AlignmentType::Dna, + is_reloaded_as_protein: false, + visible_columns: vec![0, 1, 2], + gff_feature_targets: Some(gff_features), + }) + } + + #[test] + fn jump_feature_returns_the_first_matching_feature_target() { + let state = palette_state_with_gff_features(vec![ + GffFeatureTarget { + feature_name: "gene-a".into(), + target_col: Some(2), + }, + GffFeatureTarget { + feature_name: "gene-a".into(), + target_col: Some(1), + }, + ]); + + let action = run_jump_feature(&state, "gene-a") + .expect("jump-feature should use the first matching feature in GFF order"); + + assert_eq!(action, Command::JumpToPosition(2)); + } + + #[test] + fn jump_feature_errors_when_no_gff_is_loaded() { + let state = palette_state_with_columns(vec![0, 1, 2]); + + let error = + run_jump_feature(&state, "gene-a").expect_err("jump-feature should require a GFF"); + + assert_eq!(error.to_string(), "No GFF file loaded"); + } + + #[test] + fn jump_feature_errors_when_the_feature_name_is_missing() { + let state = palette_state_with_gff_features(vec![GffFeatureTarget { + feature_name: "gene-a".into(), + target_col: Some(2), + }]); + + let error = run_jump_feature(&state, "gene-b") + .expect_err("jump-feature should reject unknown feature names"); + + assert_eq!(error.to_string(), "Feature not found: gene-b"); + } + + #[test] + fn jump_feature_uses_the_first_visible_column_inside_the_feature() { + let mut model = model_with_sequence(b"-A-CC--G"); + model.set_gap_filter(Some(0.0)).unwrap(); + let gff = Gff { + features: vec![gff_feature("gene-a", 2..6)], + }; + let state = CommandPaletteState::from_alignment(&model, Some(&gff)); + + let action = run_jump_feature(&state, "gene-a") + .expect("jump-feature should use the first visible feature column"); + + assert_eq!(action, Command::JumpToPosition(1)); + } + + #[test] + fn jump_feature_errors_when_all_feature_columns_are_hidden() { + let mut model = model_with_sequence(b"-A-CC--G"); + model.set_gap_filter(Some(0.0)).unwrap(); + let gff = Gff { + features: vec![gff_feature("gene-a", 5..7)], + }; + let state = CommandPaletteState::from_alignment(&model, Some(&gff)); + + let error = run_jump_feature(&state, "gene-a") + .expect_err("jump-feature should not jump outside the requested feature"); + + assert_eq!( + error.to_string(), + "No visible column at or after the requested position" + ); + } + + #[test] + fn jump_feature_maps_nucleotide_coordinates_into_reloaded_protein_columns() { + let mut model = model_with_sequence(b"ATGAAATTT"); + model.toggle_reload_as_protein(None).unwrap(); + let gff = Gff { + features: vec![gff_feature("gene-a", 3..9)], + }; + let state = CommandPaletteState::from_alignment(&model, Some(&gff)); + + let action = run_jump_feature(&state, "gene-a") + .expect("jump-feature should map into the current protein view"); + + assert_eq!(action, Command::JumpToPosition(1)); } #[test] diff --git a/salti/src/ui/layers/palette/completers.rs b/salti/src/ui/layers/palette/completers.rs index 217481c..1553bef 100644 --- a/salti/src/ui/layers/palette/completers.rs +++ b/salti/src/ui/layers/palette/completers.rs @@ -18,6 +18,18 @@ pub(super) fn pinned_sequences(state: &CommandPaletteState, _: &str) -> Vec Vec { + state + .gff_feature_targets + .as_deref() + .map_or_else(Vec::new, |gff_feature_targets| { + gff_feature_targets + .iter() + .map(|gff_feature_target| gff_feature_target.feature_name.to_string()) + .collect() + }) +} + pub(super) fn filter_matches(state: &CommandPaletteState, arguments: &str) -> Vec { let regex_text = arguments.trim(); if regex_text.is_empty() { @@ -97,3 +109,46 @@ pub(super) fn filename(_: &CommandPaletteState, arguments: &str) -> Vec matches.sort(); matches.into_iter().map(|(_, label)| label).collect() } + +#[cfg(test)] +mod tests { + use super::*; + + use crate::ui::layers::palette::input::{CommandPaletteSnapshot, GffFeatureTarget}; + + fn palette_state_with_gff_features( + gff_feature_targets: Option>, + ) -> CommandPaletteState { + CommandPaletteState::new(CommandPaletteSnapshot { + selectable_sequences: Vec::new(), + pinned_sequences: Vec::new(), + active_type: libmsa::AlignmentType::Dna, + is_reloaded_as_protein: false, + visible_columns: vec![0, 1, 2], + gff_feature_targets, + }) + } + + #[test] + fn features_returns_gff_feature_names_in_gff_order() { + let state = palette_state_with_gff_features(Some(vec![ + GffFeatureTarget { + feature_name: "gene-b".into(), + target_col: Some(1), + }, + GffFeatureTarget { + feature_name: "gene-a".into(), + target_col: Some(2), + }, + ])); + + assert_eq!(features(&state, ""), vec!["gene-b", "gene-a"]); + } + + #[test] + fn features_returns_an_empty_list_without_a_gff() { + let state = palette_state_with_gff_features(None); + + assert!(features(&state, "").is_empty()); + } +} diff --git a/salti/src/ui/layers/palette/input.rs b/salti/src/ui/layers/palette/input.rs index 21f7279..72919f7 100644 --- a/salti/src/ui/layers/palette/input.rs +++ b/salti/src/ui/layers/palette/input.rs @@ -5,9 +5,11 @@ use crossterm::event::{KeyCode, KeyEvent}; use libmsa::AlignmentType; use crate::command::Command; +use crate::core::gff::Gff; use crate::core::model::AlignmentModel; use crate::core::search::{Direction, FilterMode, SearchableList}; use crate::ui::layers::notification::{Notification, NotificationLevel}; +use crate::ui::panes::gff::FeatureMap; use super::command_definitions::COMMAND_SPECS; use super::command_spec::{PaletteCommand, TypableCommand}; @@ -25,6 +27,21 @@ pub struct VisibleSequence { pub sequence_name: Arc, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct GffFeatureTarget { + pub(crate) feature_name: Arc, + pub(crate) target_col: Option, +} + +pub(crate) struct CommandPaletteSnapshot { + pub(crate) selectable_sequences: Vec, + pub(crate) pinned_sequences: Vec, + pub(crate) active_type: AlignmentType, + pub(crate) is_reloaded_as_protein: bool, + pub(crate) visible_columns: Vec, + pub(crate) gff_feature_targets: Option>, +} + #[derive(Debug)] pub struct CommandPaletteState { pub(super) command_input: String, @@ -37,19 +54,21 @@ pub struct CommandPaletteState { pub(super) active_type: AlignmentType, pub(super) is_reloaded_as_protein: bool, pub(super) visible_columns: Vec, + pub(super) gff_feature_targets: Option>, } impl CommandPaletteState { pub fn empty() -> Self { - Self::new( - Vec::new(), - Vec::new(), - libmsa::AlignmentType::Generic, - false, - Vec::new(), - ) + Self::new(CommandPaletteSnapshot { + selectable_sequences: Vec::new(), + pinned_sequences: Vec::new(), + active_type: libmsa::AlignmentType::Generic, + is_reloaded_as_protein: false, + visible_columns: Vec::new(), + gff_feature_targets: None, + }) } - pub fn from_alignment(alignment: &AlignmentModel) -> Self { + pub fn from_alignment(alignment: &AlignmentModel, gff: Option<&Gff>) -> Self { let mut selectable_sequences: Vec = (0..alignment.view().row_count()) .filter_map(|rel| { let sequence = alignment.view().sequence(rel)?; @@ -82,22 +101,39 @@ impl CommandPaletteState { }) .collect(); - Self::new( + let gff_feature_targets = gff.map(|gff| { + let mapping = FeatureMap::for_alignment(alignment); + gff.features + .iter() + .map(|feature| GffFeatureTarget { + feature_name: feature.name.as_str().into(), + target_col: mapping + .map_feature(alignment.view(), feature) + .map(|range| range.start), + }) + .collect() + }); + + Self::new(CommandPaletteSnapshot { selectable_sequences, pinned_sequences, - alignment.base().active_type(), - alignment.is_reloaded_as_protein(), - alignment.view().absolute_column_ids().collect(), - ) + active_type: alignment.base().active_type(), + is_reloaded_as_protein: alignment.is_reloaded_as_protein(), + visible_columns: alignment.view().absolute_column_ids().collect(), + gff_feature_targets, + }) } - pub fn new( - selectable_sequences: Vec, - pinned_sequences: Vec, - active_type: AlignmentType, - is_reloaded_as_protein: bool, - visible_columns: Vec, - ) -> Self { + pub(crate) fn new(init: CommandPaletteSnapshot) -> Self { + let CommandPaletteSnapshot { + selectable_sequences, + pinned_sequences, + active_type, + is_reloaded_as_protein, + visible_columns, + gff_feature_targets, + } = init; + let mut command_list = SearchableList::new(FilterMode::Fuzzy, None); command_list.set_items(display_command_names()); let completion_list = SearchableList::new(FilterMode::Fuzzy, None); @@ -113,6 +149,7 @@ impl CommandPaletteState { active_type, is_reloaded_as_protein, visible_columns, + gff_feature_targets, } } @@ -415,13 +452,14 @@ mod tests { #[test] fn submit_returns_expected_command() { - let mut palette = CommandPaletteState::new( - Vec::new(), - Vec::new(), - libmsa::AlignmentType::Dna, - false, - vec![0, 3, 4], - ); + let mut palette = CommandPaletteState::new(CommandPaletteSnapshot { + selectable_sequences: Vec::new(), + pinned_sequences: Vec::new(), + active_type: libmsa::AlignmentType::Dna, + is_reloaded_as_protein: false, + visible_columns: vec![0, 3, 4], + gff_feature_targets: None, + }); palette.command_input = "jump-position 2".to_string(); let commands = palette.handle_key_event(key(KeyCode::Enter)); @@ -432,6 +470,29 @@ mod tests { ); } + #[test] + fn submit_jump_feature_alias_returns_the_expected_command() { + let mut palette = CommandPaletteState::new(CommandPaletteSnapshot { + selectable_sequences: Vec::new(), + pinned_sequences: Vec::new(), + active_type: libmsa::AlignmentType::Dna, + is_reloaded_as_protein: false, + visible_columns: vec![0, 1, 2], + gff_feature_targets: Some(vec![GffFeatureTarget { + feature_name: "gene-a".into(), + target_col: Some(2), + }]), + }); + palette.command_input = "jf gene-a".to_string(); + + let commands = palette.handle_key_event(key(KeyCode::Enter)); + + assert_eq!( + commands, + vec![Command::JumpToPosition(2), Command::CloseOverlay] + ); + } + #[test] fn submit_success_appends_close_command_palette() { let mut palette = CommandPaletteState::empty(); diff --git a/salti/src/ui/panes/gff.rs b/salti/src/ui/panes/gff.rs index f03baa7..7684d46 100644 --- a/salti/src/ui/panes/gff.rs +++ b/salti/src/ui/panes/gff.rs @@ -147,8 +147,8 @@ impl GffPaneState { } } -#[derive(Debug, Clone)] -struct FeatureMap { +#[derive(Debug, Clone, Copy)] +pub(crate) struct FeatureMap { total_columns: usize, absolute_total_columns: usize, offset: usize, @@ -157,13 +157,15 @@ struct FeatureMap { } impl FeatureMap { - fn for_alignment(alignment: &AlignmentModel) -> Self { + pub(crate) fn for_alignment(alignment: &AlignmentModel) -> Self { let visible_columns = alignment.view().column_count(); let absolute_total_columns = alignment.base().column_count(); - let frame_offset = alignment.translation_frame().offset(); - if alignment.is_reloaded_as_protein() { - Self::protein(visible_columns, absolute_total_columns, frame_offset) + Self::protein( + visible_columns, + absolute_total_columns, + alignment.translation_frame().offset(), + ) } else { Self::nucleotide(visible_columns, absolute_total_columns) } @@ -187,22 +189,25 @@ impl FeatureMap { } } - fn map_feature(&self, view: &libmsa::Alignment, feature: &Feature) -> Option> { - let start = if feature.range.start < self.offset { - 0 - } else { - (feature.range.start - self.offset) / self.positions_to_col - }; - let end = if feature.range.end <= self.offset { - 0 - } else { - (feature.range.end - self.offset).div_ceil(self.positions_to_col) - }; + pub(crate) fn map_feature( + &self, + view: &libmsa::Alignment, + feature: &Feature, + ) -> Option> { + let absolute_range = self.map_feature_absolute_range(feature)?; + view.relative_column_range_intersecting(absolute_range) + } + + fn map_feature_absolute_range(&self, feature: &Feature) -> Option> { + let start = feature.range.start.saturating_sub(self.offset) / self.positions_to_col; + let end = feature + .range + .end + .saturating_sub(self.offset) + .div_ceil(self.positions_to_col); let clipped_range = start.min(self.absolute_total_columns)..end.min(self.absolute_total_columns); - (!clipped_range.is_empty()).then_some(())?; - - view.relative_column_range_intersecting(clipped_range) + (!clipped_range.is_empty()).then_some(clipped_range) } } @@ -251,7 +256,7 @@ fn gff_content_area(area: Rect, total_columns: usize) -> Rect { } fn format_tooltip(feature: &Feature) -> String { - let length = feature.range.end.saturating_sub(feature.range.start); + let length = feature.range.len(); format!( "{} ({}) — {}\n{}-{} • {} nt", feature.name, @@ -328,11 +333,23 @@ fn render_features(track: &FeatureTrack<'_>, inner: Rect, theme: &ThemeState, bu let lines: Vec> = cells .chunks(width) .map(|row| { - Line::from( - row.iter() - .map(|&(ch, style)| Span::styled(ch.to_string(), style)) - .collect::>(), - ) + let mut spans = Vec::new(); + let mut text = String::new(); + let mut current_style = row[0].1; + + for &(ch, style) in row { + if style != current_style && !text.is_empty() { + spans.push(Span::styled(std::mem::take(&mut text), current_style)); + current_style = style; + } + text.push(ch); + } + + if !text.is_empty() { + spans.push(Span::styled(text, current_style)); + } + + Line::from(spans) }) .collect(); Paragraph::new(lines) @@ -405,7 +422,6 @@ fn placed_features<'a>( width: usize, ) -> Vec> { let mut res = Vec::new(); - let mut previous_span = None; let mut alternating_row = 0; let mut stack_offset = 0; @@ -414,18 +430,17 @@ fn placed_features<'a>( continue; }; - let row = match previous_span { - Some(previous_span) if previous_span == span => { - stack_offset += 1; - alternating_row + stack_offset - } - Some(_) | None => { - alternating_row = res.len() % 2; - stack_offset = 0; - alternating_row - } + let same_as_previous = res + .last() + .is_some_and(|placed_feature: &PlacedFeature<'_>| placed_feature.span == span); + let row = if same_as_previous { + stack_offset += 1; + alternating_row + stack_offset + } else { + alternating_row = res.len() % 2; + stack_offset = 0; + alternating_row }; - previous_span = Some(span.clone()); res.push(PlacedFeature { feature, span, row }); } @@ -439,11 +454,7 @@ fn feature_drawn_span( width: usize, ) -> Option> { let screen_span = feature_screen_span(feature, view, mapping, width)?; - let drawn_width = if 1 < screen_span.end - screen_span.start { - screen_span.end - screen_span.start - 1 - } else { - screen_span.end - screen_span.start - }; + let drawn_width = screen_span.len().saturating_sub(1).max(1); Some(screen_span.start..screen_span.start + drawn_width) } @@ -592,6 +603,17 @@ mod tests { ); } + #[test] + fn protein_mapping_clips_feature_before_frame_offset() { + let model = model_with_len(5); + let mapping = FeatureMap::protein(3, 5, 2); + + assert_eq!( + mapping.map_feature(model.view(), &feature(0, 4)), + Some(0..1) + ); + } + #[test] fn mapping_clips_feature_that_extends_past_alignment_end() { let model = model_with_len(8); From 660382b3115cf0ccbbacdd994c5d2a064143d088 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 07:16:00 +0100 Subject: [PATCH 32/48] chore: add rustfmt toml --- rustfmt.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 rustfmt.toml diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..455c820 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,2 @@ +imports_granularity = "Crate" +group_imports = "StdExternalCrate" From e535d8bc0f44b35493f6e1a0cf3362adf8db5b44 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 07:17:00 +0100 Subject: [PATCH 33/48] style(libmsa): fmt nightly --- libmsa/src/alignment_type.rs | 4 ++-- libmsa/src/detection.rs | 7 ++----- libmsa/src/error.rs | 3 +-- libmsa/src/filter.rs | 8 ++------ libmsa/src/metrics.rs | 20 +++++++++++--------- libmsa/src/model.rs | 19 ++++++++++--------- libmsa/src/translation.rs | 12 +++++++----- 7 files changed, 35 insertions(+), 38 deletions(-) diff --git a/libmsa/src/alignment_type.rs b/libmsa/src/alignment_type.rs index 9fed65d..b08fab7 100644 --- a/libmsa/src/alignment_type.rs +++ b/libmsa/src/alignment_type.rs @@ -1,6 +1,6 @@ +use std::{num::NonZeroU8, str::FromStr}; + use crate::error::AlignmentError; -use std::num::NonZeroU8; -use std::str::FromStr; /// Describes the alignment type used by an alignment. /// diff --git a/libmsa/src/detection.rs b/libmsa/src/detection.rs index edfd6e7..ec55059 100644 --- a/libmsa/src/detection.rs +++ b/libmsa/src/detection.rs @@ -2,9 +2,7 @@ use std::num::NonZeroUsize; use rand::seq::IndexedRandom; -use crate::alignment_type::AlignmentType; -use crate::data::AlignmentData; -use crate::error::AlignmentError; +use crate::{alignment_type::AlignmentType, data::AlignmentData, error::AlignmentError}; const DEFAULT_SAMPLE_SIZE: usize = 100; const DEFAULT_CLASSIFICATION_THRESHOLD: f32 = 0.5; @@ -112,8 +110,7 @@ mod detect_alignment_type_tests { use rand::{SeedableRng, rngs::StdRng}; use super::{DetectionOptions, detect_alignment_type}; - use crate::data::AlignmentData; - use crate::{AlignmentError, AlignmentType, RawSequence}; + use crate::{AlignmentError, AlignmentType, RawSequence, data::AlignmentData}; fn raw(id: &str, sequence: &[u8]) -> RawSequence { RawSequence { diff --git a/libmsa/src/error.rs b/libmsa/src/error.rs index 84fed4f..54c9449 100644 --- a/libmsa/src/error.rs +++ b/libmsa/src/error.rs @@ -1,7 +1,6 @@ -use crate::alignment_type::AlignmentType; use thiserror::Error; -use crate::translation::ReadingFrame; +use crate::{alignment_type::AlignmentType, translation::ReadingFrame}; #[derive(Debug, Clone, PartialEq, Error)] pub enum AlignmentError { diff --git a/libmsa/src/filter.rs b/libmsa/src/filter.rs index ce0a368..1b13374 100644 --- a/libmsa/src/filter.rs +++ b/libmsa/src/filter.rs @@ -1,13 +1,9 @@ -use std::borrow::Borrow; -use std::sync::Arc; +use std::{borrow::Borrow, sync::Arc}; use rayon::prelude::*; use regex::Regex; -use crate::error::AlignmentError; -use crate::metrics; -use crate::model::Alignment; -use crate::projection::Projection; +use crate::{error::AlignmentError, metrics, model::Alignment, projection::Projection}; /// Builder for a filtered view over an unfiltered [`Alignment`]. /// diff --git a/libmsa/src/metrics.rs b/libmsa/src/metrics.rs index d12328f..e74e2e8 100644 --- a/libmsa/src/metrics.rs +++ b/libmsa/src/metrics.rs @@ -1,13 +1,16 @@ +use std::{num::NonZeroU8, ops::Range}; + use rand::seq::IndexedRandom; use rayon::prelude::*; -use std::{num::NonZeroU8, ops::Range}; -use crate::AlignmentType; -use crate::data::AlignmentData; -use crate::error::AlignmentError; -use crate::model::Alignment; -use crate::projection::Projection; -use crate::translation::{ReadingFrame, TranslationTable, translated_byte_at}; +use crate::{ + AlignmentType, + data::AlignmentData, + error::AlignmentError, + model::Alignment, + projection::Projection, + translation::{ReadingFrame, TranslationTable, translated_byte_at}, +}; /// Calculated values for a single alignment column. #[derive(Debug, Clone, PartialEq)] @@ -527,9 +530,8 @@ mod conservation_count_tests { #[cfg(test)] mod constant_fraction_count_tests { - use crate::AlignmentType; - use super::max_counted_symbol_fraction_from_counts; + use crate::AlignmentType; fn counts_for(symbols: &[u8]) -> [u32; 256] { let mut counts = [0u32; 256]; diff --git a/libmsa/src/model.rs b/libmsa/src/model.rs index d140e20..f349ad9 100644 --- a/libmsa/src/model.rs +++ b/libmsa/src/model.rs @@ -1,15 +1,16 @@ -use std::ops::Range; -use std::sync::Arc; +use std::{ops::Range, sync::Arc}; use rand::{SeedableRng, rngs::StdRng}; -use crate::alignment_type::AlignmentType; -use crate::data::{AlignmentData, RawSequence}; -use crate::detection::{DetectionOptions, detect_alignment_type}; -use crate::error::AlignmentError; -use crate::filter::FilterBuilder; -use crate::projection::Projection; -use crate::translation::{ReadingFrame, TranslatedAlignment, TranslationTable}; +use crate::{ + alignment_type::AlignmentType, + data::{AlignmentData, RawSequence}, + detection::{DetectionOptions, detect_alignment_type}, + error::AlignmentError, + filter::FilterBuilder, + projection::Projection, + translation::{ReadingFrame, TranslatedAlignment, TranslationTable}, +}; const DETECTION_SEED: u64 = u64::from_be_bytes(*b"REDRIGHT"); diff --git a/libmsa/src/translation.rs b/libmsa/src/translation.rs index d0b92bc..4213338 100644 --- a/libmsa/src/translation.rs +++ b/libmsa/src/translation.rs @@ -2,11 +2,13 @@ use std::ops::Range; use rayon::prelude::*; -use crate::Alignment; -use crate::alignment_type::AlignmentType; -use crate::error::AlignmentError; -use crate::metrics::{ - ColumnSummary, ConsensusMethod, counted_translated_columns_range, summaries_from_columns, +use crate::{ + Alignment, + alignment_type::AlignmentType, + error::AlignmentError, + metrics::{ + ColumnSummary, ConsensusMethod, counted_translated_columns_range, summaries_from_columns, + }, }; const NUCLEOTIDE_INDEX_TABLE: [u8; 256] = build_nucleotide_index_table(); From 2ddc224851614dc8170596d5f5c4a52208ed9a58 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 07:17:00 +0100 Subject: [PATCH 34/48] style(salti): fmt nightly --- salti/src/app.rs | 43 +++++++++++-------- salti/src/command.rs | 6 +-- salti/src/core/gff.rs | 7 +-- salti/src/input/key.rs | 11 ++--- salti/src/input/mouse.rs | 22 +++++----- salti/src/input/route.rs | 8 ++-- salti/src/logging.rs | 12 +++--- salti/src/main.rs | 10 ++--- salti/src/ui/layers/minimap.rs | 23 +++++----- salti/src/ui/layers/notification.rs | 13 +++--- .../ui/layers/palette/command_definitions.rs | 16 ++++--- .../src/ui/layers/palette/command_runners.rs | 9 ++-- salti/src/ui/layers/palette/command_spec.rs | 2 - salti/src/ui/layers/palette/completers.rs | 3 +- salti/src/ui/layers/palette/input.rs | 28 +++++++----- salti/src/ui/layers/palette/ui.rs | 19 +++++--- salti/src/ui/layers/render.rs | 17 ++++---- salti/src/ui/layers/state.rs | 3 +- salti/src/ui/layout.rs | 6 ++- salti/src/ui/panes/alignment.rs | 16 ++++--- salti/src/ui/panes/consensus.rs | 14 +++--- salti/src/ui/panes/sequence_id.rs | 19 ++++---- 22 files changed, 172 insertions(+), 135 deletions(-) diff --git a/salti/src/app.rs b/salti/src/app.rs index 8eaa2f5..3e2ea1a 100644 --- a/salti/src/app.rs +++ b/salti/src/app.rs @@ -2,8 +2,7 @@ use std::{env, path::Path, time::Duration}; use anyhow::{Result, format_err}; use crossterm::event::{Event as TermEvent, EventStream, KeyEvent, MouseEvent}; -use ratatui::DefaultTerminal; -use ratatui::layout::Rect; +use ratatui::{DefaultTerminal, layout::Rect}; use tokio::{ sync::mpsc::{UnboundedSender, unbounded_channel}, task::{JoinError, JoinHandle, JoinSet}, @@ -12,21 +11,31 @@ use tokio_stream::StreamExt; use tokio_util::sync::CancellationToken; use tracing::{debug, error, info, warn}; -use crate::cli::StartupState; -use crate::command::Command; -use crate::core::gff::{self, Gff}; -use crate::core::model::{AlignmentModel, StatsView}; -use crate::core::parser; -use crate::core::stats_cache::{ColumnStatsCache, StatsJobRequest, StatsJobResult}; -use crate::input; -use crate::input::MouseTracker; -use crate::ui::layers::notification::{Notification, NotificationLevel}; -use crate::ui::layers::palette::CommandPaletteState; -use crate::ui::layout::{AppLayout, FrameLayout, gff_pane_height, pinned_section_layout}; -use crate::ui::panes::gff::feature_row_count; -use crate::ui::render::render; -use crate::ui::ui_state::{LoadingState, UiState}; -use crate::update::UpdateResult; +use crate::{ + cli::StartupState, + command::Command, + core::{ + gff::{self, Gff}, + model::{AlignmentModel, StatsView}, + parser, + stats_cache::{ColumnStatsCache, StatsJobRequest, StatsJobResult}, + }, + input, + input::MouseTracker, + ui::{ + layers::{ + notification::{Notification, NotificationLevel}, + palette::CommandPaletteState, + }, + layout::{ + AlignmentHeaderLayout, AppLayout, FrameLayout, gff_pane_height, pinned_section_layout, + }, + panes::{gff::feature_row_count, local_feature_track::local_feature_row_count}, + render::render, + ui_state::{LoadingState, UiState}, + }, + update::UpdateResult, +}; const RENDER_FPS: f32 = 120.0; diff --git a/salti/src/command.rs b/salti/src/command.rs index 5312046..ac3206c 100644 --- a/salti/src/command.rs +++ b/salti/src/command.rs @@ -1,6 +1,6 @@ -use crate::config::theme::ThemeId; -use crate::core::model::DiffMode; -use crate::ui::layers::notification::Notification; +use crate::{ + config::theme::ThemeId, core::model::DiffMode, ui::layers::notification::Notification, +}; #[derive(Debug, Clone, PartialEq)] pub enum Command { diff --git a/salti/src/core/gff.rs b/salti/src/core/gff.rs index 1d410c5..6541fee 100644 --- a/salti/src/core/gff.rs +++ b/salti/src/core/gff.rs @@ -1,9 +1,4 @@ -use std::cmp::Reverse; -use std::fmt; -use std::fs::File; -use std::io::BufReader; -use std::ops::Range; -use std::path::Path; +use std::{cmp::Reverse, fmt, fs::File, io::BufReader, ops::Range, path::Path}; use anyhow::{Result, format_err}; use noodles_gff as gff; diff --git a/salti/src/input/key.rs b/salti/src/input/key.rs index 341a98e..a5745f3 100644 --- a/salti/src/input/key.rs +++ b/salti/src/input/key.rs @@ -1,10 +1,11 @@ use crossterm::event::KeyEvent; -use crate::command::Command; -use crate::config::keybindings; -use crate::input::route::{KeyRoute, route_key}; -use crate::ui::layers::state::ActiveLayer; -use crate::ui::ui_state::UiState; +use crate::{ + command::Command, + config::keybindings, + input::route::{KeyRoute, route_key}, + ui::{layers::state::ActiveLayer, ui_state::UiState}, +}; pub(crate) fn handle_key_event(ui: &mut UiState, key: KeyEvent) -> Vec { match route_key(ui) { diff --git a/salti/src/input/mouse.rs b/salti/src/input/mouse.rs index 2d490f0..b4e125d 100644 --- a/salti/src/input/mouse.rs +++ b/salti/src/input/mouse.rs @@ -1,15 +1,17 @@ use crossterm::event::{KeyModifiers, MouseButton, MouseEvent, MouseEventKind}; -use crate::command::Command; -use crate::core::gff::Gff; -use crate::core::model::AlignmentModel; -use crate::input::route::{MouseRoute, route_mouse}; -use crate::ui::layers::minimap::MinimapState; -use crate::ui::layers::state::ActiveLayer; -use crate::ui::layout::{AppLayout, FrameLayout}; -use crate::ui::panes::gff; -use crate::ui::selection::selection_point_crosshair; -use crate::ui::ui_state::{MouseSelection, UiState}; +use crate::{ + command::Command, + core::{gff::Gff, model::AlignmentModel}, + input::route::{MouseRoute, route_mouse}, + ui::{ + layers::{minimap::MinimapState, state::ActiveLayer}, + layout::{AppLayout, FrameLayout}, + panes::gff, + selection::selection_point_crosshair, + ui_state::{MouseSelection, UiState}, + }, +}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) struct MouseAnchor { diff --git a/salti/src/input/route.rs b/salti/src/input/route.rs index a07adc2..fa8ac79 100644 --- a/salti/src/input/route.rs +++ b/salti/src/input/route.rs @@ -1,8 +1,10 @@ use crossterm::event::{MouseButton, MouseEvent, MouseEventKind}; -use crate::ui::layers::state::ActiveLayer; -use crate::ui::layout::{AppLayout, FrameLayout}; -use crate::ui::ui_state::UiState; +use crate::ui::{ + layers::state::ActiveLayer, + layout::{AppLayout, FrameLayout}, + ui_state::UiState, +}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(super) enum KeyRoute { diff --git a/salti/src/logging.rs b/salti/src/logging.rs index c697690..d5808d0 100644 --- a/salti/src/logging.rs +++ b/salti/src/logging.rs @@ -1,12 +1,12 @@ -use std::fs::{File, OpenOptions}; -use std::io::ErrorKind; -use std::path::PathBuf; +use std::{ + fs::{File, OpenOptions}, + io::ErrorKind, + path::PathBuf, +}; use anyhow::Result; use tracing_appender::non_blocking::WorkerGuard; -use tracing_subscriber::EnvFilter; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; +use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt}; /// fallback filter used when `RUST_LOG` env is not set. const DEFAULT_LOG_LEVEL: &str = "salti=debug"; diff --git a/salti/src/main.rs b/salti/src/main.rs index a7855d2..c5d89aa 100644 --- a/salti/src/main.rs +++ b/salti/src/main.rs @@ -10,13 +10,13 @@ mod update; use anyhow::Result; use clap::Parser; -use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; -use crossterm::execute; -use std::io::stdout; +use crossterm::{ + event::{DisableMouseCapture, EnableMouseCapture}, + execute, +}; use tracing::{error, info}; -use crate::app::App; -use crate::cli::Cli; +use crate::{app::App, cli::Cli}; struct MouseCapture { enabled: bool, diff --git a/salti/src/ui/layers/minimap.rs b/salti/src/ui/layers/minimap.rs index 8d829f3..e234bdb 100644 --- a/salti/src/ui/layers/minimap.rs +++ b/salti/src/ui/layers/minimap.rs @@ -1,17 +1,18 @@ use std::ops::Range; use crossterm::event::MouseEvent; -use ratatui::buffer::Buffer; -use ratatui::layout::Rect; -use ratatui::style::Color; -use ratatui::text::{Line, Span}; -use ratatui::widgets::{Block, Clear, Paragraph, Widget}; - -use crate::command::Command; -use crate::config::theme::Theme; -use crate::core::model::AlignmentModel; -use crate::input::movement::HorizontalDrag; -use crate::ui::ui_state::UiState; +use ratatui::{ + buffer::Buffer, + layout::Rect, + style::Color, + text::{Line, Span}, + widgets::{Block, Clear, Paragraph, Widget}, +}; + +use crate::{ + command::Command, config::theme::Theme, core::model::AlignmentModel, + input::movement::HorizontalDrag, ui::ui_state::UiState, +}; /// maximum height of the minimap in rows const MINIMAP_HEIGHT_ROWS: u16 = 7; diff --git a/salti/src/ui/layers/notification.rs b/salti/src/ui/layers/notification.rs index 7e4b63e..3f37c86 100644 --- a/salti/src/ui/layers/notification.rs +++ b/salti/src/ui/layers/notification.rs @@ -1,9 +1,12 @@ +use ratatui::{ + Frame, + layout::Rect, + style::Style, + text::{Line, Span}, + widgets::Paragraph, +}; + use crate::config::theme::ThemeStyles; -use ratatui::Frame; -use ratatui::layout::Rect; -use ratatui::style::Style; -use ratatui::text::{Line, Span}; -use ratatui::widgets::Paragraph; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum NotificationLevel { diff --git a/salti/src/ui/layers/palette/command_definitions.rs b/salti/src/ui/layers/palette/command_definitions.rs index 9bd5267..b1aa55c 100644 --- a/salti/src/ui/layers/palette/command_definitions.rs +++ b/salti/src/ui/layers/palette/command_definitions.rs @@ -1,9 +1,13 @@ -use super::command_runners::{ - run_check_update, run_clear_filter, run_clear_reference, run_consensus_method, run_diff_mode, - run_filter_constant, run_filter_gaps, run_filter_rows, run_jump_feature, run_jump_position, - run_jump_sequence, run_load_alignment, run_load_gff, run_pin_sequence, run_quit, - run_reload_as_protein, run_set_active_type, run_set_reference, run_theme, - run_toggle_translation, run_translation_frame, run_unpin_sequence, +use super::{ + command_runners::{ + run_check_update, run_clear_filter, run_clear_reference, run_consensus_method, + run_diff_mode, run_filter_constant, run_filter_gaps, run_filter_rows, run_jump_feature, + run_jump_position, run_jump_sequence, run_load_alignment, run_load_gff, run_pin_sequence, + run_quit, run_reload_as_protein, run_set_active_type, run_set_reference, run_theme, + run_toggle_translation, run_translation_frame, run_unpin_sequence, + }, + command_spec::{PaletteCommand, StaticCommand, TypableCommand}, + completers, }; use super::command_spec::{PaletteCommand, StaticCommand, TypableCommand}; use super::completers; diff --git a/salti/src/ui/layers/palette/command_runners.rs b/salti/src/ui/layers/palette/command_runners.rs index 5db25dc..74cc50d 100644 --- a/salti/src/ui/layers/palette/command_runners.rs +++ b/salti/src/ui/layers/palette/command_runners.rs @@ -1,10 +1,11 @@ -use crate::command::Command; use anyhow::format_err; use tracing::warn; -use super::input::CommandPaletteState; -use super::input::VisibleSequence; -use super::utils::parse_argument; +use super::{ + input::{CommandPaletteState, VisibleSequence}, + utils::parse_argument, +}; +use crate::command::Command; fn ensure_no_argument(arguments: &str) -> anyhow::Result<()> { if parse_argument(arguments).is_some() { diff --git a/salti/src/ui/layers/palette/command_spec.rs b/salti/src/ui/layers/palette/command_spec.rs index 37e80fd..69e921d 100644 --- a/salti/src/ui/layers/palette/command_spec.rs +++ b/salti/src/ui/layers/palette/command_spec.rs @@ -1,5 +1,3 @@ -use crate::command::Command; - use super::input::CommandPaletteState; pub(super) type CompleterFunc = fn(&CommandPaletteState, &str) -> Vec; diff --git a/salti/src/ui/layers/palette/completers.rs b/salti/src/ui/layers/palette/completers.rs index 1553bef..379452f 100644 --- a/salti/src/ui/layers/palette/completers.rs +++ b/salti/src/ui/layers/palette/completers.rs @@ -1,5 +1,4 @@ -use std::fs; -use std::path::PathBuf; +use std::{fs, path::PathBuf}; use super::input::CommandPaletteState; diff --git a/salti/src/ui/layers/palette/input.rs b/salti/src/ui/layers/palette/input.rs index 72919f7..fb2c0ab 100644 --- a/salti/src/ui/layers/palette/input.rs +++ b/salti/src/ui/layers/palette/input.rs @@ -1,19 +1,25 @@ -use anyhow::format_err; use std::sync::Arc; use crossterm::event::{KeyCode, KeyEvent}; use libmsa::AlignmentType; -use crate::command::Command; -use crate::core::gff::Gff; -use crate::core::model::AlignmentModel; -use crate::core::search::{Direction, FilterMode, SearchableList}; -use crate::ui::layers::notification::{Notification, NotificationLevel}; -use crate::ui::panes::gff::FeatureMap; - -use super::command_definitions::COMMAND_SPECS; -use super::command_spec::{PaletteCommand, TypableCommand}; -use super::utils::parse_argument; +use super::{ + command_definitions::COMMAND_SPECS, + command_spec::{PaletteCommand, TypableCommand}, + utils::parse_argument, +}; +use crate::{ + command::Command, + core::{ + gff::Gff, + model::AlignmentModel, + search::{Direction, FilterMode, SearchableList}, + }, + ui::{ + features::FeatureMap, + layers::notification::{Notification, NotificationLevel}, + }, +}; #[derive(Debug, Clone, Copy)] pub(super) enum PaletteState { diff --git a/salti/src/ui/layers/palette/ui.rs b/salti/src/ui/layers/palette/ui.rs index 625d4a5..46920ef 100644 --- a/salti/src/ui/layers/palette/ui.rs +++ b/salti/src/ui/layers/palette/ui.rs @@ -1,9 +1,16 @@ -use ratatui::Frame; -use ratatui::layout::Rect; -use ratatui::style::Styled; -use ratatui::text::Line; -use ratatui::widgets::{Block, Clear, Paragraph, Widget}; - +use ratatui::{ + Frame, + layout::Rect, + style::Styled, + text::Line, + widgets::{Block, Clear, Paragraph, Widget}, +}; + +use super::{ + command_spec::PaletteCommand, + input::{CommandPaletteState, PaletteState}, + utils::{pad_label, wrap_text}, +}; use crate::core::search::SearchableList; use super::command_spec::PaletteCommand; diff --git a/salti/src/ui/layers/render.rs b/salti/src/ui/layers/render.rs index 2585b1b..72867d3 100644 --- a/salti/src/ui/layers/render.rs +++ b/salti/src/ui/layers/render.rs @@ -1,11 +1,12 @@ -use crate::core::model::AlignmentModel; -use crate::ui::layers::minimap::Minimap; -use crate::ui::layers::notification::render_notification; -use crate::ui::layers::state::ActiveLayer; -use crate::ui::ui_state::UiState; -use ratatui::Frame; -use ratatui::layout::Rect; -use ratatui::widgets::Block; +use ratatui::{Frame, layout::Rect, widgets::Block}; + +use crate::{ + core::model::AlignmentModel, + ui::{ + layers::{minimap::Minimap, notification::render_notification, state::ActiveLayer}, + ui_state::UiState, + }, +}; pub fn render_overlays( f: &mut Frame, diff --git a/salti/src/ui/layers/state.rs b/salti/src/ui/layers/state.rs index 7b4c4d6..71c7165 100644 --- a/salti/src/ui/layers/state.rs +++ b/salti/src/ui/layers/state.rs @@ -1,5 +1,4 @@ -use crate::ui::layers::minimap::MinimapState; -use crate::ui::layers::palette::CommandPaletteState; +use crate::ui::layers::{minimap::MinimapState, palette::CommandPaletteState}; #[derive(Debug)] pub enum ActiveLayer { diff --git a/salti/src/ui/layout.rs b/salti/src/ui/layout.rs index 7ca83b1..0e41c0d 100644 --- a/salti/src/ui/layout.rs +++ b/salti/src/ui/layout.rs @@ -1,5 +1,7 @@ -use ratatui::layout::{Rect, Spacing}; -use ratatui::macros::{horizontal, vertical}; +use ratatui::{ + layout::{Rect, Spacing}, + macros::{horizontal, vertical}, +}; /// fixed height (rows) for the bottom consensus pane. /// the remaining vertical space is used for the alignment pane. diff --git a/salti/src/ui/panes/alignment.rs b/salti/src/ui/panes/alignment.rs index 22bc7e6..86cf416 100644 --- a/salti/src/ui/panes/alignment.rs +++ b/salti/src/ui/panes/alignment.rs @@ -1,10 +1,12 @@ -use ratatui::buffer::Buffer; -use ratatui::layout::Rect; -use ratatui::macros::vertical; -use ratatui::style::Styled; -use ratatui::symbols::merge::MergeStrategy; -use ratatui::text::{Line, Span}; -use ratatui::widgets::{Block, Paragraph, Widget}; +use ratatui::{ + buffer::Buffer, + layout::Rect, + macros::vertical, + style::Styled, + symbols::merge::MergeStrategy, + text::Line, + widgets::{Block, Paragraph, Widget}, +}; use crate::{ core::{ diff --git a/salti/src/ui/panes/consensus.rs b/salti/src/ui/panes/consensus.rs index 5f7dd7c..8d1b879 100644 --- a/salti/src/ui/panes/consensus.rs +++ b/salti/src/ui/panes/consensus.rs @@ -1,9 +1,11 @@ -use ratatui::buffer::Buffer; -use ratatui::layout::Rect; -use ratatui::style::{Styled, Stylize}; -use ratatui::symbols::merge::MergeStrategy; -use ratatui::text::Line; -use ratatui::widgets::{Block, Paragraph, Widget}; +use ratatui::{ + buffer::Buffer, + layout::Rect, + style::{Styled, Stylize}, + symbols::merge::MergeStrategy, + text::Line, + widgets::{Block, Paragraph, Widget}, +}; use crate::{ core::{ diff --git a/salti/src/ui/panes/sequence_id.rs b/salti/src/ui/panes/sequence_id.rs index 7fa2004..4e4d8cf 100644 --- a/salti/src/ui/panes/sequence_id.rs +++ b/salti/src/ui/panes/sequence_id.rs @@ -1,3 +1,12 @@ +use ratatui::{ + buffer::Buffer, + layout::Rect, + style::{Style, Styled}, + symbols::merge::MergeStrategy, + text::Line, + widgets::{Block, Paragraph, Widget}, +}; + use crate::{ core::{model::AlignmentModel, viewport::ViewportWindow}, ui::{ @@ -5,12 +14,6 @@ use crate::{ ui_state::ThemeState, }, }; -use ratatui::buffer::Buffer; -use ratatui::layout::Rect; -use ratatui::style::{Style, Styled}; -use ratatui::symbols::merge::MergeStrategy; -use ratatui::text::Line; -use ratatui::widgets::{Block, Paragraph, Widget}; pub(crate) struct SequenceIdPane<'a> { pub(crate) alignment: &'a AlignmentModel, @@ -131,10 +134,10 @@ fn render_sequence_id_rows( #[cfg(test)] mod tests { + use ratatui::{buffer::Buffer, layout::Rect}; + use super::*; use crate::ui::layout::AppLayout; - use ratatui::buffer::Buffer; - use ratatui::layout::Rect; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { From 6f51504fb405b8895310fe04451bcd6a8395c201 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 07:17:00 +0100 Subject: [PATCH 35/48] style(salti): fmt nightly --- salti/src/main.rs | 2 ++ salti/src/ui/layers/palette/command_spec.rs | 1 + salti/src/ui/layers/palette/input.rs | 1 + salti/src/ui/rows.rs | 9 +++++---- salti/src/ui/selection.rs | 5 +---- salti/src/ui/ui_state.rs | 5 ++++- salti/src/update.rs | 3 ++- 7 files changed, 16 insertions(+), 10 deletions(-) diff --git a/salti/src/main.rs b/salti/src/main.rs index c5d89aa..3322f00 100644 --- a/salti/src/main.rs +++ b/salti/src/main.rs @@ -8,6 +8,8 @@ mod logging; mod ui; mod update; +use std::io::stdout; + use anyhow::Result; use clap::Parser; use crossterm::{ diff --git a/salti/src/ui/layers/palette/command_spec.rs b/salti/src/ui/layers/palette/command_spec.rs index 69e921d..ac5f02c 100644 --- a/salti/src/ui/layers/palette/command_spec.rs +++ b/salti/src/ui/layers/palette/command_spec.rs @@ -1,4 +1,5 @@ use super::input::CommandPaletteState; +use crate::command::Command; pub(super) type CompleterFunc = fn(&CommandPaletteState, &str) -> Vec; pub(super) type RunnerFunc = fn(&CommandPaletteState, &str) -> anyhow::Result; diff --git a/salti/src/ui/layers/palette/input.rs b/salti/src/ui/layers/palette/input.rs index fb2c0ab..ecd4a97 100644 --- a/salti/src/ui/layers/palette/input.rs +++ b/salti/src/ui/layers/palette/input.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use anyhow::format_err; use crossterm::event::{KeyCode, KeyEvent}; use libmsa::AlignmentType; diff --git a/salti/src/ui/rows.rs b/salti/src/ui/rows.rs index 9004ff7..15a7aa9 100644 --- a/salti/src/ui/rows.rs +++ b/salti/src/ui/rows.rs @@ -1,10 +1,11 @@ use std::ops::Range; -use ratatui::style::Stylize; -use ratatui::text::Span; +use ratatui::{style::Stylize, text::Span}; -use crate::config::theme::SequenceTheme; -use crate::core::codon::{TranslatedByteRange, TranslatedDiffRange, TranslationOverlay}; +use crate::{ + config::theme::SequenceTheme, + core::codon::{TranslatedByteRange, TranslatedDiffRange, TranslationOverlay}, +}; /// Lookup table that maps each byte value (`0-255`) to a str for display. /// diff --git a/salti/src/ui/selection.rs b/salti/src/ui/selection.rs index 3978b37..05c58e9 100644 --- a/salti/src/ui/selection.rs +++ b/salti/src/ui/selection.rs @@ -1,9 +1,6 @@ use std::ops::Range; -use ratatui::Frame; -use ratatui::layout::Rect; -use ratatui::style::Color::Rgb; -use ratatui::widgets::Block; +use ratatui::{Frame, layout::Rect, style::Color::Rgb, widgets::Block}; use crate::{ core::{Viewport, codon::TranslationOverlay, model::AlignmentModel}, diff --git a/salti/src/ui/ui_state.rs b/salti/src/ui/ui_state.rs index 7b4b264..bbf976b 100644 --- a/salti/src/ui/ui_state.rs +++ b/salti/src/ui/ui_state.rs @@ -4,7 +4,10 @@ use crate::{ EVERFOREST_DARK, Theme, ThemeId, ThemeStyles, build_theme_styles, theme_from_id, }, core::Viewport, - ui::{layers::notification::Notification, layers::state::LayerState, panes::gff::GffPaneState}, + ui::{ + layers::{notification::Notification, state::LayerState}, + panes::gff::GffPaneState, + }, }; #[derive(Debug, Clone, PartialEq, Eq, Default)] diff --git a/salti/src/update.rs b/salti/src/update.rs index 03cd317..047c215 100644 --- a/salti/src/update.rs +++ b/salti/src/update.rs @@ -1,6 +1,7 @@ +use std::time::Duration; + use semver::Version; use serde::Deserialize; -use std::time::Duration; const CRATE_NAME: &str = env!("CARGO_PKG_NAME"); const CRATE_VERSION: &str = env!("CARGO_PKG_VERSION"); From b803bd640f294f9752311324fd1e140cda248245 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 17:24:00 +0100 Subject: [PATCH 36/48] tests(salti): update tests --- salti/src/app.rs | 145 +------- salti/src/core/gff.rs | 3 +- salti/src/core/parser.rs | 3 +- salti/src/input/key.rs | 3 +- salti/src/input/mouse.rs | 340 +++++++++++++++--- salti/src/input/route.rs | 137 ++++++- .../ui/layers/palette/command_definitions.rs | 2 - .../src/ui/layers/palette/command_runners.rs | 11 +- salti/src/ui/layers/palette/completers.rs | 1 - salti/src/ui/layers/palette/ui.rs | 4 - salti/src/ui/panes/alignment.rs | 168 +++++---- salti/src/ui/panes/consensus.rs | 35 +- salti/src/ui/panes/gff.rs | 75 +--- salti/src/ui/panes/sequence_id.rs | 44 ++- salti/src/ui/panes/status_bars.rs | 177 ++++++--- salti/src/ui/render.rs | 72 ++-- salti/src/ui/selection.rs | 3 +- 17 files changed, 762 insertions(+), 461 deletions(-) diff --git a/salti/src/app.rs b/salti/src/app.rs index 3e2ea1a..cfd70b8 100644 --- a/salti/src/app.rs +++ b/salti/src/app.rs @@ -824,8 +824,6 @@ fn nearest_visible_relative_column( #[cfg(test)] mod tests { use super::*; - use crossterm::event::{KeyCode, KeyModifiers, MouseButton, MouseEventKind}; - use crate::ui::ui_state::MouseSelection; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { @@ -851,93 +849,8 @@ mod tests { app } - fn left_mouse_event( - kind: MouseEventKind, - area: Rect, - column_offset: u16, - row_offset: u16, - ) -> MouseEvent { - MouseEvent { - kind, - column: area.x + column_offset, - row: area.y + row_offset, - modifiers: KeyModifiers::empty(), - } - } - - #[test] - fn translated_click_selects_whole_codon() { - let mut app = - app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); - app.alignment - .as_mut() - .unwrap() - .set_translation_frame(libmsa::ReadingFrame::Frame1) - .unwrap(); - app.alignment - .as_mut() - .unwrap() - .toggle_translation_view() - .unwrap(); - - let area = app.app_layout.alignment_pane_sequence_rows; - app.handle_mouse_event(left_mouse_event( - MouseEventKind::Down(MouseButton::Left), - area, - 1, - 0, - )); - - let selection = app.ui.selection.unwrap(); - assert_eq!(selection.sequence_id, 0); - assert_eq!(selection.column, 0); - assert_eq!(selection.end_column, 2); - } - - #[test] - fn translated_drag_extends_selection_in_codons() { - let mut app = - app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); - app.alignment - .as_mut() - .unwrap() - .set_translation_frame(libmsa::ReadingFrame::Frame1) - .unwrap(); - app.alignment - .as_mut() - .unwrap() - .toggle_translation_view() - .unwrap(); - - let area = app.app_layout.alignment_pane_sequence_rows; - app.handle_mouse_event(left_mouse_event( - MouseEventKind::Down(MouseButton::Left), - area, - 1, - 0, - )); - app.handle_mouse_event(left_mouse_event( - MouseEventKind::Drag(MouseButton::Left), - area, - 7, - 0, - )); - app.handle_mouse_event(left_mouse_event( - MouseEventKind::Up(MouseButton::Left), - area, - 7, - 0, - )); - - let selection = app.ui.selection.unwrap(); - assert_eq!(selection.sequence_id, 0); - assert_eq!(selection.column, 0); - assert_eq!(selection.end_sequence_id, 0); - assert_eq!(selection.end_column, 8); - } - #[tokio::test(flavor = "current_thread")] - async fn toggling_translation_keeps_stored_nucleotide_selection() { + async fn translation_toggle_keeps_selection() { let mut app = app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); let selection = MouseSelection { @@ -985,7 +898,7 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn reload_as_protein_maps_nt_viewport_to_matching_aa_column() { + async fn reload_as_protein_keeps_locus_from_nt() { let sequence = vec![b'C'; 360]; let mut app = app_with_alignment(vec![raw("seq1", &sequence)]); app.ui.viewport.jump_to_position(200); @@ -996,7 +909,7 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn reload_as_protein_maps_back_to_nt_from_current_aa_locus() { + async fn reload_as_dna_keeps_locus_from_aa() { let sequence = vec![b'C'; 360]; let mut app = app_with_alignment(vec![raw("seq1", &sequence)]); app.ui.viewport.jump_to_position(200); @@ -1010,41 +923,7 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn set_translation_frame_retranslates_reloaded_protein_alignment() { - let mut app = app_with_alignment(vec![raw("seq1", b"ATGCCCTAA")]); - - app.execute_commands([Command::ReloadAsProtein { frame: None }]); - assert_eq!( - app.alignment - .as_ref() - .unwrap() - .base() - .sequence(0) - .unwrap() - .byte_at(0), - Some(b'M') - ); - - app.execute_commands([Command::SetTranslationFrame(libmsa::ReadingFrame::Frame2)]); - - assert_eq!( - app.alignment.as_ref().unwrap().translation_frame(), - libmsa::ReadingFrame::Frame2 - ); - assert_eq!( - app.alignment - .as_ref() - .unwrap() - .base() - .sequence(0) - .unwrap() - .byte_at(0), - Some(b'C') - ); - } - - #[tokio::test(flavor = "current_thread")] - async fn filter_gaps_shows_notification_in_translation() { + async fn gap_filter_blocked_during_translation() { let mut app = app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); app.execute_commands([Command::ToggleTranslationView]); @@ -1058,7 +937,7 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn filter_constant_shows_notification_in_translation() { + async fn constant_filter_blocked_during_translation() { let mut app = app_with_alignment(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); app.execute_commands([Command::ToggleTranslationView]); @@ -1072,7 +951,7 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn translation_shows_notification_with_gap_filter() { + async fn translation_blocked_by_gap_filter() { let mut app = app_with_alignment(vec![raw("seq1", b"ATG---"), raw("seq2", b"ATG---")]); app.execute_commands([Command::SetGapFilter(Some(0.0))]); app.execute_commands([Command::ToggleTranslationView]); @@ -1085,7 +964,7 @@ mod tests { } #[tokio::test(flavor = "current_thread")] - async fn translation_shows_notification_with_constant_filter() { + async fn translation_blocked_by_constant_filter() { let mut app = app_with_alignment(vec![raw("seq1", b"ATGAAA"), raw("seq2", b"ATGAAA")]); app.execute_commands([Command::SetConstantFilter(Some(1.0))]); app.execute_commands([Command::ToggleTranslationView]); @@ -1096,14 +975,4 @@ mod tests { "translation is unavailable while a column filter is active" ); } - - #[tokio::test(flavor = "current_thread")] - async fn key_events_forward_to_command_execution() { - let mut app = app_with_alignment(vec![raw("seq1", b"CATC"), raw("seq2", b"CATC")]); - let key = KeyEvent::new(KeyCode::Char('q'), KeyModifiers::NONE); - - app.handle_key_event(key); - - assert!(app.should_quit); - } } diff --git a/salti/src/core/gff.rs b/salti/src/core/gff.rs index 6541fee..e990113 100644 --- a/salti/src/core/gff.rs +++ b/salti/src/core/gff.rs @@ -126,9 +126,10 @@ fn extract_name(record: &gff::feature::RecordBuf) -> String { #[cfg(test)] mod tests { - use super::*; use std::io::Write; + use super::*; + fn write_gff(content: &str) -> tempfile::NamedTempFile { let mut file = tempfile::NamedTempFile::new().unwrap(); file.write_all(content.as_bytes()).unwrap(); diff --git a/salti/src/core/parser.rs b/salti/src/core/parser.rs index 101f50c..805b3cb 100644 --- a/salti/src/core/parser.rs +++ b/salti/src/core/parser.rs @@ -83,9 +83,10 @@ fn open_fasta_reader(input: &str) -> Result> #[cfg(test)] mod tests { - use super::*; use tempfile::NamedTempFile; + use super::*; + fn create_temp_fasta(content: &str) -> NamedTempFile { let temp_file = NamedTempFile::new().unwrap(); std::fs::write(temp_file.path(), content).unwrap(); diff --git a/salti/src/input/key.rs b/salti/src/input/key.rs index a5745f3..a4579da 100644 --- a/salti/src/input/key.rs +++ b/salti/src/input/key.rs @@ -25,8 +25,7 @@ mod tests { use crossterm::event::{KeyCode, KeyEvent}; use super::*; - use crate::cli::StartupState; - use crate::ui::layers::palette::CommandPaletteState; + use crate::{cli::StartupState, ui::layers::palette::CommandPaletteState}; fn ui_state() -> UiState { UiState::new(StartupState { diff --git a/salti/src/input/mouse.rs b/salti/src/input/mouse.rs index b4e125d..937cf84 100644 --- a/salti/src/input/mouse.rs +++ b/salti/src/input/mouse.rs @@ -261,9 +261,14 @@ mod tests { use ratatui::layout::Rect; use super::*; - use crate::cli::StartupState; - use crate::ui::layers::palette::CommandPaletteState; - use crate::ui::layout::{AppLayout, FrameLayout}; + use crate::{ + cli::StartupState, + core::gff::{Feature, FeatureType, Strand}, + ui::{ + layers::palette::CommandPaletteState, + layout::{AlignmentHeaderLayout, AppLayout, FrameLayout}, + }, + }; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -272,17 +277,6 @@ mod tests { } } - fn gff(start: usize, end: usize) -> Gff { - Gff { - features: vec![crate::core::gff::Feature { - name: "gene".to_string(), - kind: crate::core::gff::FeatureType::Gene, - range: start..end, - strand: crate::core::gff::Strand::Forward, - }], - } - } - fn ui_state() -> UiState { UiState::new(StartupState { file_path: None, @@ -290,19 +284,50 @@ mod tests { }) } + fn alignment_model(sequences: Vec) -> AlignmentModel { + let alignment = libmsa::Alignment::new(sequences).expect("alignment should be valid"); + AlignmentModel::new(alignment).expect("alignment model should be valid") + } + + fn mouse_event(kind: MouseEventKind, column: u16, row: u16) -> MouseEvent { + MouseEvent { + kind, + column, + row, + modifiers: KeyModifiers::empty(), + } + } + + fn left_mouse_event( + kind: MouseEventKind, + area: Rect, + column_offset: u16, + row_offset: u16, + ) -> MouseEvent { + mouse_event(kind, area.x + column_offset, area.y + row_offset) + } + + fn feature(name: &str, start: usize, end: usize) -> Feature { + Feature { + name: name.to_string(), + kind: FeatureType::Gene, + range: start..end, + strand: Strand::Forward, + } + } + #[test] fn palette_route_masks_mouse_commands() { let mut tracker = MouseTracker::default(); let mut ui = ui_state(); ui.layers.open_palette(CommandPaletteState::empty()); let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); - let app_layout = AppLayout::new(frame_layout.content_area, 0); - let mouse = MouseEvent { - kind: MouseEventKind::Down(MouseButton::Left), - column: 10, - row: 10, - modifiers: KeyModifiers::empty(), - }; + let app_layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); + let mouse = mouse_event(MouseEventKind::Down(MouseButton::Left), 10, 10); let commands = handle_mouse_event( &mut tracker, @@ -321,26 +346,26 @@ mod tests { fn minimap_route_emits_jump_command() { let sequence_a = vec![b'A'; 200]; let sequence_c = vec![b'C'; 200]; - let alignment = libmsa::Alignment::new(vec![ + let model = alignment_model(vec![ raw("row1", sequence_a.as_slice()), raw("row2", sequence_c.as_slice()), - ]) - .expect("alignment should be valid"); - let model = crate::core::model::AlignmentModel::new(alignment) - .expect("alignment model should be valid"); + ]); let mut tracker = MouseTracker::default(); let mut ui = ui_state(); let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); - let app_layout = AppLayout::new(frame_layout.content_area, 0); + let app_layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); ui.viewport.update_dimensions(78, 10, 20); ui.viewport.set_bounds(2, 200, 4); ui.layers.toggle_minimap(); - let mouse = MouseEvent { - kind: MouseEventKind::Down(MouseButton::Left), - column: frame_layout.overlay_area.x + frame_layout.overlay_area.width - 2, - row: frame_layout.overlay_area.y + frame_layout.overlay_area.height - 2, - modifiers: KeyModifiers::empty(), - }; + let mouse = mouse_event( + MouseEventKind::Down(MouseButton::Left), + frame_layout.overlay_area.x + frame_layout.overlay_area.width - 2, + frame_layout.overlay_area.y + frame_layout.overlay_area.height - 2, + ); let commands = handle_mouse_event( &mut tracker, @@ -356,24 +381,194 @@ mod tests { } #[test] - fn moved_event_in_gff_pane_sets_tooltip_without_mouse_down() { - let alignment = libmsa::Alignment::new(vec![raw("row1", &[b'A'; 20])]) - .expect("alignment should be valid"); - let model = crate::core::model::AlignmentModel::new(alignment) - .expect("alignment model should be valid"); - let gff = gff(0, 10); + fn translated_click_selects_codon() { + let mut model = alignment_model(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); + model + .set_translation(Some(libmsa::ReadingFrame::Frame1)) + .expect("translation should succeed"); let mut tracker = MouseTracker::default(); let mut ui = ui_state(); let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); - let app_layout = AppLayout::new(frame_layout.content_area, 4); - ui.viewport.update_dimensions(20, 10, 20); - ui.viewport.set_bounds(1, 20, 4); - let mouse = MouseEvent { - kind: MouseEventKind::Moved, - column: app_layout.gff_pane_rows.x, - row: app_layout.gff_pane_rows.y, - modifiers: KeyModifiers::empty(), + let app_layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); + ui.viewport.update_dimensions(60, 10, 20); + ui.viewport.set_bounds(2, 9, 4); + + let mouse = left_mouse_event( + MouseEventKind::Down(MouseButton::Left), + app_layout.alignment_pane_sequence_rows, + 1, + 0, + ); + handle_mouse_event( + &mut tracker, + Some(&model), + None, + &mut ui, + &frame_layout, + &app_layout, + mouse, + ); + + assert_eq!( + ui.selection, + Some(MouseSelection { + sequence_id: 0, + column: 0, + end_sequence_id: 0, + end_column: 2, + }) + ); + } + + #[test] + fn translated_ctrl_drag_spans_codons() { + let mut model = alignment_model(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); + model + .set_translation(Some(libmsa::ReadingFrame::Frame1)) + .expect("translation should succeed"); + let mut tracker = MouseTracker::default(); + let mut ui = ui_state(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); + ui.viewport.update_dimensions(60, 10, 20); + ui.viewport.set_bounds(2, 9, 4); + let area = app_layout.alignment_pane_sequence_rows; + + for mouse in [ + MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: area.x + 1, + row: area.y, + modifiers: KeyModifiers::CONTROL, + }, + left_mouse_event(MouseEventKind::Drag(MouseButton::Left), area, 7, 0), + left_mouse_event(MouseEventKind::Up(MouseButton::Left), area, 7, 0), + ] { + handle_mouse_event( + &mut tracker, + Some(&model), + None, + &mut ui, + &frame_layout, + &app_layout, + mouse, + ); + } + + assert_eq!( + ui.selection, + Some(MouseSelection { + sequence_id: 0, + column: 0, + end_sequence_id: 0, + end_column: 8, + }) + ); + } + + #[test] + fn left_click_outside_msa_clears_selection() { + let model = alignment_model(vec![raw("seq1", b"ATG"), raw("seq2", b"ATG")]); + let mut tracker = MouseTracker::default(); + let mut ui = ui_state(); + ui.selection = Some(MouseSelection { + sequence_id: 0, + column: 0, + end_sequence_id: 0, + end_column: 0, + }); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); + ui.viewport.update_dimensions(60, 10, 20); + ui.viewport.set_bounds(2, 3, 4); + + handle_mouse_event( + &mut tracker, + Some(&model), + None, + &mut ui, + &frame_layout, + &app_layout, + mouse_event(MouseEventKind::Down(MouseButton::Left), 0, 0), + ); + + assert_eq!(ui.selection, None); + } + + #[test] + fn middle_drag_pans_msa() { + let model = alignment_model(vec![raw("seq1", b"ATG"), raw("seq2", b"ATG")]); + let mut tracker = MouseTracker::default(); + let mut ui = ui_state(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); + let area = app_layout.alignment_pane_sequence_rows; + + handle_mouse_event( + &mut tracker, + Some(&model), + None, + &mut ui, + &frame_layout, + &app_layout, + left_mouse_event(MouseEventKind::Down(MouseButton::Middle), area, 10, 5), + ); + let commands = handle_mouse_event( + &mut tracker, + Some(&model), + None, + &mut ui, + &frame_layout, + &app_layout, + left_mouse_event(MouseEventKind::Drag(MouseButton::Middle), area, 12, 7), + ); + + assert_eq!( + commands, + vec![ + Command::ScrollUp { amount: 2 }, + Command::ScrollLeft { amount: 2 } + ] + ); + } + + #[test] + fn gff_hover_sets_tooltip() { + let model = alignment_model(vec![raw("seq1", &vec![b'A'; 100])]); + let gff = Gff { + features: vec![feature("gene1", 0, 100)], }; + let mut tracker = MouseTracker::default(); + let mut ui = ui_state(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 4, + AlignmentHeaderLayout::without_features(), + ); + ui.viewport.update_dimensions(60, 10, 20); + ui.viewport.set_bounds(1, 100, 4); + let mouse = mouse_event( + MouseEventKind::Moved, + app_layout.gff_pane_rows.x, + app_layout.gff_pane_rows.y, + ); let commands = handle_mouse_event( &mut tracker, @@ -386,9 +581,54 @@ mod tests { ); assert!(commands.is_empty()); - assert_eq!( - ui.gff_tooltip.as_deref(), - Some("gene (gene) — Forward →\n1-10 • 10 nt") + assert!( + ui.gff_tooltip + .as_deref() + .is_some_and(|it| it.starts_with("gene1 ")) + ); + } + + #[test] + fn gff_drag_emits_jump() { + let model = alignment_model(vec![raw("seq1", &vec![b'A'; 100])]); + let gff = Gff { + features: vec![feature("gene1", 0, 100)], + }; + let mut tracker = MouseTracker::default(); + let mut ui = ui_state(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 4, + AlignmentHeaderLayout::without_features(), ); + ui.viewport.update_dimensions(60, 10, 20); + ui.viewport.set_bounds(1, 100, 4); + let area = app_layout.gff_pane_rows; + + handle_mouse_event( + &mut tracker, + Some(&model), + Some(&gff), + &mut ui, + &frame_layout, + &app_layout, + mouse_event(MouseEventKind::Down(MouseButton::Left), area.x + 1, area.y), + ); + let commands = handle_mouse_event( + &mut tracker, + Some(&model), + Some(&gff), + &mut ui, + &frame_layout, + &app_layout, + mouse_event( + MouseEventKind::Drag(MouseButton::Left), + area.x + area.width - 1, + area.y, + ), + ); + + assert!(matches!(commands.as_slice(), [Command::JumpToPosition(_)])); } } diff --git a/salti/src/input/route.rs b/salti/src/input/route.rs index fa8ac79..861a4aa 100644 --- a/salti/src/input/route.rs +++ b/salti/src/input/route.rs @@ -90,7 +90,10 @@ mod tests { use ratatui::layout::Rect; use super::*; - use crate::cli::StartupState; + use crate::{ + cli::StartupState, + ui::{layers::palette::CommandPaletteState, layout::AlignmentHeaderLayout}, + }; fn ui_state() -> UiState { UiState::new(StartupState { @@ -99,12 +102,142 @@ mod tests { }) } + fn mouse_event(kind: MouseEventKind, column: u16, row: u16) -> MouseEvent { + MouseEvent { + kind, + column, + row, + modifiers: KeyModifiers::empty(), + } + } + + #[test] + fn key_uses_palette_when_open() { + let mut ui = ui_state(); + ui.layers.open_palette(CommandPaletteState::empty()); + + let route = route_key(&ui); + + assert_eq!(route, KeyRoute::Palette); + } + + #[test] + fn key_uses_global_without_palette() { + let ui = ui_state(); + + let route = route_key(&ui); + + assert_eq!(route, KeyRoute::Global); + } + + #[test] + fn palette_captures_mouse() { + let mut ui = ui_state(); + ui.layers.open_palette(CommandPaletteState::empty()); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 5, + AlignmentHeaderLayout::without_features(), + ); + let mouse = mouse_event( + MouseEventKind::Moved, + app_layout.gff_pane_rows.x, + app_layout.gff_pane_rows.y, + ); + + let route = route_mouse(&ui, &frame_layout, &app_layout, mouse, true); + + assert_eq!(route, MouseRoute::Palette); + } + + #[test] + fn minimap_captures_left_mouse_inside_track() { + let mut ui = ui_state(); + ui.layers.toggle_minimap(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); + let mouse = mouse_event( + MouseEventKind::Down(MouseButton::Left), + frame_layout.overlay_area.x + frame_layout.overlay_area.width - 2, + frame_layout.overlay_area.y + frame_layout.overlay_area.height - 2, + ); + + let route = route_mouse(&ui, &frame_layout, &app_layout, mouse, false); + + assert_eq!(route, MouseRoute::Minimap); + } + + #[test] + fn gff_pane_captures_hover() { + let ui = ui_state(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 5, + AlignmentHeaderLayout::without_features(), + ); + let mouse = mouse_event( + MouseEventKind::Moved, + app_layout.gff_pane_rows.x, + app_layout.gff_pane_rows.y, + ); + + let route = route_mouse(&ui, &frame_layout, &app_layout, mouse, true); + + assert_eq!(route, MouseRoute::GffPane); + } + + #[test] + fn gff_pane_ignored_without_gff() { + let ui = ui_state(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 5, + AlignmentHeaderLayout::without_features(), + ); + let mouse = mouse_event( + MouseEventKind::Moved, + app_layout.gff_pane_rows.x, + app_layout.gff_pane_rows.y, + ); + + let route = route_mouse(&ui, &frame_layout, &app_layout, mouse, false); + + assert_eq!(route, MouseRoute::Alignment); + } + + #[test] + fn mouse_defaults_to_alignment() { + let ui = ui_state(); + let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); + let app_layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); + let mouse = mouse_event(MouseEventKind::Moved, 0, 0); + + let route = route_mouse(&ui, &frame_layout, &app_layout, mouse, false); + + assert_eq!(route, MouseRoute::Alignment); + } + #[test] fn minimap_falls_through_to_gff_pane_outside_track() { let mut ui = ui_state(); ui.layers.toggle_minimap(); let frame_layout = FrameLayout::new(Rect::new(0, 0, 80, 24)); - let app_layout = AppLayout::new(frame_layout.content_area, 5); + let app_layout = AppLayout::new( + frame_layout.content_area, + 5, + AlignmentHeaderLayout::without_features(), + ); let mouse = MouseEvent { kind: MouseEventKind::Down(MouseButton::Left), column: app_layout.gff_pane_rows.x, diff --git a/salti/src/ui/layers/palette/command_definitions.rs b/salti/src/ui/layers/palette/command_definitions.rs index b1aa55c..a3a5ded 100644 --- a/salti/src/ui/layers/palette/command_definitions.rs +++ b/salti/src/ui/layers/palette/command_definitions.rs @@ -9,8 +9,6 @@ use super::{ command_spec::{PaletteCommand, StaticCommand, TypableCommand}, completers, }; -use super::command_spec::{PaletteCommand, StaticCommand, TypableCommand}; -use super::completers; /// Defines all commands available in the command palette. /// diff --git a/salti/src/ui/layers/palette/command_runners.rs b/salti/src/ui/layers/palette/command_runners.rs index 74cc50d..c191f89 100644 --- a/salti/src/ui/layers/palette/command_runners.rs +++ b/salti/src/ui/layers/palette/command_runners.rs @@ -355,11 +355,14 @@ pub(super) fn run_load_gff(_: &CommandPaletteState, arguments: &str) -> anyhow:: mod tests { use std::ops::Range; - use crate::core::gff::{Feature, FeatureType, Gff, Strand}; - use crate::core::model::AlignmentModel; - use crate::ui::layers::palette::input::{CommandPaletteSnapshot, GffFeatureTarget}; - use super::*; + use crate::{ + core::{ + gff::{Feature, FeatureType, Gff, Strand}, + model::AlignmentModel, + }, + ui::layers::palette::input::{CommandPaletteSnapshot, GffFeatureTarget}, + }; fn raw(sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { diff --git a/salti/src/ui/layers/palette/completers.rs b/salti/src/ui/layers/palette/completers.rs index 379452f..68532f5 100644 --- a/salti/src/ui/layers/palette/completers.rs +++ b/salti/src/ui/layers/palette/completers.rs @@ -112,7 +112,6 @@ pub(super) fn filename(_: &CommandPaletteState, arguments: &str) -> Vec #[cfg(test)] mod tests { use super::*; - use crate::ui::layers::palette::input::{CommandPaletteSnapshot, GffFeatureTarget}; fn palette_state_with_gff_features( diff --git a/salti/src/ui/layers/palette/ui.rs b/salti/src/ui/layers/palette/ui.rs index 46920ef..ef36c4b 100644 --- a/salti/src/ui/layers/palette/ui.rs +++ b/salti/src/ui/layers/palette/ui.rs @@ -13,10 +13,6 @@ use super::{ }; use crate::core::search::SearchableList; -use super::command_spec::PaletteCommand; -use super::input::{CommandPaletteState, PaletteState}; -use super::utils::{pad_label, wrap_text}; - /// maximum number of rows shown in the command/preview grid at once. const COMMAND_GRID_MAX_VISIBLE_ROWS: usize = 6; /// maximum number of columns shown in the command/preview grid. diff --git a/salti/src/ui/panes/alignment.rs b/salti/src/ui/panes/alignment.rs index 86cf416..3209da8 100644 --- a/salti/src/ui/panes/alignment.rs +++ b/salti/src/ui/panes/alignment.rs @@ -541,12 +541,18 @@ fn render_ruler( #[cfg(test)] mod tests { - use super::*; - use crate::core::model::StatsView; - use crate::core::stats_cache::StatsJobResult; - use crate::ui::layout::AppLayout; use ratatui::buffer::Buffer; + use super::*; + use crate::{ + core::{ + gff::{Feature, FeatureType, Gff, Strand}, + model::StatsView, + stats_cache::StatsJobResult, + }, + ui::layout::AppLayout, + }; + fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { id: id.to_string(), @@ -601,9 +607,42 @@ mod tests { area: Rect, row_offset: usize, col_offset: usize, + ) -> String { + render_alignment_pane_text_with_gff( + alignment, + stats_cache, + None, + area, + row_offset, + col_offset, + ) + } + + fn render_alignment_pane_text_with_gff( + alignment: &AlignmentModel, + stats_cache: &ColumnStatsCache, + gff: Option<&Gff>, + area: Rect, + row_offset: usize, + col_offset: usize, ) -> String { let mut buffer = Buffer::empty(area); - let layout = AppLayout::new(area, 0); + let header = match gff { + Some(gff) => { + let probe_layout = + AppLayout::new(area, 0, AlignmentHeaderLayout::without_features()); + let col_range = col_offset + ..col_offset + .saturating_add(probe_layout.alignment_pane_sequence_rows.width as usize) + .min(alignment.view().column_count()); + let local_rows = crate::ui::panes::local_feature_track::local_feature_row_count( + gff, alignment, &col_range, + ); + AlignmentHeaderLayout::with_features(local_rows as u16) + } + None => AlignmentHeaderLayout::without_features(), + }; + let layout = AppLayout::new(area, 0, header); let mut viewport = Viewport::default(); viewport.update_dimensions( layout.alignment_pane_sequence_rows.width as usize, @@ -623,6 +662,8 @@ mod tests { alignment, viewport: &viewport, metrics: stats_cache, + gff, + header: layout.alignment_header, theme: &theme, } .render(layout.alignment_pane, &mut buffer); @@ -676,6 +717,64 @@ mod tests { ); } + #[test] + fn alignment_pane_reserves_blank_local_feature_row_snapshot() { + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCAT"), + ]); + let gff = Gff { + features: vec![Feature { + name: "Offscreen".to_string(), + kind: FeatureType::Gene, + range: 30..40, + strand: Strand::Forward, + }], + }; + + insta::assert_snapshot!( + "alignment_pane_blank_local_feature_track", + render_alignment_pane_text_with_gff( + &alignment, + &ColumnStatsCache::default(), + Some(&gff), + Rect::new(0, 0, 100, 12), + 0, + 0, + ) + ); + } + + #[test] + fn alignment_pane_with_local_feature_track_snapshot() { + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCAT"), + ]); + let gff = Gff { + features: vec![Feature { + name: "Spike".to_string(), + kind: FeatureType::Gene, + range: 2..14, + strand: Strand::Forward, + }], + }; + + insta::assert_snapshot!( + "alignment_pane_with_local_feature_track", + render_alignment_pane_text_with_gff( + &alignment, + &ColumnStatsCache::default(), + Some(&gff), + Rect::new(0, 0, 100, 12), + 0, + 0, + ) + ); + } + #[test] fn alignment_pane_pinned_and_fragmented_snapshot() { let mut alignment = alignment_model(vec![ @@ -770,27 +869,6 @@ mod tests { ); } - #[test] - fn alignment_pane_raw_diff_reference_without_reference_snapshot() { - let mut alignment = alignment_model(vec![ - raw("seq1", b"CATCATCATCATCATCAT"), - raw("seq2", b"CATCATGATCATCATCAT"), - raw("seq3", b"CATCATCATCATGATCAT"), - ]); - alignment.diff_mode = DiffMode::Reference; - - insta::assert_snapshot!( - "alignment_pane_raw_diff_reference_without_reference", - render_alignment_pane_text( - &alignment, - &ColumnStatsCache::default(), - Rect::new(0, 0, 100, 12), - 0, - 0, - ) - ); - } - #[test] fn alignment_pane_raw_diff_consensus_snapshot() { let mut alignment = alignment_model(vec![ @@ -807,23 +885,6 @@ mod tests { ); } - #[test] - fn alignment_pane_raw_diff_consensus_loading_snapshot() { - let mut alignment = alignment_model(vec![ - raw("seq1", b"CATCATCATCATCATCAT"), - raw("seq2", b"CATCATGATCATCATCAT"), - raw("seq3", b"CATCATCATCATGATCAT"), - ]); - alignment.diff_mode = DiffMode::Consensus; - let mut metrics = ColumnStatsCache::default(); - metrics.init(alignment.view().column_count()); - - insta::assert_snapshot!( - "alignment_pane_raw_diff_consensus_loading", - render_alignment_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 12), 0, 0,) - ); - } - #[test] fn alignment_pane_scrolled_with_scrollbar_snapshot() { let alignment = alignment_model(vec![ @@ -868,25 +929,4 @@ mod tests { ) ); } - - #[test] - fn alignment_pane_dense_fragmented_ruler_snapshot() { - let mut alignment = alignment_model(vec![ - raw("seq1", b"CA-CA-CA-CA-CA-CA-CA-CA"), - raw("seq2", b"CA-CA-CA-CA-CA-CA-CA-CA"), - raw("seq3", b"CA-CA-CA-CA-CA-CA-CA-CA"), - ]); - alignment.set_gap_filter(Some(0.5)).unwrap(); - - insta::assert_snapshot!( - "alignment_pane_dense_fragmented_ruler", - render_alignment_pane_text( - &alignment, - &ColumnStatsCache::default(), - Rect::new(0, 0, 100, 12), - 0, - 0, - ) - ); - } } diff --git a/salti/src/ui/panes/consensus.rs b/salti/src/ui/panes/consensus.rs index 8d1b879..5202454 100644 --- a/salti/src/ui/panes/consensus.rs +++ b/salti/src/ui/panes/consensus.rs @@ -282,12 +282,13 @@ fn build_conservation_line( #[cfg(test)] mod tests { + use ratatui::{buffer::Buffer, layout::Rect}; + use super::*; - use crate::core::model::StatsView; - use crate::core::stats_cache::StatsJobResult; - use crate::ui::layout::AppLayout; - use ratatui::buffer::Buffer; - use ratatui::layout::Rect; + use crate::{ + core::{model::StatsView, stats_cache::StatsJobResult}, + ui::layout::{AlignmentHeaderLayout, AppLayout}, + }; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -343,7 +344,7 @@ mod tests { area: Rect, ) -> String { let mut buffer = Buffer::empty(area); - let layout = AppLayout::new(area, 0); + let layout = AppLayout::new(area, 0, AlignmentHeaderLayout::without_features()); let window = ViewportWindow { row_range: 0..alignment.view().row_count(), col_range: 0..alignment.view().column_count(), @@ -410,7 +411,7 @@ mod tests { } #[test] - fn raw_consensus_pane_no_reference_and_loading_snapshots() { + fn raw_consensus_no_reference_snapshot() { let alignment = alignment_model(vec![ raw("seq1", b"CATCATCATCATCATCAT"), raw("seq2", b"CATCATCATCATCATCAT"), @@ -421,14 +422,6 @@ mod tests { "consensus_pane_raw_no_reference", render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5)) ); - - let mut loading_metrics = ColumnStatsCache::default(); - loading_metrics.init(alignment.view().column_count()); - - insta::assert_snapshot!( - "consensus_pane_raw_loading", - render_consensus_pane_text(&alignment, &loading_metrics, Rect::new(0, 0, 100, 5)) - ); } #[test] @@ -454,7 +447,7 @@ mod tests { } #[test] - fn translated_consensus_pane_no_reference_and_loading_snapshots() { + fn translated_consensus_no_reference_snapshot() { let mut alignment = alignment_model(vec![ raw("seq1", b"CATCATCATCATCATCAT"), raw("seq2", b"CATCATCATCATCATCAT"), @@ -472,18 +465,10 @@ mod tests { "consensus_pane_translated_no_reference", render_consensus_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 5)) ); - - let mut loading_metrics = ColumnStatsCache::default(); - loading_metrics.init(alignment.view().column_count()); - - insta::assert_snapshot!( - "consensus_pane_translated_loading", - render_consensus_pane_text(&alignment, &loading_metrics, Rect::new(0, 0, 100, 5)) - ); } #[test] - fn generic_consensus_pane_hides_conservation_snapshot() { + fn generic_consensus_hides_conservation_snapshot() { let mut alignment = alignment_model(vec![ raw("seq1", b"ACDEACDEACDE"), raw("seq2", b"ACDEACDEACDE"), diff --git a/salti/src/ui/panes/gff.rs b/salti/src/ui/panes/gff.rs index 7684d46..e81ee81 100644 --- a/salti/src/ui/panes/gff.rs +++ b/salti/src/ui/panes/gff.rs @@ -562,85 +562,14 @@ mod tests { model_with_sequence(&vec![b'A'; len]) } - #[test] - fn filtered_nucleotide_mapping_collapses_hidden_columns() { - let mut model = model_with_sequence(b"-A-CC--G"); - model.set_gap_filter(Some(0.0)).unwrap(); - let mapping = FeatureMap::for_alignment(&model); - - assert_eq!( - model.view().absolute_column_ids().collect::>(), - vec![1, 3, 4, 7] - ); - assert_eq!( - mapping.map_feature(model.view(), &feature(2, 6)), - Some(1..3) - ); - } - - #[test] - fn filtered_nucleotide_mapping_hides_fully_filtered_feature() { - let mut model = model_with_sequence(b"-A-CC--G"); - model.set_gap_filter(Some(0.0)).unwrap(); - let mapping = FeatureMap::for_alignment(&model); - - assert_eq!(mapping.map_feature(model.view(), &feature(5, 6)), None); - } - - #[test] - fn filtered_protein_mapping_uses_projected_protein_columns() { - let mut model = model_with_sequence(b"M-M-M"); - model.set_gap_filter(Some(0.0)).unwrap(); - let mapping = FeatureMap::protein(3, 5, 0); - - assert_eq!( - model.view().absolute_column_ids().collect::>(), - vec![0, 2, 4] - ); - assert_eq!( - mapping.map_feature(model.view(), &feature(3, 8)), - Some(1..2) - ); - } - - #[test] - fn protein_mapping_clips_feature_before_frame_offset() { - let model = model_with_len(5); - let mapping = FeatureMap::protein(3, 5, 2); - - assert_eq!( - mapping.map_feature(model.view(), &feature(0, 4)), - Some(0..1) - ); - } - - #[test] - fn mapping_clips_feature_that_extends_past_alignment_end() { - let model = model_with_len(8); - let mapping = FeatureMap::for_alignment(&model); - - assert_eq!( - mapping.map_feature(model.view(), &feature(6, 10)), - Some(6..8) - ); - } - - #[test] - fn mapping_hides_feature_after_alignment_end() { - let model = model_with_len(8); - let mapping = FeatureMap::for_alignment(&model); - - assert_eq!(mapping.map_feature(model.view(), &feature(10, 12)), None); - } - #[test] fn placed_features_alternate_rows() { let gff = Gff { features: vec![feature(0, 1), feature(2, 3), feature(4, 5)], }; let model = model_with_len(6); - let mapping = FeatureMap::for_alignment(&model); - let rows: Vec = placed_features(&gff, model.view(), &mapping, 6) + let display_features = display_features(&gff, &model); + let rows: Vec = placed_features(&display_features, 6, model.view().column_count()) .into_iter() .map(|placed_feature| placed_feature.row) .collect(); diff --git a/salti/src/ui/panes/sequence_id.rs b/salti/src/ui/panes/sequence_id.rs index 4e4d8cf..295dacb 100644 --- a/salti/src/ui/panes/sequence_id.rs +++ b/salti/src/ui/panes/sequence_id.rs @@ -152,14 +152,27 @@ mod tests { } fn render_sequence_id_pane_text(alignment: &AlignmentModel, window: &ViewportWindow) -> String { + render_sequence_id_pane_text_with_header( + alignment, + window, + AlignmentHeaderLayout::without_features(), + ) + } + + fn render_sequence_id_pane_text_with_header( + alignment: &AlignmentModel, + window: &ViewportWindow, + header: AlignmentHeaderLayout, + ) -> String { let area = Rect::new(0, 0, 150, 12); let mut buffer = Buffer::empty(area); - let layout = AppLayout::new(area, 0); + let layout = AppLayout::new(area, 0, header); let theme = ThemeState::default(); SequenceIdPane { alignment, window, + header: layout.alignment_header, theme: &theme, } .render(layout.sequence_id_pane, &mut buffer); @@ -195,7 +208,7 @@ mod tests { } #[test] - fn sequence_id_pane_basic_snapshot() { + fn basic_sequence_ids_snapshot() { let alignment = alignment_model(vec![ raw("seq1", b"CATCATCATCATCATCAT"), raw("seq2", b"CATCATCATCATCATCAT"), @@ -214,7 +227,30 @@ mod tests { } #[test] - fn sequence_id_pane_pinned_snapshot() { + fn local_feature_rows_reserved_snapshot() { + let alignment = alignment_model(vec![ + raw("seq1", b"CATCATCATCATCATCAT"), + raw("seq2", b"CATCATCATCATCATCAT"), + raw("seq3", b"CATCATCATCATCATCAT"), + ]); + let window = ViewportWindow { + row_range: 0..alignment.view().row_count(), + col_range: 0..alignment.view().column_count(), + name_range: 0..18, + }; + + insta::assert_snapshot!( + "sequence_id_pane_local_feature_rows", + render_sequence_id_pane_text_with_header( + &alignment, + &window, + AlignmentHeaderLayout::with_features(2), + ) + ); + } + + #[test] + fn pinned_sequence_ids_snapshot() { let mut alignment = alignment_model(vec![ raw("seq1", b"CATCATCATCATCATCAT"), raw("seq2", b"CATCATCATCATCATCAT"), @@ -237,7 +273,7 @@ mod tests { } #[test] - fn sequence_id_pane_name_scroll_snapshot() { + fn scrolled_sequence_names_snapshot() { let alignment = alignment_model(vec![ raw("seq1-loooooooooooong-name", b"CATCATCATCATCATCAT"), raw("seq2-loooooooooooong-name", b"CATCATCATCATCATCAT"), diff --git a/salti/src/ui/panes/status_bars.rs b/salti/src/ui/panes/status_bars.rs index e10119e..df899d7 100644 --- a/salti/src/ui/panes/status_bars.rs +++ b/salti/src/ui/panes/status_bars.rs @@ -1,5 +1,13 @@ use std::fmt::Write as _; +use ratatui::{ + Frame, + layout::Rect, + style::Styled, + text::{Line, Span}, + widgets::Paragraph, +}; + use crate::{ core::model::AlignmentModel, ui::{ @@ -8,11 +16,6 @@ use crate::{ utils::truncate_label, }, }; -use ratatui::Frame; -use ratatui::layout::Rect; -use ratatui::style::Styled; -use ratatui::text::{Line, Span}; -use ratatui::widgets::Paragraph; /// maximum displayed character count for a selected sequence name in the status bar before truncation const STATUS_BAR_SELECTED_NAME_MAX_CHARS: usize = 25; @@ -199,8 +202,7 @@ pub fn render_frame( #[cfg(test)] mod tests { use super::*; - use crate::cli::StartupState; - use crate::ui::ui_state::MouseSelection; + use crate::{cli::StartupState, ui::ui_state::MouseSelection}; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -225,105 +227,162 @@ mod tests { } #[test] - fn top_status_bar_snapshots() { + fn top_status_loaded_alignment() { let alignment = alignment_model(vec![ raw("seq1", b"ACGTACGT"), raw("seq2", b"ACGTAC-T"), raw("seq3", b"ACGTACGA"), ]); - - let mut loaded_ui = ui_state(); - loaded_ui.meta.input_path = Some("/iamnotreal.fasta".to_string()); - loaded_ui.viewport.update_dimensions(5, 3, 0); - loaded_ui.viewport.set_bounds( + let mut ui = ui_state(); + ui.meta.input_path = Some("/iamnotreal.fasta".to_string()); + ui.viewport.update_dimensions(5, 3, 0); + ui.viewport.set_bounds( alignment.view().row_count(), alignment.view().column_count(), alignment.base().max_id_len(), ); - insta::assert_snapshot!( - "frame_top_status_loaded_alignment", - status_text(&build_top_status_bar(Some(&alignment), &loaded_ui)) + assert_eq!( + status_text(&build_top_status_bar(Some(&alignment), &ui)), + "File: iamnotreal.fasta | Status: Loaded | 3 alignments | Length: 8 | Positions: 1-5" ); + } - let mut failed_ui = UiState::new(StartupState::default()); - failed_ui.meta.loading_state = LoadingState::Failed("boom".to_string()); + #[test] + fn top_status_failed_load() { + let mut ui = UiState::new(StartupState::default()); + ui.meta.loading_state = LoadingState::Failed("boom".to_string()); - insta::assert_snapshot!( - "frame_top_status_failed_load", - status_text(&build_top_status_bar(None, &failed_ui)) + assert_eq!( + status_text(&build_top_status_bar(None, &ui)), + "File: Unknown | Status: Failed | 0 alignments | Length: 0 | Positions: 0-0" ); } #[test] - fn bottom_status_bar_snapshots() { - let mut filtered_alignment = alignment_model(vec![ + fn bottom_status_filters_translation() { + let mut alignment = alignment_model(vec![ raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATG---TTT"), raw("seq3", b"ATGAAGTTT"), ]); - filtered_alignment - .set_filter("seq1|seq2".to_string()) - .unwrap(); - filtered_alignment.set_gap_filter(Some(0.5)).unwrap(); - filtered_alignment + alignment.set_filter("seq1|seq2".to_string()).unwrap(); + alignment.set_gap_filter(Some(0.5)).unwrap(); + alignment .set_translation(Some(libmsa::ReadingFrame::Frame2)) .unwrap(); - insta::assert_snapshot!( - "frame_bottom_status_filters_translation", - status_text(&build_bottom_status_bar( - Some(&filtered_alignment), - &ui_state() - )) + assert_eq!( + status_text(&build_bottom_status_bar(Some(&alignment), &ui_state())), + "Filters: [rows: seq1|seq2] [gaps: <= 50%] (2 rows) (9 cols) | Translation frame: 2" ); + } - let mut constant_filter_alignment = alignment_model(vec![ + #[test] + fn bottom_status_constant_filter() { + let mut alignment = alignment_model(vec![ raw("seq1", b"CATCATCATCAT"), raw("seq2", b"CATCATCATCAT"), raw("seq3", b"CATCATCATCAT"), ]); - constant_filter_alignment - .set_constant_filter(Some(1.0)) - .unwrap(); + alignment.set_constant_filter(Some(1.0)).unwrap(); - insta::assert_snapshot!( - "frame_bottom_status_constant_filter", - status_text(&build_bottom_status_bar( - Some(&constant_filter_alignment), - &ui_state(), - )) + assert_eq!( + status_text(&build_bottom_status_bar(Some(&alignment), &ui_state())), + "Filters: [constant: >= 100%] (3 rows) (0 cols)" ); - let selected_alignment = - alignment_model(vec![raw("seq1", b"ACGTACGT"), raw("seq2", b"ACGTACGT")]); - let mut single_selection_ui = ui_state(); - single_selection_ui.selection = Some(MouseSelection { + #[test] + fn bottom_status_single_selection() { + let alignment = alignment_model(vec![raw("seq1", b"ACGTACGT"), raw("seq2", b"ACGTACGT")]); + let mut ui = ui_state(); + ui.selection = Some(MouseSelection { sequence_id: 0, column: 5, end_sequence_id: 0, end_column: 5, }); - insta::assert_snapshot!( - "frame_bottom_status_single_selection", - status_text(&build_bottom_status_bar( - Some(&selected_alignment), - &single_selection_ui - )) + assert_eq!( + status_text(&build_bottom_status_bar(Some(&alignment), &ui)), + "Selected: seq1 @ 6" + ); + } + + #[test] + fn bottom_status_single_range_selection() { + let alignment = alignment_model(vec![raw("seq1", b"ACGTACGT"), raw("seq2", b"ACGTACGT")]); + let mut ui = ui_state(); + ui.selection = Some(MouseSelection { + sequence_id: 0, + column: 2, + end_sequence_id: 0, + end_column: 8, + }); + + assert_eq!( + status_text(&build_bottom_status_bar(Some(&alignment), &ui)), + "Selected: seq1 @ 3-9" ); + } - let mut multi_selection_ui = ui_state(); - multi_selection_ui.selection = Some(MouseSelection { + #[test] + fn bottom_status_translated_codon_selection() { + let mut alignment = + alignment_model(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); + alignment + .set_translation_frame(libmsa::ReadingFrame::Frame1) + .unwrap(); + alignment.toggle_translation_view().unwrap(); + let mut ui = ui_state(); + ui.selection = Some(MouseSelection { + sequence_id: 0, + column: 0, + end_sequence_id: 0, + end_column: 2, + }); + + assert_eq!( + status_text(&build_bottom_status_bar(Some(&alignment), &ui)), + "Translation frame: 1 | Selected: seq1 @ 1" + ); + } + + #[test] + fn bottom_status_translated_range_selection() { + let mut alignment = + alignment_model(vec![raw("seq1", b"ATGAAATTT"), raw("seq2", b"ATGAAATTT")]); + alignment + .set_translation_frame(libmsa::ReadingFrame::Frame1) + .unwrap(); + alignment.toggle_translation_view().unwrap(); + let mut ui = ui_state(); + ui.selection = Some(MouseSelection { + sequence_id: 0, + column: 0, + end_sequence_id: 0, + end_column: 8, + }); + + assert_eq!( + status_text(&build_bottom_status_bar(Some(&alignment), &ui)), + "Translation frame: 1 | Selected: seq1 @ 1-3" + ); + } + + #[test] + fn bottom_status_multi_selection() { + let mut ui = ui_state(); + ui.selection = Some(MouseSelection { sequence_id: 0, column: 1, end_sequence_id: 2, end_column: 4, }); - insta::assert_snapshot!( - "frame_bottom_status_multi_selection", - status_text(&build_bottom_status_bar(None, &multi_selection_ui)) + assert_eq!( + status_text(&build_bottom_status_bar(None, &ui)), + "3 sequence(s) selected @ 2-5" ); } } diff --git a/salti/src/ui/render.rs b/salti/src/ui/render.rs index d235509..50605da 100644 --- a/salti/src/ui/render.rs +++ b/salti/src/ui/render.rs @@ -1,22 +1,27 @@ +use ratatui::{ + Frame, + layout::Rect, + style::{Styled, Stylize}, + text::Line, + widgets::Paragraph, +}; + use crate::{ core::{gff::Gff, model::AlignmentModel, stats_cache::ColumnStatsCache}, - ui::layers::render::render_overlays, ui::{ + layers::render::render_overlays, layout::{AppLayout, FrameLayout}, - panes::alignment::AlignmentPane, - panes::consensus::{ConsensusAlignmentPane, ConsensusSequenceIdPane}, - panes::gff::{GffInfoPane, GffPane}, - panes::sequence_id::SequenceIdPane, - panes::status_bars::render_frame, + panes::{ + alignment::AlignmentPane, + consensus::{ConsensusAlignmentPane, ConsensusSequenceIdPane}, + gff::{GffInfoPane, GffPane}, + sequence_id::SequenceIdPane, + status_bars::render_frame, + }, selection::render_mouse_selection, ui_state::{LoadingState, UiState}, }, }; -use ratatui::Frame; -use ratatui::layout::Rect; -use ratatui::style::{Styled, Stylize}; -use ratatui::text::Line; -use ratatui::widgets::Paragraph; fn render_empty_state_with_ui(f: &mut Frame, area: Rect, ui: &UiState) { let theme = &ui.theme; @@ -172,16 +177,24 @@ pub fn render( #[cfg(test)] mod tests { + use ratatui::{Terminal, backend::TestBackend, buffer::Buffer}; + use super::*; - use crate::cli::StartupState; - use crate::core::model::{DiffMode, StatsView}; - use crate::core::stats_cache::StatsJobResult; - use crate::ui::layers::notification::{Notification, NotificationLevel}; - use crate::ui::layers::palette::CommandPaletteState; - use crate::ui::ui_state::MouseSelection; - use ratatui::Terminal; - use ratatui::backend::TestBackend; - use ratatui::buffer::Buffer; + use crate::{ + cli::StartupState, + core::{ + model::{DiffMode, StatsView}, + stats_cache::StatsJobResult, + }, + ui::{ + layers::{ + notification::{Notification, NotificationLevel}, + palette::CommandPaletteState, + }, + layout::AlignmentHeaderLayout, + ui_state::MouseSelection, + }, + }; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { @@ -246,7 +259,11 @@ mod tests { let backend = TestBackend::new(area.width, area.height); let mut terminal = Terminal::new(backend).unwrap(); let frame_layout = FrameLayout::new(area); - let layout = AppLayout::new(frame_layout.content_area, 0); + let layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); terminal .draw(|frame| { @@ -293,7 +310,11 @@ mod tests { fn set_viewport(ui: &mut UiState, alignment: &AlignmentModel, area: Rect) { let frame_layout = FrameLayout::new(area); - let layout = AppLayout::new(frame_layout.content_area, 0); + let layout = AppLayout::new( + frame_layout.content_area, + 0, + AlignmentHeaderLayout::without_features(), + ); ui.viewport.update_dimensions( layout.alignment_pane_sequence_rows.width as usize, layout.alignment_pane_sequence_rows.height as usize, @@ -322,13 +343,6 @@ mod tests { "render_empty_failed", render_text(None, &failed_ui, &ColumnStatsCache::default(), area) ); - - let mut loading_ui = UiState::new(StartupState::default()); - loading_ui.meta.loading_state = LoadingState::Loading; - insta::assert_snapshot!( - "render_empty_loading", - render_text(None, &loading_ui, &ColumnStatsCache::default(), area) - ); } #[test] diff --git a/salti/src/ui/selection.rs b/salti/src/ui/selection.rs index 05c58e9..9b7c914 100644 --- a/salti/src/ui/selection.rs +++ b/salti/src/ui/selection.rs @@ -336,8 +336,7 @@ fn translated_selection_visible_col_range( #[cfg(test)] mod tests { use super::*; - use crate::core::Viewport; - use crate::core::model::AlignmentModel; + use crate::core::{Viewport, model::AlignmentModel}; fn raw(id: &str, sequence: &[u8]) -> libmsa::RawSequence { libmsa::RawSequence { From 903c4e0e9915ce3d76090470787a8d8b22d0746a Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 17:31:00 +0100 Subject: [PATCH 37/48] tests(salti): update snapshots --- ...es__alignment__tests__alignment_pane_basic.snap | 7 +++---- ..._alignment_pane_blank_local_feature_track.snap} | 14 +++++++------- ...sts__alignment_pane_dense_fragmented_ruler.snap | 13 ------------- ...ests__alignment_pane_pinned_and_fragmented.snap | 7 +++---- ...alignment_pane_pinned_with_vertical_scroll.snap | 5 ++--- ...__tests__alignment_pane_raw_diff_consensus.snap | 5 ++--- ...__tests__alignment_pane_raw_diff_reference.snap | 5 ++--- ...ts__alignment_pane_scrolled_with_scrollbar.snap | 5 ++--- ...lignment__tests__alignment_pane_translated.snap | 7 +++---- ...__alignment_pane_translated_diff_reference.snap | 5 ++--- ...__alignment_pane_with_local_feature_track.snap} | 14 +++++++------- ...nsensus__tests__consensus_pane_raw_loading.snap | 10 ---------- ...__tests__consensus_pane_translated_loading.snap | 10 ---------- ...sequence_id__tests__sequence_id_pane_basic.snap | 5 ++--- ...tests__sequence_id_pane_local_feature_rows.snap | 13 +++++++++++++ ...ce_id__tests__sequence_id_pane_name_scroll.snap | 4 ++-- ...equence_id__tests__sequence_id_pane_pinned.snap | 5 ++--- ..._ui__render__tests__render_command_palette.snap | 8 ++++---- ...i__ui__render__tests__render_empty_loading.snap | 6 ------ ...ti__ui__render__tests__render_loaded_basic.snap | 3 +-- ...__render__tests__render_loaded_translation.snap | 3 +-- ...tests__render_loaded_with_selection_status.snap | 3 +-- .../salti__ui__render__tests__render_minimap.snap | 3 +-- ...ti__ui__render__tests__render_notification.snap | 3 +-- 24 files changed, 61 insertions(+), 102 deletions(-) rename salti/src/ui/panes/snapshots/{salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus_loading.snap => salti__ui__panes__alignment__tests__alignment_pane_blank_local_feature_track.snap} (63%) delete mode 100644 salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_dense_fragmented_ruler.snap rename salti/src/ui/panes/snapshots/{salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference_without_reference.snap => salti__ui__panes__alignment__tests__alignment_pane_with_local_feature_track.snap} (56%) delete mode 100644 salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_loading.snap delete mode 100644 salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_loading.snap create mode 100644 salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_local_feature_rows.snap delete mode 100644 salti/src/ui/snapshots/salti__ui__render__tests__render_empty_loading.snap diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_basic.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_basic.snap index 0deefc4..6ffb49b 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_basic.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_basic.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 619 -expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12),)" +source: salti/src/ui/panes/alignment.rs +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" --- -┌Alignment──────────────────────────────────────────────────────────────────────┐ +┌───────────────────────────────────────────────────────────────────────────────┐ │1 10 │ │. . | . │ │CATCATCATCATCATCAT │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus_loading.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_blank_local_feature_track.snap similarity index 63% rename from salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus_loading.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_blank_local_feature_track.snap index 63ce4b2..e87aca7 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus_loading.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_blank_local_feature_track.snap @@ -1,13 +1,13 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 811 -expression: "render_alignment_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 12), 0,\n0,)" +source: salti/src/ui/panes/alignment.rs +assertion_line: 520 +expression: "render_alignment_pane_text_with_gff(&alignment, &ColumnStatsCache::default(),\nSome(&gff), Rect::new(0, 0, 100, 12), 0, 0,)" --- -┌Alignment──────────────────────────────────────────────────────────────────────┐ +┌───────────────────────────────────────────────────────────────────────────────┐ +│ │ │1 10 │ │. . | . │ │CATCATCATCATCATCAT │ -│CATCATGATCATCATCAT │ -│CATCATCATCATGATCAT │ -│ │ +│CATCATCATCATCATCAT │ +│CATCATCATCATCATCAT │ └───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_dense_fragmented_ruler.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_dense_fragmented_ruler.snap deleted file mode 100644 index be0fb71..0000000 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_dense_fragmented_ruler.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: salti/src/ui/alignment_pane.rs -assertion_line: 871 -expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" ---- -┌Alignment──────────────────────────────────────────────────────────────────────┐ -│1 10 20 │ -│. ~~~~~~~~~~~~~ │ -│CACACACACACACACA │ -│CACACACACACACACA │ -│CACACACACACACACA │ -│ │ -└───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_and_fragmented.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_and_fragmented.snap index 127f6e3..58d4084 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_and_fragmented.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_and_fragmented.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 641 -expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12),)" +source: salti/src/ui/panes/alignment.rs +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" --- -┌Alignment──────────────────────────────────────────────────────────────────────┐ +┌───────────────────────────────────────────────────────────────────────────────┐ │1 10 │ │. › | . │ │CATCATCATCATCAT │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_with_vertical_scroll.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_with_vertical_scroll.snap index 1fa1e87..5d049c8 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_with_vertical_scroll.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_pinned_with_vertical_scroll.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 850 +source: salti/src/ui/panes/alignment.rs expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 10), 2, 0,)" --- -┌Alignment──────────────────────────────────────────────────────────────────────┐ +┌───────────────────────────────────────────────────────────────────────────────┐ │1 10 │ │. . | . │ │CATCATCATCATCATCAT │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus.snap index aaae619..5ed7cb2 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_consensus.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 794 +source: salti/src/ui/panes/alignment.rs expression: "render_alignment_pane_text(&alignment, &metrics, Rect::new(0, 0, 100, 12), 0,\n0,)" --- -┌Alignment──────────────────────────────────────────────────────────────────────┐ +┌───────────────────────────────────────────────────────────────────────────────┐ │1 10 │ │. . | . │ │.................. │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference.snap index 467f09c..0ccf7d0 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 728 +source: salti/src/ui/panes/alignment.rs expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" --- -┌Alignment──────────────────────────────────────────────────────────────────────┐ +┌───────────────────────────────────────────────────────────────────────────────┐ │1 10 │ │. . | . │ │......G........... │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_scrolled_with_scrollbar.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_scrolled_with_scrollbar.snap index 8ba37ab..dabf787 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_scrolled_with_scrollbar.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_scrolled_with_scrollbar.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 825 +source: salti/src/ui/panes/alignment.rs expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 60, 12), 0, 10,)" --- -┌Alignment──────────────────────────────────────┐ +┌───────────────────────────────────────────────┐ │ 20 30 │ │ . | . | . │ │ATCATCATCATCATCATCATCATCAT │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated.snap index 8efdfe1..919eec7 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 660 -expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12),)" +source: salti/src/ui/panes/alignment.rs +expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" --- -┌Alignment──────────────────────────────────────────────────────────────────────┐ +┌───────────────────────────────────────────────────────────────────────────────┐ │1 10 │ │. . | . │ │ H H H H H H │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated_diff_reference.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated_diff_reference.snap index e429cf9..86379d5 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated_diff_reference.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_translated_diff_reference.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 751 +source: salti/src/ui/panes/alignment.rs expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" --- -┌Alignment──────────────────────────────────────────────────────────────────────┐ +┌───────────────────────────────────────────────────────────────────────────────┐ │1 10 │ │. . | . │ │ . . D . . . │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference_without_reference.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_with_local_feature_track.snap similarity index 56% rename from salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference_without_reference.snap rename to salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_with_local_feature_track.snap index de17b15..89ff89e 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_raw_diff_reference_without_reference.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__alignment__tests__alignment_pane_with_local_feature_track.snap @@ -1,13 +1,13 @@ --- -source: salti/src/ui/alignment_pane.rs -assertion_line: 772 -expression: "render_alignment_pane_text(&alignment, &ColumnStatsCache::default(),\nRect::new(0, 0, 100, 12), 0, 0,)" +source: salti/src/ui/panes/alignment.rs +assertion_line: 520 +expression: "render_alignment_pane_text_with_gff(&alignment, &ColumnStatsCache::default(),\nSome(&gff), Rect::new(0, 0, 100, 12), 0, 0,)" --- -┌Alignment──────────────────────────────────────────────────────────────────────┐ +┌───────────────────────────────────────────────────────────────────────────────┐ +│ Spike → │ │1 10 │ │. . | . │ │CATCATCATCATCATCAT │ -│CATCATGATCATCATCAT │ -│CATCATCATCATGATCAT │ -│ │ +│CATCATCATCATCATCAT │ +│CATCATCATCATCATCAT │ └───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_loading.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_loading.snap deleted file mode 100644 index 0bef212..0000000 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_raw_loading.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: salti/src/ui/consensus_pane.rs -assertion_line: 444 -expression: "render_consensus_pane_text(&alignment, &loading_metrics,\nRect::new(0, 0, 100, 5))" ---- -┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ -│Reference Sequence│No reference selected │ -│Consensus Sequence│Calculating consensus... │ -│Conservation: │Calculating conservation... │ -└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_loading.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_loading.snap deleted file mode 100644 index adc5a4b..0000000 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__consensus__tests__consensus_pane_translated_loading.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: salti/src/ui/consensus_pane.rs -assertion_line: 495 -expression: "render_consensus_pane_text(&alignment, &loading_metrics,\nRect::new(0, 0, 100, 5))" ---- -┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ -│Reference Sequence│No reference selected │ -│Consensus Sequence│Calculating consensus... │ -│Conservation: │Calculating conservation... │ -└──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_basic.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_basic.snap index 9802923..dc740b2 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_basic.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_basic.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/sequence_id_pane.rs -assertion_line: 207 +source: salti/src/ui/panes/sequence_id.rs expression: "render_sequence_id_pane_text(&alignment, &window)" --- -┌Sequence Name───────────────┐ +┌────────────────────────────┐ │ │ │ │ │1 seq1 │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_local_feature_rows.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_local_feature_rows.snap new file mode 100644 index 0000000..ac31e57 --- /dev/null +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_local_feature_rows.snap @@ -0,0 +1,13 @@ +--- +source: salti/src/ui/panes/sequence_id.rs +assertion_line: 253 +expression: "render_sequence_id_pane_text_with_header(&alignment, &window,\nAlignmentHeaderLayout::with_local_features(2),)" +--- +┌────────────────────────────┐ +│ │ +│ │ +│ │ +│ │ +│1 seq1 │ +│2 seq2 │ +└────────────────────────────┘ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_name_scroll.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_name_scroll.snap index 989ad48..5fd1ef2 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_name_scroll.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_name_scroll.snap @@ -1,8 +1,8 @@ --- -source: salti/src/ui/sequence_id_pane.rs +source: salti/src/ui/panes/sequence_id.rs expression: "render_sequence_id_pane_text(&alignment, &window)" --- -┌Sequence Name───────────────┐ +┌────────────────────────────┐ │ │ │ │ │1 loooooooooooong-na │ diff --git a/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_pinned.snap b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_pinned.snap index 5a0a0e9..3417745 100644 --- a/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_pinned.snap +++ b/salti/src/ui/panes/snapshots/salti__ui__panes__sequence_id__tests__sequence_id_pane_pinned.snap @@ -1,9 +1,8 @@ --- -source: salti/src/ui/sequence_id_pane.rs -assertion_line: 230 +source: salti/src/ui/panes/sequence_id.rs expression: "render_sequence_id_pane_text(&alignment, &window)" --- -┌Sequence Name───────────────┐ +┌────────────────────────────┐ │ │ │Pinned sequences: │ │2 seq2 │ diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap index 9657962..9d3cf54 100644 --- a/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_command_palette.snap @@ -3,7 +3,7 @@ source: salti/src/ui/render.rs expression: "render_text(Some(&alignment), &ui, &metrics, area)" --- File: Unknown | Status: Loaded | 2 alignments | Length: 18 | Positions: 1-18 -┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ │ │1 10 │ │ │. . | . │ │1 seq1 │CATCATCATCATCATCAT │ @@ -19,10 +19,10 @@ expression: "render_text(Some(&alignment), &ui, &metrics, area)" │ │ │ │ │ │ │ │ │ -jump-position filter-gaps check-update set-theme -jump-sequence filter-constant quit set-sequence-type +jump-position clear-filter reload-as-protein set-translation-frame +jump-sequence filter-gaps check-update set-theme +jump-feature filter-constant quit set-sequence-type pin-sequence set-reference set-diff-mode load-gff unpin-sequence clear-reference load-alignment filter-rows toggle-translate set-consensus-method -clear-filter reload-as-protein set-translation-frame :█ diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_loading.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_loading.snap deleted file mode 100644 index 8382835..0000000 --- a/salti/src/ui/snapshots/salti__ui__render__tests__render_empty_loading.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: salti/src/ui/render.rs -assertion_line: 455 -expression: "render_text(None, &loading_ui, &ColumnStatsCache::default(), area)" ---- - File: Unknown | Status: Loading | 0 alignments | Length: 0 | Positions: 0-0 diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_basic.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_basic.snap index ec18596..bf26c5e 100644 --- a/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_basic.snap +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_basic.snap @@ -1,10 +1,9 @@ --- source: salti/src/ui/render.rs -assertion_line: 474 expression: "render_text(Some(&alignment), &ui, &metrics, area)" --- File: Unknown | Status: Loaded | 4 alignments | Length: 18 | Positions: 1-18 -┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ │ │1 10 │ │ │. . | . │ │1 seq1 │CATCATCATCATCATCAT │ diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_translation.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_translation.snap index 9d3a10c..b1052c5 100644 --- a/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_translation.snap +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_translation.snap @@ -1,10 +1,9 @@ --- source: salti/src/ui/render.rs -assertion_line: 505 expression: "render_text(Some(&alignment), &ui, &metrics, area)" --- File: Unknown | Status: Loaded | 2 alignments | Length: 18 | Positions: 1-18 -┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ │ │1 10 │ │ │. . | . │ │2 seq2 │ . . D . . . │ diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_with_selection_status.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_with_selection_status.snap index 70cf9aa..a10e5bb 100644 --- a/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_with_selection_status.snap +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_loaded_with_selection_status.snap @@ -1,10 +1,9 @@ --- source: salti/src/ui/render.rs -assertion_line: 484 expression: "render_text(Some(&alignment), &selection_ui, &metrics, area)" --- File: Unknown | Status: Loaded | 4 alignments | Length: 18 | Positions: 1-18 -┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ │ │1 10 │ │ │. . | . │ │1 seq1 │CATCATCATCATCATCAT │ diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_minimap.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_minimap.snap index b8fae7a..f334802 100644 --- a/salti/src/ui/snapshots/salti__ui__render__tests__render_minimap.snap +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_minimap.snap @@ -1,10 +1,9 @@ --- source: salti/src/ui/render.rs -assertion_line: 563 expression: "render_text(Some(&alignment), &ui, &metrics, area)" --- File: Unknown | Status: Loaded | 3 alignments | Length: 36 | Positions: 1-36 -┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ │ │1 10 20 30 │ │ │. . | . | . | . │ │1 seq1 │CATCATCATCATCATCATCATCATCATCATCATCAT │ diff --git a/salti/src/ui/snapshots/salti__ui__render__tests__render_notification.snap b/salti/src/ui/snapshots/salti__ui__render__tests__render_notification.snap index 92cf1f9..f9cbc8e 100644 --- a/salti/src/ui/snapshots/salti__ui__render__tests__render_notification.snap +++ b/salti/src/ui/snapshots/salti__ui__render__tests__render_notification.snap @@ -1,10 +1,9 @@ --- source: salti/src/ui/render.rs -assertion_line: 526 expression: "render_text(Some(&alignment), &ui, &metrics, area)" --- File: Unknown | Status: Loaded | 2 alignments | Length: 18 | Positions: 1-18 -┌Sequence Name─────┬Alignment──────────────────────────────────────────────────────────────────────┐ +┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ │ │1 10 │ │ │. . | . │ │1 seq1 │CATCATCATCATCATCAT │ From d35adaf71a5b326ba3f940aedaa39f7ea56dcb4b Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 17:38:00 +0100 Subject: [PATCH 38/48] feat(libmsa): is_empty function (clippy) --- libmsa/src/model.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libmsa/src/model.rs b/libmsa/src/model.rs index f349ad9..b652f33 100644 --- a/libmsa/src/model.rs +++ b/libmsa/src/model.rs @@ -348,6 +348,11 @@ impl<'a> RowView<'a> { self.columns.len() } + /// Returns true if this sequence view has no visible columns. + pub fn is_empty(&self) -> bool { + self.columns.len() == 0 + } + /// Returns the byte at `relative_col`, or `None` if the column is out of bounds. /// /// The column index is relative to this view's column projection. From 06fec4dd816dce02ac04fe649d8e7dbdc76c8f34 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 17:38:00 +0100 Subject: [PATCH 39/48] build(libmsa): bump version --- Cargo.lock | 2 +- libmsa/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b71ac31..73c8547 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1499,7 +1499,7 @@ dependencies = [ [[package]] name = "libmsa" -version = "0.1.0" +version = "0.2.0" dependencies = [ "rand 0.9.2", "rayon", diff --git a/libmsa/Cargo.toml b/libmsa/Cargo.toml index 30ae242..86239c6 100644 --- a/libmsa/Cargo.toml +++ b/libmsa/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libmsa" -version = "0.1.0" +version = "0.2.0" edition = "2024" authors = ["Samuel Sims"] description = "A library for operations on multiple sequence alignments" From 6afc24871c96b42e818b0eb647f64d5284f097f2 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 18:17:00 +0100 Subject: [PATCH 40/48] feat(salti): add local feature track --- Cargo.lock | 2 +- salti/Cargo.toml | 2 +- salti/src/app.rs | 166 ++++++++-- salti/src/core/gff.rs | 4 +- salti/src/input/mouse.rs | 4 +- salti/src/ui/features.rs | 224 +++++++++++++ .../ui/layers/palette/command_definitions.rs | 2 +- salti/src/ui/layers/palette/completers.rs | 16 +- salti/src/ui/layers/palette/input.rs | 16 +- salti/src/ui/layers/palette/ui.rs | 20 +- salti/src/ui/layout.rs | 43 ++- salti/src/ui/mod.rs | 1 + salti/src/ui/panes/alignment.rs | 263 ++------------- salti/src/ui/panes/consensus.rs | 12 +- salti/src/ui/panes/gff.rs | 140 +++----- salti/src/ui/panes/local_feature_track.rs | 279 ++++++++++++++++ salti/src/ui/panes/mod.rs | 2 + salti/src/ui/panes/ruler.rs | 304 ++++++++++++++++++ salti/src/ui/panes/sequence_id.rs | 22 +- salti/src/ui/panes/status_bars.rs | 43 ++- salti/src/ui/render.rs | 3 + salti/src/ui/rows.rs | 71 ++-- salti/src/ui/selection.rs | 4 +- salti/src/ui/ui_state.rs | 1 + 24 files changed, 1197 insertions(+), 447 deletions(-) create mode 100644 salti/src/ui/features.rs create mode 100644 salti/src/ui/panes/local_feature_track.rs create mode 100644 salti/src/ui/panes/ruler.rs diff --git a/Cargo.lock b/Cargo.lock index 73c8547..8f27fdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2606,7 +2606,7 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salti" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "clap", diff --git a/salti/Cargo.toml b/salti/Cargo.toml index c525319..791c93e 100644 --- a/salti/Cargo.toml +++ b/salti/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "salti" -version = "0.8.0" +version = "0.9.0" edition = "2024" authors = ["Samuel Sims"] description = "A modern, fast, multiple sequence alignment browser - built for the terminal. " diff --git a/salti/src/app.rs b/salti/src/app.rs index cfd70b8..9de1333 100644 --- a/salti/src/app.rs +++ b/salti/src/app.rs @@ -76,7 +76,12 @@ impl App { pub(crate) fn new(startup: StartupState) -> Self { let layout_area = Rect::default(); let frame_layout = FrameLayout::new(layout_area); - let app_layout = AppLayout::new(frame_layout.content_area, 0); + let app_layout = AppLayout::new( + frame_layout.content_area, + // TODO: remove magic number similar to AlignmentHeaderLayout - currently 0 at start since no GFF loaded + 0, + AlignmentHeaderLayout::without_features(), + ); Self { alignment: None, gff: None, @@ -107,7 +112,7 @@ impl App { height = area.height, "Captured initial terminal size" ); - self.update_layout(area.into()); + self.rebuild_layout(area.into()); } Err(error) => { warn!(error = ?error, "Failed to capture initial terminal size"); @@ -136,7 +141,10 @@ impl App { _ = interval.tick() => { if needs_redraw { if let Err(error) = terminal.draw(|frame| { - self.update_layout(frame.area()); + let area = frame.area(); + if area != self.layout_area { + self.rebuild_layout(area); + } render( frame, self.alignment.as_ref(), @@ -156,7 +164,7 @@ impl App { Some(Ok(event)) = events.next() => { match event { TermEvent::Resize(width, height) => { - self.update_layout(Rect::new(0, 0, width, height)); + self.rebuild_layout(Rect::new(0, 0, width, height)); self.extend_stats_if_needed(); } TermEvent::Key(key) => { @@ -247,13 +255,10 @@ impl App { self.start_load_job(input); } - fn update_layout(&mut self, area: Rect) { - if area == self.layout_area { - return; - } - + fn rebuild_layout(&mut self, area: Rect) { self.layout_area = area; self.frame_layout = FrameLayout::new(area); + // TODO: revist this as feels clunky // hides the gff pane if we dont have one loaded // if loaded the height is dynamic to the number of rows the features spill on to let gff_height = self.gff.as_ref().map_or(0, |gff| { @@ -261,12 +266,48 @@ impl App { return 0; }; // create a temp applayout with a gff height of 1 to get a value for width - let probe_layout = AppLayout::new(self.frame_layout.content_area, gff_pane_height(1)); + let probe_layout = AppLayout::new( + self.frame_layout.content_area, + gff_pane_height(1), + AlignmentHeaderLayout::without_features(), + ); let width = usize::from(probe_layout.gff_pane_rows.width); gff_pane_height(feature_row_count(gff, alignment, width).max(1)) }); + let local_feature_rows = match (self.gff.as_ref(), self.alignment.as_ref()) { + (Some(gff), Some(alignment)) => { + let probe_layout = AppLayout::new( + self.frame_layout.content_area, + gff_height, + AlignmentHeaderLayout::without_features(), + ); + let visible_width = probe_layout.alignment_pane.width.saturating_sub(2) as usize; + let col_start = self + .ui + .viewport + .offsets + .cols + .min(alignment.view().column_count()); + let col_end = col_start + .saturating_add(visible_width) + .min(alignment.view().column_count()); + u16::try_from(local_feature_row_count( + gff, + alignment, + &(col_start..col_end), + )) + .unwrap_or(u16::MAX) + } + (None, _) | (_, None) => 0, + }; + let alignment_header = if local_feature_rows == 0 { + AlignmentHeaderLayout::without_features() + } else { + AlignmentHeaderLayout::with_features(local_feature_rows) + }; // set the real layout once we know the height of the gff - self.app_layout = AppLayout::new(self.frame_layout.content_area, gff_height); + self.app_layout = + AppLayout::new(self.frame_layout.content_area, gff_height, alignment_header); let visible_width = self.app_layout.alignment_pane.width.saturating_sub(2) as usize; let available_sequence_rows = self.app_layout.alignment_pane_sequence_rows.height as usize; @@ -385,7 +426,7 @@ impl App { Ok(model) => { self.gff = Some(model); self.ui.gff_pane = Default::default(); - self.force_relayout(); + self.rebuild_layout(self.layout_area); self.show_info(format!("Loaded GFF file: {path}")); } Err(error) => { @@ -401,8 +442,18 @@ impl App { Command::ScrollDown { amount } => self.ui.viewport.scroll_down(amount), Command::ScrollUp { amount } => self.ui.viewport.scroll_up(amount), - Command::ScrollLeft { amount } => self.ui.viewport.scroll_left(amount), - Command::ScrollRight { amount } => self.ui.viewport.scroll_right(amount), + Command::ScrollLeft { amount } => { + self.ui.viewport.scroll_left(amount); + if self.layout_needs_rebuild() { + self.rebuild_layout(self.layout_area); + } + } + Command::ScrollRight { amount } => { + self.ui.viewport.scroll_right(amount); + if self.layout_needs_rebuild() { + self.rebuild_layout(self.layout_area); + } + } Command::ScrollNamesLeft { amount } => self.ui.viewport.scroll_names_left(amount), Command::ScrollNamesRight { amount } => self.ui.viewport.scroll_names_right(amount), @@ -413,6 +464,9 @@ impl App { .is_some_and(|alignment| relative_col < alignment.view().column_count()); if has_column { self.ui.viewport.jump_to_position(relative_col); + if self.layout_needs_rebuild() { + self.rebuild_layout(self.layout_area); + } } } Command::JumpToSequence(abs_row) => { @@ -433,6 +487,9 @@ impl App { .is_some_and(|alignment| alignment.view().column_count() > 0); if has_columns { self.ui.viewport.jump_to_position(0); + if self.layout_needs_rebuild() { + self.rebuild_layout(self.layout_area); + } } } Command::JumpToEnd => { @@ -442,6 +499,9 @@ impl App { .and_then(|alignment| alignment.view().column_count().checked_sub(1)); if let Some(last_col) = last_col { self.ui.viewport.jump_to_position(last_col); + if self.layout_needs_rebuild() { + self.rebuild_layout(self.layout_area); + } } } @@ -523,7 +583,7 @@ impl App { let viewport_target = self.reload_as_protein_viewport_target(frame); self.alignment_mut()?.toggle_reload_as_protein(frame)?; self.clear_mouse_selection(); - self.force_relayout(); + self.rebuild_layout(self.layout_area); self.jump_to_reloaded_viewport_target(viewport_target); self.invalidate_all_stats(); return Ok(()); @@ -567,7 +627,7 @@ impl App { } fn on_view_rebuilt(&mut self) { - self.force_relayout(); + self.rebuild_layout(self.layout_area); self.invalidate_all_stats(); } @@ -608,6 +668,9 @@ impl App { return; }; self.ui.viewport.jump_to_position(relative_col); + if self.layout_needs_rebuild() { + self.rebuild_layout(self.layout_area); + } } fn clear_mouse_selection(&mut self) { @@ -633,10 +696,24 @@ impl App { ); } - fn force_relayout(&mut self) { - let area = self.layout_area; - self.layout_area = Rect::default(); - self.update_layout(area); + fn layout_needs_rebuild(&self) -> bool { + let (Some(gff), Some(alignment)) = (self.gff.as_ref(), self.alignment.as_ref()) else { + return false; + }; + + let visible_width = self.app_layout.alignment_pane.width.saturating_sub(2) as usize; + let col_start = self.ui.viewport.offsets.cols; + let col_end = col_start + .saturating_add(visible_width) + .min(alignment.view().column_count()); + let local_feature_rows = u16::try_from(local_feature_row_count( + gff, + alignment, + &(col_start..col_end), + )) + .unwrap_or(u16::MAX); + + local_feature_rows != self.app_layout.alignment_header.local_feature_rows } fn alignment_mut(&mut self) -> Result<&mut AlignmentModel> { @@ -845,10 +922,57 @@ mod tests { app.alignment = Some(model); app.ui.meta.loading_state = LoadingState::Loaded; app.refresh_viewport_bounds(); - app.update_layout(Rect::new(0, 0, 40, 12)); + app.rebuild_layout(Rect::new(0, 0, 40, 12)); app } + fn gff_with_overlapping_features() -> Gff { + Gff { + features: vec![ + gff::Feature { + name: "gene1".to_string(), + kind: gff::FeatureType::Gene, + range: 0..10, + strand: gff::Strand::Forward, + }, + gff::Feature { + name: "gene2".to_string(), + kind: gff::FeatureType::Gene, + range: 0..10, + strand: gff::Strand::Forward, + }, + ], + } + } + + #[tokio::test(flavor = "current_thread")] + async fn horizontal_scroll_updates_layout_local_feature_stacked() { + let sequence = vec![b'A'; 120]; + let mut app = app_with_alignment(vec![raw("seq1", &sequence)]); + app.gff = Some(gff_with_overlapping_features()); + app.rebuild_layout(app.layout_area); + assert_eq!(app.app_layout.alignment_header.local_feature_rows, 2); + + app.execute_commands([Command::ScrollRight { amount: 50 }]); + + assert_eq!(app.ui.viewport.offsets.cols, 50); + assert_eq!(app.app_layout.alignment_header.local_feature_rows, 1); + } + + #[tokio::test(flavor = "current_thread")] + async fn jump_to_position_updates_layout_local_feature_stacked() { + let sequence = vec![b'A'; 120]; + let mut app = app_with_alignment(vec![raw("seq1", &sequence)]); + app.gff = Some(gff_with_overlapping_features()); + app.rebuild_layout(app.layout_area); + assert_eq!(app.app_layout.alignment_header.local_feature_rows, 2); + + app.execute_commands([Command::JumpToPosition(50)]); + + assert_eq!(app.ui.viewport.offsets.cols, 50); + assert_eq!(app.app_layout.alignment_header.local_feature_rows, 1); + } + #[tokio::test(flavor = "current_thread")] async fn translation_toggle_keeps_selection() { let mut app = diff --git a/salti/src/core/gff.rs b/salti/src/core/gff.rs index e990113..343d94d 100644 --- a/salti/src/core/gff.rs +++ b/salti/src/core/gff.rs @@ -115,10 +115,10 @@ pub fn parse_gff(path: &Path) -> Result { fn extract_name(record: &gff::feature::RecordBuf) -> String { const POSSIBLE_NAMES: [&[u8]; 4] = [b"Name", b"ID", b"gene_name", b"product"]; - // try get names in order of preference, or falls back to record type so something is shown + // try get names in order of preference, or falls back to record type so at at least something is shown POSSIBLE_NAMES .iter() - .filter_map(|tag| record.attributes().get(*tag)) + .filter_map(|tag| record.attributes().get(tag)) .filter_map(|value| value.as_string()) .find(|name| !name.is_empty()) .map_or_else(|| record.ty().to_string(), |name| name.to_string()) diff --git a/salti/src/input/mouse.rs b/salti/src/input/mouse.rs index 937cf84..caab2bc 100644 --- a/salti/src/input/mouse.rs +++ b/salti/src/input/mouse.rs @@ -550,7 +550,7 @@ mod tests { #[test] fn gff_hover_sets_tooltip() { - let model = alignment_model(vec![raw("seq1", &vec![b'A'; 100])]); + let model = alignment_model(vec![raw("seq1", &[b'A'; 100])]); let gff = Gff { features: vec![feature("gene1", 0, 100)], }; @@ -590,7 +590,7 @@ mod tests { #[test] fn gff_drag_emits_jump() { - let model = alignment_model(vec![raw("seq1", &vec![b'A'; 100])]); + let model = alignment_model(vec![raw("seq1", &[b'A'; 100])]); let gff = Gff { features: vec![feature("gene1", 0, 100)], }; diff --git a/salti/src/ui/features.rs b/salti/src/ui/features.rs new file mode 100644 index 0000000..5fe4cd9 --- /dev/null +++ b/salti/src/ui/features.rs @@ -0,0 +1,224 @@ +use std::{num::NonZeroUsize, ops::Range}; + +use ratatui::style::Style; + +use crate::{ + core::{ + gff::{Feature, Gff}, + model::AlignmentModel, + }, + ui::ui_state::ThemeState, +}; + +const NUCLEOTIDE_POSITIONS_PER_COL: NonZeroUsize = NonZeroUsize::new(1).unwrap(); +const PROTEIN_POSITIONS_PER_COL: NonZeroUsize = NonZeroUsize::new(3).unwrap(); + +#[derive(Debug, Clone)] +pub(crate) struct DisplayFeature<'a> { + pub(crate) feature: &'a Feature, + pub(crate) relative_col_range: Range, + pub(crate) colour_idx: usize, +} + +#[derive(Debug, Clone, Copy)] +pub(crate) struct FeatureStyle { + pub(crate) background: Style, + pub(crate) text: Style, +} + +#[derive(Debug, Clone, Copy)] +pub(crate) struct FeatureMap { + absolute_total_columns: usize, + offset: usize, + positions_to_col: NonZeroUsize, +} + +impl FeatureMap { + pub(crate) fn for_alignment(alignment: &AlignmentModel) -> Self { + let absolute_total_columns = alignment.base().column_count(); + + if alignment.is_reloaded_as_protein() { + Self::protein( + absolute_total_columns, + alignment.translation_frame().offset(), + ) + } else { + Self::nucleotide(absolute_total_columns) + } + } + + pub(crate) fn protein(absolute_total_columns: usize, frame_offset: usize) -> Self { + Self { + absolute_total_columns, + offset: frame_offset, + positions_to_col: PROTEIN_POSITIONS_PER_COL, + } + } + + fn nucleotide(absolute_total_columns: usize) -> Self { + Self { + absolute_total_columns, + offset: 0, + positions_to_col: NUCLEOTIDE_POSITIONS_PER_COL, + } + } + + pub(crate) fn map_feature( + &self, + view: &libmsa::Alignment, + feature: &Feature, + ) -> Option> { + let absolute_range = self.map_feature_absolute_range(feature)?; + view.relative_column_range_intersecting(absolute_range) + } + + fn map_feature_absolute_range(&self, feature: &Feature) -> Option> { + let positions_to_col = self.positions_to_col.get(); + let start = feature.range.start.saturating_sub(self.offset) / positions_to_col; + let end = feature + .range + .end + .saturating_sub(self.offset) + .div_ceil(positions_to_col); + let clipped_range = + start.min(self.absolute_total_columns)..end.min(self.absolute_total_columns); + (!clipped_range.is_empty()).then_some(clipped_range) + } +} + +pub(crate) fn display_features<'a>( + gff: &'a Gff, + alignment: &AlignmentModel, +) -> Vec> { + let mapping = FeatureMap::for_alignment(alignment); + gff.features + .iter() + .filter_map(|feature| { + mapping + .map_feature(alignment.view(), feature) + .map(|range| (feature, range)) + }) + .enumerate() + .map( + |(colour_idx, (feature, relative_col_range))| DisplayFeature { + feature, + relative_col_range, + colour_idx, + }, + ) + .collect() +} + +pub(crate) fn feature_style(theme: &ThemeState, colour_idx: usize) -> FeatureStyle { + let dna = theme.theme.sequence.dna; + let colour = match colour_idx % 4 { + 0 => dna.a, + 1 => dna.t, + 2 => dna.c, + _ => dna.g, + }; + let background = theme.styles.base_block.bg(colour); + let text = background.fg(theme.theme.sequence.foreground); + FeatureStyle { background, text } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::core::gff::Strand; + + fn feature(start: usize, end: usize) -> Feature { + Feature { + name: "gene".to_owned(), + kind: crate::core::gff::FeatureType::Gene, + range: start..end + 1, + strand: Strand::Forward, + } + } + + fn raw(sequence: &[u8]) -> libmsa::RawSequence { + libmsa::RawSequence { + id: "seq".to_owned(), + sequence: sequence.to_vec(), + } + } + + fn model_with_sequence(sequence: &[u8]) -> AlignmentModel { + let alignment = libmsa::Alignment::new(vec![raw(sequence)]).unwrap(); + AlignmentModel::new(alignment).unwrap() + } + + fn model_with_len(len: usize) -> AlignmentModel { + let alignment = libmsa::Alignment::new(vec![libmsa::RawSequence { + id: "seq".to_owned(), + sequence: vec![b'A'; len], + }]) + .unwrap(); + AlignmentModel::new(alignment).unwrap() + } + + #[test] + fn filtered_nt_collapses_hidden_cols() { + let mut model = model_with_sequence(b"-A-CC--G"); + model.set_gap_filter(Some(0.0)).unwrap(); + let mapping = FeatureMap::for_alignment(&model); + + assert!(model.view().absolute_column_ids().eq([1, 3, 4, 7])); + assert_eq!( + mapping.map_feature(model.view(), &feature(2, 6)), + Some(1..3) + ); + } + + #[test] + fn filtered_nt_hides_feature() { + let mut model = model_with_sequence(b"-A-CC--G"); + model.set_gap_filter(Some(0.0)).unwrap(); + let mapping = FeatureMap::for_alignment(&model); + + assert_eq!(mapping.map_feature(model.view(), &feature(5, 6)), None); + } + + #[test] + fn filtered_protein_projects_cols() { + let mut model = model_with_sequence(b"M-M-M"); + model.set_gap_filter(Some(0.0)).unwrap(); + let mapping = FeatureMap::protein(5, 0); + + assert!(model.view().absolute_column_ids().eq([0, 2, 4])); + assert_eq!( + mapping.map_feature(model.view(), &feature(3, 8)), + Some(1..2) + ); + } + + #[test] + fn protein_clips_before_frame() { + let model = model_with_len(5); + let mapping = FeatureMap::protein(5, 2); + + assert_eq!( + mapping.map_feature(model.view(), &feature(0, 4)), + Some(0..1) + ); + } + + #[test] + fn mapping_clips_past_alignment_end() { + let model = model_with_len(8); + let mapping = FeatureMap::for_alignment(&model); + + assert_eq!( + mapping.map_feature(model.view(), &feature(6, 10)), + Some(6..8) + ); + } + + #[test] + fn mapping_hides_after_alignment_end() { + let model = model_with_len(8); + let mapping = FeatureMap::for_alignment(&model); + + assert_eq!(mapping.map_feature(model.view(), &feature(10, 12)), None); + } +} diff --git a/salti/src/ui/layers/palette/command_definitions.rs b/salti/src/ui/layers/palette/command_definitions.rs index a3a5ded..ea97f79 100644 --- a/salti/src/ui/layers/palette/command_definitions.rs +++ b/salti/src/ui/layers/palette/command_definitions.rs @@ -88,7 +88,7 @@ pub(super) const COMMAND_SPECS: &[PaletteCommand] = &[ }), PaletteCommand::Typable(TypableCommand { name: "filter-constant", - help_text: "Hide columns when a counted symbol reaches the given percentage. Gaps and type-specific unknowns are ignored. Use 0 to disable it.", + help_text: "Hide columns when a counted position reaches the given percentage. Gaps and unknowns are ignored. Use 0 to disable it.", aliases: &[], completer: None, static_candidates: &["0", "70", "90", "95", "100"], diff --git a/salti/src/ui/layers/palette/completers.rs b/salti/src/ui/layers/palette/completers.rs index 68532f5..5629ca4 100644 --- a/salti/src/ui/layers/palette/completers.rs +++ b/salti/src/ui/layers/palette/completers.rs @@ -1,4 +1,4 @@ -use std::{fs, path::PathBuf}; +use std::{fs, path::Path}; use super::input::CommandPaletteState; @@ -76,12 +76,12 @@ fn join_display_path(dir_prefix: &str, name: &str) -> String { pub(super) fn filename(_: &CommandPaletteState, arguments: &str) -> Vec { let (dir_prefix, name_prefix) = split_dir_and_prefix(arguments); let base_dir = if dir_prefix.is_empty() { - PathBuf::from(".") + Path::new(".") } else { - PathBuf::from(dir_prefix) + Path::new(dir_prefix) }; - let Ok(entries) = fs::read_dir(base_dir.as_path()) else { + let Ok(entries) = fs::read_dir(base_dir) else { return Vec::new(); }; @@ -89,16 +89,14 @@ pub(super) fn filename(_: &CommandPaletteState, arguments: &str) -> Vec for entry in entries.flatten() { let entry_name = entry.file_name(); - let Some(entry_name) = entry_name.to_str() else { - continue; - }; + let entry_name = entry_name.to_string_lossy(); if !entry_name.starts_with(name_prefix) { continue; } - let is_dir = entry.path().is_dir(); - let mut label = join_display_path(dir_prefix, entry_name); + let is_dir = entry.file_type().is_ok_and(|kind| kind.is_dir()); + let mut label = join_display_path(dir_prefix, &entry_name); if is_dir { label.push('/'); } diff --git a/salti/src/ui/layers/palette/input.rs b/salti/src/ui/layers/palette/input.rs index ecd4a97..ad6d6a3 100644 --- a/salti/src/ui/layers/palette/input.rs +++ b/salti/src/ui/layers/palette/input.rs @@ -167,18 +167,17 @@ impl CommandPaletteState { Some(command) } - fn parse_command_input(&self) -> Option<(String, Option)> { - let input = self.command_input.trim(); + fn parse_command_input(input: &str) -> Option<(&str, Option<&str>)> { + let input = input.trim(); if input.is_empty() { return None; } if let Some((command_name, rest)) = input.split_once(char::is_whitespace) { let arguments = rest.trim(); - let arguments = (!arguments.is_empty()).then_some(arguments.to_string()); - Some((command_name.to_string(), arguments)) + Some((command_name, (!arguments.is_empty()).then_some(arguments))) } else { - Some((input.to_string(), None)) + Some((input, None)) } } @@ -297,10 +296,11 @@ impl CommandPaletteState { } fn submit_command_selection(&mut self) -> Vec { - let Some((command_name, arguments)) = self.parse_command_input() else { + let input = std::mem::take(&mut self.command_input); + let Some((command_name, arguments)) = Self::parse_command_input(input.as_str()) else { return self.command_error(&format_err!("No command selected")); }; - let Some(spec) = resolve_command(command_name.as_str()) else { + let Some(spec) = resolve_command(command_name) else { return self.command_error(&format_err!("Unknown command")); }; let command_selected = self.command_list.selected_display_index().is_some(); @@ -311,7 +311,7 @@ impl CommandPaletteState { if spec.typable().is_none() { return self.command_error(&format_err!("Expected 0 arguments, got 1")); } - return match spec.run(self, arguments.as_str()) { + return match spec.run(self, arguments) { Ok(action) => self.close_palette_with(action), Err(error) => self.command_error(&error), }; diff --git a/salti/src/ui/layers/palette/ui.rs b/salti/src/ui/layers/palette/ui.rs index ef36c4b..6720731 100644 --- a/salti/src/ui/layers/palette/ui.rs +++ b/salti/src/ui/layers/palette/ui.rs @@ -2,7 +2,7 @@ use ratatui::{ Frame, layout::Rect, style::Styled, - text::Line, + text::{Line, Span}, widgets::{Block, Clear, Paragraph, Widget}, }; @@ -238,14 +238,18 @@ impl CommandPaletteState { } fn render_input(&self, f: &mut Frame, area: Rect, theme: &crate::config::theme::ThemeStyles) { - let input = match self.phase { - PaletteState::Command => format!(":{}", self.command_input), - PaletteState::Argument { .. } => { - format!(":{} {}", self.command_input, self.argument_input) - } - }; + let mut spans = vec![ + Span::styled(":", theme.warning), + Span::styled(self.command_input.as_str(), theme.warning), + ]; + + if matches!(self.phase, PaletteState::Argument { .. }) { + spans.push(Span::styled(" ", theme.warning)); + spans.push(Span::styled(self.argument_input.as_str(), theme.warning)); + } - let line = Line::from(format!("{input}█").set_style(theme.warning)); + spans.push(Span::styled("█", theme.warning)); + let line = Line::from(spans); f.render_widget(Paragraph::new(line).style(theme.base_block), area); } diff --git a/salti/src/ui/layout.rs b/salti/src/ui/layout.rs index 0e41c0d..bd01979 100644 --- a/salti/src/ui/layout.rs +++ b/salti/src/ui/layout.rs @@ -12,6 +12,32 @@ pub const RULER_HEIGHT_ROWS: u16 = 2; /// the remaining horizontal space is used for sequence content. const SEQUENCE_ID_PANE_WIDTH_PERCENT: u16 = 20; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AlignmentHeaderLayout { + pub local_feature_rows: u16, + pub ruler_rows: u16, +} + +impl AlignmentHeaderLayout { + pub(crate) fn without_features() -> Self { + Self { + local_feature_rows: 0, + ruler_rows: RULER_HEIGHT_ROWS, + } + } + + pub(crate) fn with_features(local_feature_rows: u16) -> Self { + Self { + local_feature_rows, + ruler_rows: RULER_HEIGHT_ROWS, + } + } + + pub(crate) fn height(self) -> u16 { + self.local_feature_rows.saturating_add(self.ruler_rows) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct PinnedSectionLayout { pub pinned_rendered: usize, @@ -68,6 +94,7 @@ pub struct AppLayout { pub sequence_id_pane: Rect, pub alignment_pane: Rect, pub alignment_pane_sequence_rows: Rect, + pub alignment_header: AlignmentHeaderLayout, pub consensus_sequence_id_pane: Rect, pub consensus_alignment_pane: Rect, pub gff_info_pane: Rect, @@ -76,7 +103,11 @@ pub struct AppLayout { } impl AppLayout { - pub fn new(content_area: Rect, gff_height: u16) -> Self { + pub fn new( + content_area: Rect, + gff_height: u16, + alignment_header: AlignmentHeaderLayout, + ) -> Self { let [gff_area, main_area] = content_area.layout(&vertical![==gff_height, *=1].spacing(Spacing::Overlap(1))); @@ -92,9 +123,12 @@ impl AppLayout { ] = consensus_area.layout( &horizontal![==SEQUENCE_ID_PANE_WIDTH_PERCENT%, *=1].spacing(Spacing::Overlap(1)), ); - let [_, sequence_rows_area] = ratatui::widgets::Block::bordered() - .inner(alignment_pane_area) - .layout(&vertical![==RULER_HEIGHT_ROWS, *=1]); + let inner_alignment_pane = ratatui::widgets::Block::bordered().inner(alignment_pane_area); + let [_, _, sequence_rows_area] = inner_alignment_pane.layout(&vertical![ + ==alignment_header.local_feature_rows, + ==alignment_header.ruler_rows, + *=1 + ]); let [gff_info_pane_area, gff_pane_area] = gff_area.layout( &horizontal![==SEQUENCE_ID_PANE_WIDTH_PERCENT%, *=1].spacing(Spacing::Overlap(1)), @@ -109,6 +143,7 @@ impl AppLayout { sequence_id_pane: sequence_id_pane_area, alignment_pane: alignment_pane_area, alignment_pane_sequence_rows: sequence_rows_area, + alignment_header, consensus_sequence_id_pane: consensus_sequence_id_pane_area, consensus_alignment_pane: consensus_alignment_pane_area, gff_info_pane: gff_info_pane_area, diff --git a/salti/src/ui/mod.rs b/salti/src/ui/mod.rs index 62d6e33..520fc78 100644 --- a/salti/src/ui/mod.rs +++ b/salti/src/ui/mod.rs @@ -1,3 +1,4 @@ +pub(crate) mod features; pub(crate) mod layers; pub(crate) mod layout; pub(crate) mod panes; diff --git a/salti/src/ui/panes/alignment.rs b/salti/src/ui/panes/alignment.rs index 3209da8..aa90517 100644 --- a/salti/src/ui/panes/alignment.rs +++ b/salti/src/ui/panes/alignment.rs @@ -11,13 +11,15 @@ use ratatui::{ use crate::{ core::{ codon::TranslatedDiffRange, + gff::Gff, model::{AlignmentModel, DiffMode}, stats_cache::ColumnStatsCache, viewport::{Viewport, ViewportWindow}, }, ui::{ - layout::{PinnedSectionLayout, RULER_HEIGHT_ROWS, pinned_section_layout}, - rows::{RowRenderMode, format_row_spans, format_translated_row_spans, visible_bytes}, + layout::{AlignmentHeaderLayout, PinnedSectionLayout, pinned_section_layout}, + panes::{local_feature_track::LocalFeatureTrack, ruler::Ruler}, + rows::{RowRenderMode, format_row_view_spans, format_translated_row_spans, visible_bytes}, ui_state::ThemeState, }, }; @@ -29,6 +31,8 @@ pub(crate) struct AlignmentPane<'a> { pub(crate) alignment: &'a AlignmentModel, pub(crate) viewport: &'a Viewport, pub(crate) metrics: &'a ColumnStatsCache, + pub(crate) gff: Option<&'a Gff>, + pub(crate) header: AlignmentHeaderLayout, pub(crate) theme: &'a ThemeState, } @@ -41,11 +45,28 @@ impl Widget for AlignmentPane<'_> { let inner_area = block.inner(area); block.render(area, buf); - let [ruler_area, sequence_rows_area] = - inner_area.layout(&vertical![==RULER_HEIGHT_ROWS, *=1]); + let [local_feature_area, ruler_area, sequence_rows_area] = inner_area.layout(&vertical![ + ==self.header.local_feature_rows, + ==self.header.ruler_rows, + *=1 + ]); let window = self.viewport.window(); - render_ruler(self.alignment, &window, ruler_area, self.theme, buf); + if let Some(gff) = self.gff { + LocalFeatureTrack { + gff, + alignment: self.alignment, + window: &window, + theme: self.theme, + } + .render(local_feature_area, buf); + } + Ruler { + alignment: self.alignment, + window: &window, + theme: self.theme, + } + .render(ruler_area, buf); render_sequence_rows( self.alignment, &window, @@ -234,8 +255,12 @@ fn build_sequence_row_lines( theme, &mut |absolute_row| { let projected_row = alignment.view().project_absolute_row(absolute_row)?; - let bytes = visible_bytes(projected_row, &window.col_range); - let spans = format_row_spans(&bytes, &theme.theme.sequence, render_mode); + let spans = format_row_view_spans( + projected_row, + &window.col_range, + &theme.theme.sequence, + render_mode, + ); Some(Line::from(spans)) }, ); @@ -315,230 +340,6 @@ fn render_scrollbar( } } -fn add_number_to_ruler( - number_line: &mut [Span<'static>], - centre_pos: usize, - number: usize, - theme: &ThemeState, -) -> bool { - let number_string = number.to_string(); - let number_length = number_string.len(); - let ruler_width = number_line.len(); - let start_idx = centre_pos - .saturating_sub(number_length / 2) - .min(ruler_width.saturating_sub(number_length)); - let left_padding = start_idx.saturating_sub(1); - let right_padding = (start_idx + number_length + 1).min(ruler_width); - - if number_line[left_padding..right_padding] - .iter() - .any(|span| span.content.as_ref() != " ") - { - return false; - } - - for (offset, digit) in number_string.chars().enumerate() { - if let Some(cell) = number_line.get_mut(start_idx + offset) { - *cell = digit.to_string().set_style(theme.styles.accent); - } - } - - true -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum BreakMarker { - Leading, - Trailing, -} - -fn break_positions( - absolute_columns: &[usize], - filtered_leading: bool, - filtered_trailing: bool, -) -> Vec<(usize, BreakMarker)> { - let width = absolute_columns.len(); - if width == 0 { - return Vec::new(); - } - - let mut breaks = Vec::new(); - - if filtered_leading { - breaks.push((0, BreakMarker::Leading)); - } - - for (index, pair) in absolute_columns.windows(2).enumerate() { - if pair[1] != pair[0] + 1 { - breaks.push((index, BreakMarker::Trailing)); - } - } - - if filtered_trailing { - let last = width - 1; - if !breaks.iter().any(|&(position, _)| position == last) { - breaks.push((last, BreakMarker::Trailing)); - } - } - - breaks -} - -fn dense_break_marker_position(position: usize, marker: BreakMarker, width: usize) -> usize { - match marker { - BreakMarker::Leading => position, - BreakMarker::Trailing => { - if position + 1 < width { - position + 1 - } else { - position - } - } - } -} - -fn dense_break_spans(breaks: &[(usize, BreakMarker)], width: usize) -> Vec<(usize, usize)> { - let marker_positions: Vec = breaks - .iter() - .map(|&(position, marker)| dense_break_marker_position(position, marker, width)) - .collect(); - let mut spans = Vec::new(); - let mut cluster_start = 0; - - while cluster_start < marker_positions.len() { - let mut cluster_end = cluster_start + 1; - while cluster_end < marker_positions.len() - && marker_positions[cluster_end] <= marker_positions[cluster_end - 1] + 3 - { - cluster_end += 1; - } - - if cluster_end - cluster_start >= 2 { - spans.push(( - marker_positions[cluster_start], - marker_positions[cluster_end - 1], - )); - } - - cluster_start = cluster_end; - } - - spans -} - -fn run_start_positions(absolute_columns: &[usize]) -> Vec { - let mut starts = Vec::new(); - if absolute_columns.is_empty() { - return starts; - } - - starts.push(0); - for (index, pair) in absolute_columns.windows(2).enumerate() { - if pair[1] != pair[0] + 1 { - starts.push(index + 1); - } - } - - starts -} - -fn build_ruler( - absolute_columns: &[usize], - filtered_leading: bool, - filtered_trailing: bool, - theme: &ThemeState, -) -> (Line<'static>, Line<'static>) { - let width = absolute_columns.len(); - if width == 0 { - return (Line::from(""), Line::from("")); - } - - let mut number_line = vec![Span::raw(" "); width]; - let mut marker_line = vec![Span::raw(" "); width]; - let breaks = break_positions(absolute_columns, filtered_leading, filtered_trailing); - let fragmented_view = !breaks.is_empty(); - let run_starts = fragmented_view.then(|| run_start_positions(absolute_columns)); - - for (index, marker_span) in marker_line.iter_mut().enumerate() { - let display_pos = absolute_columns[index] + 1; - if display_pos == 1 || display_pos.is_multiple_of(5) { - let is_major_tick = display_pos.is_multiple_of(10); - *marker_span = if is_major_tick { - "|".set_style(theme.styles.accent) - } else { - ".".set_style(theme.styles.text_dim) - }; - - let is_run_start = run_starts - .as_ref() - .is_some_and(|run_starts| run_starts.contains(&index)); - if is_major_tick || display_pos == 1 || is_run_start { - let _ = add_number_to_ruler(&mut number_line, index, display_pos, theme); - } - } - } - - let dense_spans = dense_break_spans(&breaks, width); - - for (position, marker) in breaks { - let marker_position = dense_break_marker_position(position, marker, width); - if dense_spans - .iter() - .any(|&(start, end)| start <= marker_position && marker_position <= end) - { - continue; - } - - let symbol = match marker { - BreakMarker::Leading => "‹", - BreakMarker::Trailing => "›", - }; - marker_line[position] = symbol.set_style(theme.styles.warning); - } - - for (start, end) in dense_spans { - for marker in marker_line.iter_mut().take(end + 1).skip(start) { - *marker = "~".set_style(theme.styles.warning); - } - } - - (Line::from(number_line), Line::from(marker_line)) -} - -fn render_ruler( - alignment: &AlignmentModel, - window: &ViewportWindow, - area: Rect, - theme: &ThemeState, - buf: &mut Buffer, -) { - let absolute_columns: Vec = window - .col_range - .clone() - .filter_map(|relative_col| alignment.view().absolute_column_id(relative_col)) - .collect(); - let filtered_leading = window.col_range.start == 0 - && alignment - .view() - .absolute_column_id(0) - .is_some_and(|first| first > 0); - let filtered_trailing = window.col_range.end >= alignment.view().column_count() - && alignment.base().column_count() > 0 - && alignment - .view() - .absolute_column_id(alignment.view().column_count().saturating_sub(1)) - .is_some_and(|last| last < alignment.base().column_count() - 1); - let (number_line, marker_line) = build_ruler( - &absolute_columns, - filtered_leading, - filtered_trailing, - theme, - ); - Paragraph::new(vec![number_line, marker_line]) - .style(theme.styles.base_block) - .render(area, buf); -} - #[cfg(test)] mod tests { use ratatui::buffer::Buffer; diff --git a/salti/src/ui/panes/consensus.rs b/salti/src/ui/panes/consensus.rs index 5202454..405d19c 100644 --- a/salti/src/ui/panes/consensus.rs +++ b/salti/src/ui/panes/consensus.rs @@ -16,8 +16,8 @@ use crate::{ }, ui::{ rows::{ - RowRenderMode, format_row_spans, format_translated_byte_range_spans, - format_translated_row_spans, visible_bytes, + RowRenderMode, format_row_spans, format_row_view_spans, + format_translated_byte_range_spans, format_translated_row_spans, }, ui_state::ThemeState, }, @@ -223,8 +223,12 @@ fn consensus_alignment_lines( let Some(projected_row) = alignment.view().project_absolute_row(absolute_row) else { return Line::from("No reference selected".fg(theme.theme.text_dim).italic()); }; - let bytes = visible_bytes(projected_row, &window.col_range); - let spans = format_row_spans(&bytes, &theme.theme.sequence, no_diff_mode); + let spans = format_row_view_spans( + projected_row, + &window.col_range, + &theme.theme.sequence, + no_diff_mode, + ); Line::from(spans) }, ); diff --git a/salti/src/ui/panes/gff.rs b/salti/src/ui/panes/gff.rs index e81ee81..e5bbe7f 100644 --- a/salti/src/ui/panes/gff.rs +++ b/salti/src/ui/panes/gff.rs @@ -17,13 +17,13 @@ use crate::{ model::AlignmentModel, }, input::movement::HorizontalDrag, - ui::ui_state::ThemeState, + ui::{ + features::{DisplayFeature, display_features, feature_style}, + ui_state::ThemeState, + }, }; const MIN_LABEL_WIDTH: usize = 2; -const NUCLEOTIDE_POSITIONS_PER_COL: usize = 1; -const PROTEIN_POSITIONS_PER_COL: usize = 3; - pub(crate) struct GffPane<'a> { pub(crate) gff: &'a Gff, pub(crate) alignment: &'a AlignmentModel, @@ -147,70 +147,6 @@ impl GffPaneState { } } -#[derive(Debug, Clone, Copy)] -pub(crate) struct FeatureMap { - total_columns: usize, - absolute_total_columns: usize, - offset: usize, - // proteins use three nucleotide positions per displayed column; nucleotides use one. - positions_to_col: usize, -} - -impl FeatureMap { - pub(crate) fn for_alignment(alignment: &AlignmentModel) -> Self { - let visible_columns = alignment.view().column_count(); - let absolute_total_columns = alignment.base().column_count(); - if alignment.is_reloaded_as_protein() { - Self::protein( - visible_columns, - absolute_total_columns, - alignment.translation_frame().offset(), - ) - } else { - Self::nucleotide(visible_columns, absolute_total_columns) - } - } - - fn nucleotide(total_columns: usize, absolute_total_columns: usize) -> Self { - Self { - total_columns, - absolute_total_columns, - offset: 0, - positions_to_col: NUCLEOTIDE_POSITIONS_PER_COL, - } - } - - fn protein(total_columns: usize, absolute_total_columns: usize, frame_offset: usize) -> Self { - Self { - total_columns, - absolute_total_columns, - offset: frame_offset, - positions_to_col: PROTEIN_POSITIONS_PER_COL, - } - } - - pub(crate) fn map_feature( - &self, - view: &libmsa::Alignment, - feature: &Feature, - ) -> Option> { - let absolute_range = self.map_feature_absolute_range(feature)?; - view.relative_column_range_intersecting(absolute_range) - } - - fn map_feature_absolute_range(&self, feature: &Feature) -> Option> { - let start = feature.range.start.saturating_sub(self.offset) / self.positions_to_col; - let end = feature - .range - .end - .saturating_sub(self.offset) - .div_ceil(self.positions_to_col); - let clipped_range = - start.min(self.absolute_total_columns)..end.min(self.absolute_total_columns); - (!clipped_range.is_empty()).then_some(clipped_range) - } -} - pub(crate) fn tooltip_at( gff: &Gff, alignment: &AlignmentModel, @@ -271,12 +207,8 @@ fn format_tooltip(feature: &Feature) -> String { fn render_features(track: &FeatureTrack<'_>, inner: Rect, theme: &ThemeState, buf: &mut Buffer) { let width = usize::from(inner.width); let max_row = usize::from(inner.height); - let foreground = theme.theme.sequence.foreground; - let dna = theme.theme.sequence.dna; - let palette = [dna.a, dna.t, dna.c, dna.g]; let blank = (' ', theme.styles.base_block); let mut cells = vec![blank; width * max_row]; - let mut feature_idx = 0; for placed_feature in track.placed_features() { if placed_feature.row >= max_row { @@ -284,18 +216,17 @@ fn render_features(track: &FeatureTrack<'_>, inner: Rect, theme: &ThemeState, bu } let feature = placed_feature.feature; - let feature_span = placed_feature.span.clone(); - let colour = palette[feature_idx % palette.len()]; - let feature_style = theme.styles.base_block.bg(colour); - let text_style = feature_style.fg(foreground); - feature_idx += 1; + let feature_span = &placed_feature.span; + let styles = feature_style(theme, placed_feature.colour_idx); + let feature_style = styles.background; + let text_style = styles.text; - for x in feature_span.clone() { + for x in feature_span.start..feature_span.end { let idx = placed_feature.row * width + x; cells[idx] = (' ', feature_style); } - let available = feature_span.end - feature_span.start; + let available = feature_span.len(); let (label_x, label_width, strand_arrow) = match feature.strand { Strand::Forward if 0 < available => ( feature_span.start, @@ -366,18 +297,19 @@ struct FeatureTrack<'a> { impl<'a> FeatureTrack<'a> { fn for_alignment(gff: &'a Gff, alignment: &AlignmentModel, available_width: usize) -> Self { - let mapping = FeatureMap::for_alignment(alignment); - let width = available_width.min(mapping.total_columns); - let placed_features = placed_features(gff, alignment.view(), &mapping, width); + let total_columns = alignment.view().column_count(); + let width = available_width.min(total_columns); + let display_features = display_features(gff, alignment); + let placed_features = placed_features(&display_features, width, total_columns); Self { placed_features, - total_columns: mapping.total_columns, + total_columns, width, } } fn total_columns_for_alignment(alignment: &AlignmentModel) -> usize { - FeatureMap::for_alignment(alignment).total_columns + alignment.view().column_count() } fn total_columns(&self) -> usize { @@ -413,20 +345,20 @@ struct PlacedFeature<'a> { feature: &'a Feature, span: Range, row: usize, + colour_idx: usize, } fn placed_features<'a>( - gff: &'a Gff, - view: &libmsa::Alignment, - mapping: &FeatureMap, + display_features: &[DisplayFeature<'a>], width: usize, + total_columns: usize, ) -> Vec> { let mut res = Vec::new(); let mut alternating_row = 0; let mut stack_offset = 0; - for feature in &gff.features { - let Some(span) = feature_drawn_span(feature, view, mapping, width) else { + for display_feature in display_features { + let Some(span) = feature_drawn_span(display_feature, width, total_columns) else { continue; }; @@ -441,37 +373,43 @@ fn placed_features<'a>( stack_offset = 0; alternating_row }; - res.push(PlacedFeature { feature, span, row }); + res.push(PlacedFeature { + feature: display_feature.feature, + span, + row, + colour_idx: display_feature.colour_idx, + }); } res } fn feature_drawn_span( - feature: &Feature, - view: &libmsa::Alignment, - mapping: &FeatureMap, + display_feature: &DisplayFeature<'_>, width: usize, + total_columns: usize, ) -> Option> { - let screen_span = feature_screen_span(feature, view, mapping, width)?; + let screen_span = feature_screen_span(display_feature, width, total_columns)?; let drawn_width = screen_span.len().saturating_sub(1).max(1); Some(screen_span.start..screen_span.start + drawn_width) } fn feature_screen_span( - feature: &Feature, - view: &libmsa::Alignment, - mapping: &FeatureMap, + display_feature: &DisplayFeature<'_>, width: usize, + total_columns: usize, ) -> Option> { - let total_columns = mapping.total_columns; if width == 0 || total_columns == 0 { return None; } - let mapped_span = mapping.map_feature(view, feature)?; - let x_start = mapped_span.start.saturating_mul(width) / total_columns; - let x_end = mapped_span + let x_start = display_feature + .relative_col_range + .start + .saturating_mul(width) + / total_columns; + let x_end = display_feature + .relative_col_range .end .saturating_mul(width) .div_ceil(total_columns) diff --git a/salti/src/ui/panes/local_feature_track.rs b/salti/src/ui/panes/local_feature_track.rs new file mode 100644 index 0000000..9e3d985 --- /dev/null +++ b/salti/src/ui/panes/local_feature_track.rs @@ -0,0 +1,279 @@ +use std::ops::Range; + +use ratatui::{ + buffer::Buffer, + layout::Rect, + text::{Line, Span}, + widgets::{Paragraph, Widget}, +}; + +use crate::{ + core::{ + gff::{Feature, Gff, Strand}, + model::AlignmentModel, + viewport::ViewportWindow, + }, + ui::{ + features::{DisplayFeature, FeatureMap, display_features, feature_style}, + ui_state::ThemeState, + }, +}; + +const MAX_LOCAL_FEATURE_ROWS: usize = 5; +const MIN_LABEL_WIDTH: usize = 1; + +pub(crate) struct LocalFeatureTrack<'a> { + pub(crate) gff: &'a Gff, + pub(crate) alignment: &'a AlignmentModel, + pub(crate) window: &'a ViewportWindow, + pub(crate) theme: &'a ThemeState, +} + +impl Widget for LocalFeatureTrack<'_> { + fn render(self, area: Rect, buf: &mut Buffer) { + if area.width == 0 || area.height == 0 { + return; + } + + let display_features = display_features(self.gff, self.alignment); + let placed_features = place_visible_features(&display_features, &self.window.col_range); + render_features(&placed_features, area, self.theme, buf); + } +} + +pub(crate) fn local_feature_row_count( + gff: &Gff, + alignment: &AlignmentModel, + col_range: &Range, +) -> usize { + let mapping = FeatureMap::for_alignment(alignment); + let mut row_ends = [0; MAX_LOCAL_FEATURE_ROWS]; + let mut row_count = 0; + + for feature in &gff.features { + let Some(relative_col_range) = mapping.map_feature(alignment.view(), feature) else { + continue; + }; + let Some(visible_range) = intersect(&relative_col_range, col_range) else { + continue; + }; + let span = visible_range.start - col_range.start..visible_range.end - col_range.start; + let Some(row) = row_ends.iter().position(|&row_end| row_end <= span.start) else { + continue; + }; + row_ends[row] = span.end; + row_count = row_count.max(row + 1); + } + + row_count.max(1) +} + +#[derive(Debug, Clone)] +struct LocalPlacedFeature<'a> { + feature: &'a Feature, + span: Range, + row: usize, + colour_idx: usize, +} + +fn place_visible_features<'a>( + display_features: &[DisplayFeature<'a>], + col_range: &Range, +) -> Vec> { + let mut res: Vec> = Vec::new(); + let mut row_ends = [0; MAX_LOCAL_FEATURE_ROWS]; + + for display_feature in display_features { + let Some(visible_range) = intersect(&display_feature.relative_col_range, col_range) else { + continue; + }; + let span = visible_range.start - col_range.start..visible_range.end - col_range.start; + let Some(row) = row_ends.iter().position(|&row_end| row_end <= span.start) else { + continue; + }; + row_ends[row] = span.end; + res.push(LocalPlacedFeature { + feature: display_feature.feature, + span, + row, + colour_idx: display_feature.colour_idx, + }); + } + + res +} + +fn intersect(left: &Range, right: &Range) -> Option> { + let start = left.start.max(right.start); + let end = left.end.min(right.end); + (start < end).then_some(start..end) +} + +fn render_features( + placed_features: &[LocalPlacedFeature<'_>], + area: Rect, + theme: &ThemeState, + buf: &mut Buffer, +) { + let width = usize::from(area.width); + let height = usize::from(area.height); + let blank = (' ', theme.styles.base_block); + let mut cells = vec![blank; width * height]; + + for placed_feature in placed_features { + if height <= placed_feature.row { + continue; + } + let styles = feature_style(theme, placed_feature.colour_idx); + let span = placed_feature.span.start.min(width)..placed_feature.span.end.min(width); + if span.is_empty() { + continue; + } + + for x in span.clone() { + cells[placed_feature.row * width + x] = (' ', styles.background); + } + + draw_label( + &mut cells, + width, + placed_feature.row, + span, + placed_feature.feature, + styles.text, + ); + } + + let lines: Vec> = cells + .chunks(width) + .map(|row| { + let mut spans = Vec::new(); + let mut text = String::new(); + let mut current_style = row[0].1; + + for &(ch, style) in row { + if style != current_style && !text.is_empty() { + spans.push(Span::styled(std::mem::take(&mut text), current_style)); + current_style = style; + } + text.push(ch); + } + + if !text.is_empty() { + spans.push(Span::styled(text, current_style)); + } + + Line::from(spans) + }) + .collect(); + Paragraph::new(lines) + .style(theme.styles.base_block) + .render(area, buf); +} + +fn draw_label( + cells: &mut [(char, ratatui::style::Style)], + width: usize, + row: usize, + span: Range, + feature: &Feature, + text_style: ratatui::style::Style, +) { + let available = span.len(); + if available == 0 { + return; + } + + let (label_start, label_width, arrow) = match feature.strand { + Strand::Forward => ( + span.start, + available.saturating_sub(1), + Some((span.end - 1, '→')), + ), + Strand::Reverse => ( + span.start + 1, + available.saturating_sub(1), + Some((span.start, '←')), + ), + Strand::Unknown => (span.start, available, None), + }; + + if let Some((arrow_x, arrow)) = arrow { + cells[row * width + arrow_x] = (arrow, text_style); + } + + if label_width < MIN_LABEL_WIDTH { + return; + } + + let truncated: String = feature.name.chars().take(label_width).collect(); + let truncated_len = truncated.chars().count(); + let label_offset = (label_width - truncated_len) / 2; + let x_start = label_start + label_offset; + for (offset, ch) in truncated.chars().enumerate() { + cells[row * width + x_start + offset] = (ch, text_style); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::core::gff::FeatureType; + + fn feature_with_name(name: &str, start: usize, end: usize) -> Feature { + Feature { + name: name.to_string(), + kind: FeatureType::Gene, + range: start..end, + strand: Strand::Forward, + } + } + + fn raw(sequence: &[u8]) -> libmsa::RawSequence { + libmsa::RawSequence { + id: "seq".to_string(), + sequence: sequence.to_vec(), + } + } + + fn model_with_len(len: usize) -> AlignmentModel { + let alignment = libmsa::Alignment::new(vec![raw(&vec![b'A'; len])]).unwrap(); + AlignmentModel::new(alignment).unwrap() + } + + #[test] + fn local_feature_row_count_is_one_when_no_feature_is_visible() { + let gff = Gff { + features: vec![feature_with_name("left", 0, 5)], + }; + let model = model_with_len(20); + + assert_eq!(local_feature_row_count(&gff, &model, &(10..15)), 1); + } + + #[test] + fn local_features_stack_overlapping_visible_spans() { + let gff = Gff { + features: vec![ + feature_with_name("a", 0, 10), + feature_with_name("b", 2, 8), + feature_with_name("c", 10, 12), + ], + }; + let model = model_with_len(20); + + assert_eq!(local_feature_row_count(&gff, &model, &(0..12)), 2); + } + + #[test] + fn local_feature_rows_are_capped_at_five() { + let gff = Gff { + features: (0..8) + .map(|idx| feature_with_name(&format!("f{idx}"), 0, 10)) + .collect(), + }; + let model = model_with_len(20); + + assert_eq!(local_feature_row_count(&gff, &model, &(0..12)), 5); + } +} diff --git a/salti/src/ui/panes/mod.rs b/salti/src/ui/panes/mod.rs index b41e104..6c228ed 100644 --- a/salti/src/ui/panes/mod.rs +++ b/salti/src/ui/panes/mod.rs @@ -1,5 +1,7 @@ pub(crate) mod alignment; pub(crate) mod consensus; pub(crate) mod gff; +pub(crate) mod local_feature_track; +pub(crate) mod ruler; pub(crate) mod sequence_id; pub(crate) mod status_bars; diff --git a/salti/src/ui/panes/ruler.rs b/salti/src/ui/panes/ruler.rs new file mode 100644 index 0000000..c1a21a8 --- /dev/null +++ b/salti/src/ui/panes/ruler.rs @@ -0,0 +1,304 @@ +use ratatui::{ + buffer::Buffer, + layout::Rect, + style::Styled, + text::{Line, Span}, + widgets::{Paragraph, Widget}, +}; + +use crate::{ + core::{model::AlignmentModel, viewport::ViewportWindow}, + ui::ui_state::ThemeState, +}; + +pub(crate) struct Ruler<'a> { + pub(crate) alignment: &'a AlignmentModel, + pub(crate) window: &'a ViewportWindow, + pub(crate) theme: &'a ThemeState, +} + +impl Widget for Ruler<'_> { + fn render(self, area: Rect, buf: &mut Buffer) { + let absolute_columns: Vec = self + .window + .col_range + .clone() + .filter_map(|relative_col| self.alignment.view().absolute_column_id(relative_col)) + .collect(); + let filtered_leading = self.window.col_range.start == 0 + && self + .alignment + .view() + .absolute_column_id(0) + .is_some_and(|first| first > 0); + let filtered_trailing = self.window.col_range.end >= self.alignment.view().column_count() + && self.alignment.base().column_count() > 0 + && self + .alignment + .view() + .absolute_column_id(self.alignment.view().column_count().saturating_sub(1)) + .is_some_and(|last| last < self.alignment.base().column_count() - 1); + let (number_line, marker_line) = build_ruler( + &absolute_columns, + filtered_leading, + filtered_trailing, + self.theme, + ); + Paragraph::new(vec![number_line, marker_line]) + .style(self.theme.styles.base_block) + .render(area, buf); + } +} + +fn add_number_to_ruler( + number_line: &mut [Span<'static>], + centre_pos: usize, + number: usize, + theme: &ThemeState, +) -> bool { + let number_string = number.to_string(); + let number_length = number_string.len(); + let ruler_width = number_line.len(); + let start_idx = centre_pos + .saturating_sub(number_length / 2) + .min(ruler_width.saturating_sub(number_length)); + let left_padding = start_idx.saturating_sub(1); + let right_padding = (start_idx + number_length + 1).min(ruler_width); + + if number_line[left_padding..right_padding] + .iter() + .any(|span| span.content.as_ref() != " ") + { + return false; + } + + for (offset, digit) in number_string.chars().enumerate() { + if let Some(cell) = number_line.get_mut(start_idx + offset) { + *cell = digit.to_string().set_style(theme.styles.accent); + } + } + + true +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum BreakMarker { + Leading, + Trailing, +} + +fn break_positions( + absolute_columns: &[usize], + filtered_leading: bool, + filtered_trailing: bool, +) -> Vec<(usize, BreakMarker)> { + let width = absolute_columns.len(); + if width == 0 { + return Vec::new(); + } + + let mut breaks = Vec::new(); + + if filtered_leading { + breaks.push((0, BreakMarker::Leading)); + } + + for (index, pair) in absolute_columns.windows(2).enumerate() { + if pair[1] != pair[0] + 1 { + breaks.push((index, BreakMarker::Trailing)); + } + } + + if filtered_trailing { + let last = width - 1; + if !breaks.iter().any(|&(position, _)| position == last) { + breaks.push((last, BreakMarker::Trailing)); + } + } + + breaks +} + +fn dense_break_marker_position(position: usize, marker: BreakMarker, width: usize) -> usize { + match marker { + BreakMarker::Leading => position, + BreakMarker::Trailing => { + if position + 1 < width { + position + 1 + } else { + position + } + } + } +} + +fn dense_break_spans(breaks: &[(usize, BreakMarker)], width: usize) -> Vec<(usize, usize)> { + let marker_positions: Vec = breaks + .iter() + .map(|&(position, marker)| dense_break_marker_position(position, marker, width)) + .collect(); + let mut spans = Vec::new(); + let mut cluster_start = 0; + + while cluster_start < marker_positions.len() { + let mut cluster_end = cluster_start + 1; + while cluster_end < marker_positions.len() + && marker_positions[cluster_end] <= marker_positions[cluster_end - 1] + 3 + { + cluster_end += 1; + } + + if cluster_end - cluster_start >= 2 { + spans.push(( + marker_positions[cluster_start], + marker_positions[cluster_end - 1], + )); + } + + cluster_start = cluster_end; + } + + spans +} + +fn run_start_positions(absolute_columns: &[usize]) -> Vec { + let mut starts = Vec::new(); + if absolute_columns.is_empty() { + return starts; + } + + starts.push(0); + for (index, pair) in absolute_columns.windows(2).enumerate() { + if pair[1] != pair[0] + 1 { + starts.push(index + 1); + } + } + + starts +} + +fn build_ruler( + absolute_columns: &[usize], + filtered_leading: bool, + filtered_trailing: bool, + theme: &ThemeState, +) -> (Line<'static>, Line<'static>) { + let width = absolute_columns.len(); + if width == 0 { + return (Line::from(""), Line::from("")); + } + + let mut number_line = vec![Span::raw(" "); width]; + let mut marker_line = vec![Span::raw(" "); width]; + let breaks = break_positions(absolute_columns, filtered_leading, filtered_trailing); + let fragmented_view = !breaks.is_empty(); + let mut run_starts = + fragmented_view.then(|| run_start_positions(absolute_columns).into_iter().peekable()); + + for (index, marker_span) in marker_line.iter_mut().enumerate() { + let is_run_start = run_starts.as_mut().is_some_and(|starts| { + while starts.peek().is_some_and(|&start| start < index) { + let _ = starts.next(); + } + matches!(starts.peek(), Some(&start) if start == index) + }); + let display_pos = absolute_columns[index] + 1; + if display_pos == 1 || display_pos.is_multiple_of(5) { + let is_major_tick = display_pos.is_multiple_of(10); + *marker_span = if is_major_tick { + "|".set_style(theme.styles.accent) + } else { + ".".set_style(theme.styles.text_dim) + }; + + if is_run_start { + let _ = run_starts.as_mut().and_then(Iterator::next); + } + if is_major_tick || display_pos == 1 || is_run_start { + let _ = add_number_to_ruler(&mut number_line, index, display_pos, theme); + } + } + } + + let dense_spans = dense_break_spans(&breaks, width); + + for (position, marker) in breaks { + let marker_position = dense_break_marker_position(position, marker, width); + if dense_spans + .iter() + .any(|&(start, end)| start <= marker_position && marker_position <= end) + { + continue; + } + + let symbol = match marker { + BreakMarker::Leading => "‹", + BreakMarker::Trailing => "›", + }; + marker_line[position] = symbol.set_style(theme.styles.warning); + } + + for (start, end) in dense_spans { + for marker in marker_line.iter_mut().take(end + 1).skip(start) { + *marker = "~".set_style(theme.styles.warning); + } + } + + (Line::from(number_line), Line::from(marker_line)) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn line_text(line: &Line<'_>) -> String { + line.spans + .iter() + .map(|span| span.content.as_ref()) + .collect() + } + + #[test] + fn basic_ruler_marks_positions() { + let theme = ThemeState::default(); + let absolute_columns: Vec = (0..18).collect(); + + let (number_line, marker_line) = build_ruler(&absolute_columns, false, false, &theme); + + assert_eq!(line_text(&number_line), "1 10 "); + assert_eq!(line_text(&marker_line), ". . | . "); + } + + #[test] + fn fragmented_ruler_marks_break() { + let theme = ThemeState::default(); + let absolute_columns = [0, 1, 2, 6, 7]; + + let (number_line, marker_line) = build_ruler(&absolute_columns, false, false, &theme); + + assert_eq!(line_text(&number_line), "1 "); + assert_eq!(line_text(&marker_line), ". › "); + } + + #[test] + fn dense_fragmented_ruler_uses_span() { + let theme = ThemeState::default(); + let absolute_columns = [0, 2, 4, 6, 8, 10]; + + let (number_line, marker_line) = build_ruler(&absolute_columns, false, false, &theme); + + assert_eq!(line_text(&number_line), "1 5 "); + assert_eq!(line_text(&marker_line), ".~~~~~"); + } + + #[test] + fn filtered_ruler_marks_edges() { + let theme = ThemeState::default(); + let absolute_columns = [2, 3, 4, 5, 6]; + + let (number_line, marker_line) = build_ruler(&absolute_columns, true, true, &theme); + + assert_eq!(line_text(&number_line), " "); + assert_eq!(line_text(&marker_line), "‹ . ›"); + } +} diff --git a/salti/src/ui/panes/sequence_id.rs b/salti/src/ui/panes/sequence_id.rs index 295dacb..259b898 100644 --- a/salti/src/ui/panes/sequence_id.rs +++ b/salti/src/ui/panes/sequence_id.rs @@ -10,7 +10,7 @@ use ratatui::{ use crate::{ core::{model::AlignmentModel, viewport::ViewportWindow}, ui::{ - layout::{RULER_HEIGHT_ROWS, pinned_section_layout}, + layout::{AlignmentHeaderLayout, pinned_section_layout}, ui_state::ThemeState, }, }; @@ -18,6 +18,7 @@ use crate::{ pub(crate) struct SequenceIdPane<'a> { pub(crate) alignment: &'a AlignmentModel, pub(crate) window: &'a ViewportWindow, + pub(crate) header: AlignmentHeaderLayout, pub(crate) theme: &'a ThemeState, } @@ -30,7 +31,14 @@ impl Widget for SequenceIdPane<'_> { let inner_area = block.inner(area); block.render(area, buf); - render_sequence_id_rows(self.alignment, self.window, self.theme, inner_area, buf); + render_sequence_id_rows( + self.alignment, + self.window, + self.header, + self.theme, + inner_area, + buf, + ); } } @@ -60,17 +68,23 @@ fn build_pinned_divider_line(width: usize, style: Style) -> Line<'static> { fn render_sequence_id_rows( alignment: &AlignmentModel, window: &ViewportWindow, + header: AlignmentHeaderLayout, theme: &ThemeState, area: Rect, buf: &mut Buffer, ) { - let ruler_height = usize::from(RULER_HEIGHT_ROWS); - let available_content_height = area.height.saturating_sub(RULER_HEIGHT_ROWS) as usize; + let local_feature_height = usize::from(header.local_feature_rows); + let ruler_height = usize::from(header.ruler_rows); + let available_content_height = area.height.saturating_sub(header.height()) as usize; let band_layout = pinned_section_layout(alignment.rows().pinned().len(), available_content_height); let mut lines = Vec::with_capacity(ruler_height + area.height as usize); let has_pins = !alignment.rows().pinned().is_empty(); + for _ in 0..local_feature_height { + lines.push(Line::from(" ")); + } + for ruler_row in 0..ruler_height { if ruler_row == 1 && has_pins { lines.push(Line::from( diff --git a/salti/src/ui/panes/status_bars.rs b/salti/src/ui/panes/status_bars.rs index df899d7..1f0ab08 100644 --- a/salti/src/ui/panes/status_bars.rs +++ b/salti/src/ui/panes/status_bars.rs @@ -88,7 +88,32 @@ fn build_bottom_status_bar(alignment: Option<&AlignmentModel>, ui: &UiState) -> parts.push(Span::raw(" | ")); } - if selected_sequence_count == 1 && col_start == col_end { + if selected_sequence_count == 1 { + let position_label = alignment + .and_then(|alignment| alignment.translation_overlay()) + .and_then(|overlay| { + let start_col = selection.column.min(selection.end_column); + let end_col = selection.column.max(selection.end_column); + match (overlay.codon_span(start_col), overlay.codon_span(end_col)) { + (Some(start_span), Some(end_span)) => { + let start = (start_span.start - overlay.frame.offset()) / 3 + 1; + let end = (end_span.start - overlay.frame.offset()) / 3 + 1; + if start == end { + Some(start.to_string()) + } else { + Some(format!("{start}-{end}")) + } + } + _ => None, + } + }) + .unwrap_or_else(|| { + if col_start == col_end { + col_start.to_string() + } else { + format!("{col_start}-{col_end}") + } + }); let sequence_name = if let Some(alignment) = alignment { if let Some(sequence) = alignment.base().project_absolute_row(selection.sequence_id) { @@ -99,7 +124,9 @@ fn build_bottom_status_bar(alignment: Option<&AlignmentModel>, ui: &UiState) -> } else { "Unknown".to_string() }; - parts.push(format!("Selected: {sequence_name} @ {col_start}").set_style(theme.text)); + parts.push( + format!("Selected: {sequence_name} @ {position_label}").set_style(theme.text), + ); } else { parts.push( format!("{selected_sequence_count} sequence(s) selected @ {col_start}-{col_end}") @@ -126,13 +153,12 @@ fn build_top_status_bar(alignment: Option<&AlignmentModel>, ui: &UiState) -> Vec }) .unwrap_or("Unknown"); - let loading_text = ui.meta.loading_state.to_string(); - let loading_style = match &ui.meta.loading_state { - LoadingState::Idle | LoadingState::Loading => theme.text_dim, - LoadingState::Loaded => theme.success, - LoadingState::Failed(_) => theme.error, + let loading_status = match &ui.meta.loading_state { + LoadingState::Idle => Span::styled("Status: Idle", theme.text_dim), + LoadingState::Loading => Span::styled("Status: Loading", theme.text_dim), + LoadingState::Loaded => Span::styled("Status: Loaded", theme.success), + LoadingState::Failed(_) => Span::styled("Status: Failed", theme.error), }; - let loading_status = loading_text.set_style(loading_style); let alignment_count = alignment .map(|alignment| alignment.view().row_count()) @@ -291,6 +317,7 @@ mod tests { status_text(&build_bottom_status_bar(Some(&alignment), &ui_state())), "Filters: [constant: >= 100%] (3 rows) (0 cols)" ); + } #[test] fn bottom_status_single_selection() { diff --git a/salti/src/ui/render.rs b/salti/src/ui/render.rs index 50605da..50287a9 100644 --- a/salti/src/ui/render.rs +++ b/salti/src/ui/render.rs @@ -133,6 +133,7 @@ pub fn render( SequenceIdPane { alignment, window: &window, + header: layout.alignment_header, theme: &ui.theme, }, layout.sequence_id_pane, @@ -143,6 +144,8 @@ pub fn render( alignment, viewport: &ui.viewport, metrics: stats_cache, + gff, + header: layout.alignment_header, theme: &ui.theme, }, layout.alignment_pane, diff --git a/salti/src/ui/rows.rs b/salti/src/ui/rows.rs index 15a7aa9..b384535 100644 --- a/salti/src/ui/rows.rs +++ b/salti/src/ui/rows.rs @@ -48,57 +48,48 @@ fn span_for_sequence_byte( } #[inline] -fn format_visible_bytes( - bytes: &[u8], +fn format_byte_iter_spans( + bytes: impl Iterator, sequence_theme: &SequenceTheme, - alignment_type: libmsa::AlignmentType, + mode: RowRenderMode<'_>, ) -> Vec> { - bytes - .iter() - .map(|&byte| span_for_sequence_byte(byte, sequence_theme, alignment_type)) - .collect() + match mode.diff_against { + Some(diff_against) => bytes + .zip(diff_against.iter().copied()) + .map(|(byte, diff_byte)| { + if byte == diff_byte { + ".".fg(sequence_theme.diff_match) + } else { + span_for_sequence_byte(byte, sequence_theme, mode.alignment_type) + } + }) + .collect(), + None => bytes + .map(|byte| span_for_sequence_byte(byte, sequence_theme, mode.alignment_type)) + .collect(), + } } -#[inline] -fn format_visible_bytes_with_diff( - bytes: &[u8], - diff_against: &[u8], +pub fn format_row_spans( + visible_bytes: &[u8], sequence_theme: &SequenceTheme, - alignment_type: libmsa::AlignmentType, + mode: RowRenderMode<'_>, ) -> Vec> { - assert_eq!( - bytes.len(), - diff_against.len(), - "diff bytes must match the visible width" - ); - - bytes - .iter() - .zip(diff_against.iter()) - .map(|(&byte, &diff_byte)| { - if byte == diff_byte { - ".".fg(sequence_theme.diff_match) - } else { - span_for_sequence_byte(byte, sequence_theme, alignment_type) - } - }) - .collect() + format_byte_iter_spans(visible_bytes.iter().copied(), sequence_theme, mode) } -pub fn format_row_spans( - visible_bytes: &[u8], +pub fn format_row_view_spans( + sequence: libmsa::RowView<'_>, + col_range: &Range, sequence_theme: &SequenceTheme, mode: RowRenderMode<'_>, ) -> Vec> { - match mode.diff_against { - Some(diff_against) => format_visible_bytes_with_diff( - visible_bytes, - diff_against, - sequence_theme, - mode.alignment_type, - ), - None => format_visible_bytes(visible_bytes, sequence_theme, mode.alignment_type), - } + let bytes = sequence + .indexed_bytes_range(col_range.clone()) + .expect("viewport range must be within the current view") + .map(|(_, byte)| byte); + + format_byte_iter_spans(bytes, sequence_theme, mode) } pub fn format_translated_row_spans( diff --git a/salti/src/ui/selection.rs b/salti/src/ui/selection.rs index 9b7c914..0f9cd9f 100644 --- a/salti/src/ui/selection.rs +++ b/salti/src/ui/selection.rs @@ -5,7 +5,7 @@ use ratatui::{Frame, layout::Rect, style::Color::Rgb, widgets::Block}; use crate::{ core::{Viewport, codon::TranslationOverlay, model::AlignmentModel}, ui::{ - layout::{AppLayout, RULER_HEIGHT_ROWS, pinned_section_layout}, + layout::{AppLayout, pinned_section_layout}, ui_state::{MouseSelection, UiState}, }, }; @@ -74,7 +74,7 @@ pub fn render_mouse_selection( let window = viewport.window(); let id_inner_area = Block::bordered().inner(layout.sequence_id_pane); let sequence_rows_area = layout.alignment_pane_sequence_rows; - let id_content_y = id_inner_area.y + RULER_HEIGHT_ROWS; + let id_content_y = id_inner_area.y + layout.alignment_header.height(); let id_end_x = id_inner_area.x.saturating_add(id_inner_area.width); let sequence_end_x = sequence_rows_area .x diff --git a/salti/src/ui/ui_state.rs b/salti/src/ui/ui_state.rs index bbf976b..b9d4acb 100644 --- a/salti/src/ui/ui_state.rs +++ b/salti/src/ui/ui_state.rs @@ -109,5 +109,6 @@ impl UiState { self.selection = None; self.layers.close_active(); self.notification = None; + self.gff_tooltip = None; } } From 986cb593e4b629278a0ac888cd74c5c6f0d0342e Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 18:20:00 +0100 Subject: [PATCH 41/48] docs(readme): update readme w/ 0.9.0 changes --- README.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 29c3b5c..5c40c97 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,18 @@ [![test](https://github.com/Sam-Sims/salti/actions/workflows/test.yaml/badge.svg)](https://github.com/Sam-Sims/salti/actions/workflows/test.yaml) [![check](https://github.com/Sam-Sims/salti/actions/workflows/check.yaml/badge.svg)](https://github.com/Sam-Sims/salti/actions/workflows/check.yaml) -# salti +

Salti

+ +

+ +

`salti` is a terminal based multiple sequence alignment (MSA) viewer for FASTA files. It is designed for fast interactive browsing primarily on remote servers, and HPC environments, or anytime you dont want to leave the terminal. ## Quick start + If using linux/macOS ```bash @@ -31,7 +36,7 @@ conda install -c bioconda salti - [Usage](#usage) - [Some notes on features](#some-notes-on-features) -## Features +## Feature showcase ### Fast @@ -67,13 +72,6 @@ Press `m` to open the minimap and drag to quickly pan around. ![minimap](assets/minimap.gif) -### Nucleotide and Amino acid support - -`salti` automatically detects whether your alignment is nucleotide (NT) or amino acid (AA), then applies the correct -rendering mode. - -![nt/aa](assets/aant.png) - ### Translation Can translate NT codons to AA on the fly, with support for all 3 frames, although designed for browsing, rather than a @@ -195,6 +193,9 @@ I plan to add a help screen in the future for reference in app, but for now here - `Ctrl + Left click` - Select a range of sequences or positions - `Middle click + drag` - Pan. - `m` - Open the minimap +- `t` - Quick translate the current view. +- `Shift+t` - Full translate the current view. +- `Alt+1|2|3` - Change reading frame for translation. ### Command palette @@ -211,15 +212,19 @@ Commands: - `jump-position` - Jump to a 1-based alignment position. - `jump-sequence` - Jump to a sequence by name +- `jump-feature` - Jump to a feature if a GFF file has been loaded. - `pin-sequence` - Pin a visible sequence to the top of the alignment view. - `unpin-sequence` - Remove a sequence from the pinned group. - `filter-rows` - Filter rows by their IDs (fasta headers) via regex. - `filter-gaps` - Filter columns by their gap percentage. +- `filter-constant` - Filter columns by their similarity. - `clear-filter` - Clear the active filter. - `set-reference` - Set a reference sequence . - `toggle-translate` - Toggle AA translation. +- `reload-as-protein` - Reloads the entire alignment as a protien alignment. - `set-diff-mode` - Set diff rendering mode (`off`, `reference`, or `consensus`). - `load-alignment` (alias: `load`) - Load an alignment file. +- `load-gff` - Load an GFF3 annotation file. - `set-consensus-method` - Choose `majority` or `majority-non-gap`. - `set-translation-frame` - Set translation frame (`1`, `2`, or `3`). - `set-theme` - Set active theme (`everforest-dark`, `solarized-light`, `tokyo-night`, or `terminal-default`). @@ -248,6 +253,27 @@ If there is a tie for most common character, one is chosen at random. Consensus is calculated in the background +### Quick translate vs full translate + +`salti` offers two methods of translating. The first is "quick translate" toggled by pressing `t` or the `toggle-translate` command, named as such because +it only translates the visible view and so is technically faster than the full translate + +Quick translate maps the currently visible nucleotides into their respetive codons according to the current frame and then renders them +as an amino acid overlay. This does not change the coordinate space - and the ruler will stay in nucleotides. Clicking on an amino acid however +will display the coordinate in protein space in the bottom status bar. + +Importantly quick translate can not be used if any of the columns have been filtered - as this would cause frameshifts and would not make sense to +represent. + +In contrast full translate (`Shift+T` or the `reload-as-protein` command) takes the full alignment and reloads it into a protein alignment, as if you +had loaded a fasta with the translated amino acids instead of nucleotides. This means the coordinate space becomes amino acids - and each amino acid +is represented by one column. This means full translate is compatible with column filtering, unlike quick translate. + +In practice this is still very fast (~3000 mpox virus sequences which are about 200kb big can be translated in under 0.1 seconds on my PC) and so it is useful +to switch between different translation modes depending on what is useful. + +Reading frame can be changed at any time using `Alt+1`, `Alt+2`, `Alt+3`, or the `set-translation-frame` command. + ### Gap filtering `filter-gaps` hides columns whose gap fraction is above the threshold you give it. The threshold is a percentage, so @@ -260,6 +286,29 @@ Dense regions of skipped columns are shown as a run of `~` characters rather tha Gap filtering and translation cannot be used at the same time. If translation is active, `filter-gaps` will be rejected. Likewise if a gap filter is active, translation cannot be enabled until the filter is cleared. +### Constant filtering + +`filter-constant` hides columns where any given value in the column meets the threshold you give it. Like gap filtering, the +threshold is also a percentage so `filter-constant 100` hides columns where 100% of the positions are the same (i.e removes constant sites). + +Like gap filtering - removing columns can change the visible coordinate space - see gap filtering for a more detailed breakdown of what that means. + +`filter-constant 99` hides columns where 99% of the positions are the same and so on. `filter-constant 0` clears the filter. + +NOTE: +Gaps and Unknown symbols (`N`/`X`) are not counted when calculating constants + +### GFF support + +`salti` can load and display GFF3 annotations from a file with the `load-gff` command. This is currently experimental. + +Currently annotations are treated as "global" - and per sequence annotations are not supported. This also means there is no fancy business that +tries to match GFF coordinates to gaps etc. This is mainly useful in specific use cases e.g: + +When you have multiple alignments to a reference sequence where that reference does not have gaps inserted (i.e insertions are ignored). +For example running mafft something like `mafft --add --keeplength` or using alignments from [nextclade](https://github.com/nextstrain/nextclade) +or [fastalign](https://github.com/Sam-Sims/fastalign). + ### Pinned behaviour - Pinned sequences stay visible and remain at the top, even when they do not match the active filter. From dfaf42bb14fad673331b43fdcd6c3fdde57ba878 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 20:09:08 +0100 Subject: [PATCH 42/48] chore: salti screenshot --- assets/salti_ss.png | Bin 0 -> 307179 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/salti_ss.png diff --git a/assets/salti_ss.png b/assets/salti_ss.png new file mode 100644 index 0000000000000000000000000000000000000000..dc7cb454a30b54d288a5a030567ea073ef0ece33 GIT binary patch literal 307179 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

~!B=UQi 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

fwPznEu;lP(Px}W!+ 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

)?>9^Msu-=NH6dc#tZGHPfsf= z(Ia30O?w1K^kD_NuB*?I#!B84wlQ~ff6kVX+ktz!RB3T-iuXg;{j-nL+H?4Dc$r^S zI5gph9e!DbS~?3i`P%XCbXenk!6X$og%t4k46kjNGHmPTIqgOy7Lc6wgH zvnxJ$RB86WpLCbBYOvF5@6%Y;on@N0x<(q9F~^8{(ksIc^q?p{f)2sdFwU2$|9v@RRWuq)5t#eh*U(@3 zYLb-HWYHEBLV61s|EwlaAgI%1OpGQU!s_t3{-}ebkSt-FehqbSifc{Y-hGF-nxz$y zBe{!eN=yO3fg z-Q>*ME+d<^goKM`V1q}9|F7GBu8#vXuADC>|Ls9Hnmhq+Qht3Dd( z47|+c{2lwDZu6wMcv{WE8##&`K^^36aslRB8#dU}Fc{e`JuuOu85A;#j-%dFUKWP! z{>6>H>CauZT%$4WFbNeo;piQlU%&jnTs(!|59fXs4bB>@*^b!c@=Ihpid#q{(?bK~ zlEL243t#T;q%rYVnPt;u(bAqGA`8tyk1t3rGzT3TZb_ z*?9rKTC|+(Fw+rz6So#U^@6GhOR>C)Y^KQPApiK#+mWc3rq5C3Kx+_#%4vTmyi=_< zqu51wfcQB61QxeEhhLx>%tK+d>d%qqh7WFuKF!LmC&Wh1)$5A5qPI-* z(MtcqxE0d{-qFFDdW{-8a>Ey)`4WMQh-RsAh>TF>UgSU#8!qm@cP?+^+!$hl;3;&w zE|jVkxm{b+-9p4gt9b(Hr1!^UR#IPAo)H2eXM)>RMYMZjZx%$%A@9}eSVzX~A zpNaUpaIw|!AdJ)EvMzh|B{g$sQ&ULJ_2l(h5=F6VnhXw0o=44vI7EhOqABL=$zEjR zb491e$m~?zs$E-z!l7W!4ZjH##@$pdYB@p1!guW3qvKBYRb`BUTT(*tmBjUQtB6>k47_(@8P~@ z9~6fKs-N6lOs*~Zb0@lXVaxwPz5fUx)GG<0UT+43dgGQlvEar_Q-WkT8}>sT=j+LN zL;l7u0tDKLvIxgNz>K2Wq$HZ3ee}wVXFB2hQ&aT(1gC7E4C>*9fo5{PPNEEOW8-i@LNM^b%e&(R zHNdFzuJ>vLp0DZN<`KcFDTQ)7hzy~7a2EP_$%r)JmhP9cL~hCj(BuuK>}saAx`8df zv}!}HVq>{Fq^ zfY^b{Mxh=1;dvfsD8>}YHQ9q$?BV?&N882^ebIm#cr)@%m$u2K(9RjwCc%>`hh^5l z)O@L^)Roh@HDZmb^=#FerqDu;)KHkyyiLGiGZJW_I3qTUsy`3Yy%+hHt)?ws4oa1g z0f}N?n9IS`LCI60W7X%cN1Va)cc4x8g9%TOo=DQ43oNmRV1vmk0M<^RqmHBf(7QV@ zgIH55o~z(&YZCQjRC;!NYsw;N5s|yAJ@f}?GEElW(9o|Jad`hsv!0RE=*lVOs#b;$ z$Ofr_9lRgw&mH}PI)t+?o=VoEH!Shnix%SeSLvWL=;Vm35}G!mTl8toeX^cT>Ov={ ztA+f0!4=`*_;bn|YDMd8Ezw>c_9PbBVFOV4icP?;Kx5Cp0ABRqOZR|x-xYb<4rt?z zr8scuY#4>5Z2Xsf^dZpBV)6=U>f0B1U8$dG3dQsY@Z1y>E{82eD2*Ajt~0*Vtba-l zc{5p3IGhhoq*2lFL{{Wz5?G-oMa} z=!O`>Kd4`58z-4syS;^*GU%=pq@!t<`E(JE_=Ad5^ytj9o$AxcZZvyZ>uv59FqusV z(lEioF?2!a+4QUG$9_#!52!?6cnm3av#}e)c4=RlpOdy|BzF9)GcOiQJr_{62|egaf?hyq^?=U6t3QvB-xBOt z4Wxbmc0YMk_>#p@$5B2E*e^-s>&dQY+oE}@EluU(_6CR7J5n%|REycjbow)b5EXlH^r5o`Gb#n&$;tz1@YgH~p-2Qwg5kSn>=?nLN zOu6T^cHg>S#Z732E_cio5!(}LS9!lj99xT+YHi3#l=8A>Puljo$g9pXWIDqC$v+VG z#j13P@y68`e)?~%-0oPjqfPhWD^?^gCrGwp$fG@{^^5Plp2G@fv%Sn$>7SmjKrv^b zcLN9TN0D5~W4Ez?Js0wg>-p3fwmnyQXXF-WvRTk&29}u-^7}c`$Kmd_5oV&i2vgRF zW6HqXSm-E*z^+*_|FmVx_Lx2Emwms_cBgm1EcecT3lODWIT*M8qI6HXR_LCBZI0D< zmiVKHnQNacZ8P=_5t)8-fnNbM}ToNDus;BBa{L! zy)6YFcfg)Zq%AaAI<9GC5^GUb4DF*VTrJSgN$~o48c*!^2o>2Gi8eQ-BATI!>2iDz zZ%K`>jzjo14C+^gT>o^SG?#&6csC8eVnVavjlkVSWjg4yo9xjT&6>Jo54-5FGxI@O z!U*gqPqBntAm73$`?8K$QM-}>Ka)NxXHdaX#?e(CiqtMf$ln>8q?UQk*(Fb!vW`pu zh6UW-4U;U9)j_Hs;CmXK=VJT@adXN0)P|*SU=U+dJrh-p=zzWx);amS#|G2k)x`+B zZ%5>rN%w7qLe$+=>_|5&_$=SG6P=jhHRe)(DTMxtDT|{I2;U}RyG{pqh30GLvPMrY zVbo_2JxXk>dBSDVtWPfig;0&z;3FgFMqlh_mapp7hiL)2Rmk@jR7acHrt+|;*Q})9 zesu{H>8O%y|f zOLV2{VhlxLf!q(IVk6z{?p+zp-<~7lRJBvEYc^<*`8$Ny2OTM64EczQeli`@*4S@Ne$4#&dx2TxztNf|6#AOGaBP|MJ%@ceT+E zLsOQgjly1aQ3yc0^Mt$|UCP zC-b)H5}y@wL`8mptq8q7A|s(6Q|k^BK(1wYvVC?ItCbVvM5t_NF_jGY^CTX<^5bf; z=t8dO*%=dUykXF8Pfi*LeM&?NZ9PGsTp{8tH#Dj1nA*;#kPsOXn!tP;U8PHF-R%5C z8;imXJGD|r-(x62POC=L;Ff4fpXNG$p#qw8Gpb)<57lc9p3X1_1Um+s4oEyL# z+;wfGKVT2}4Uyr`ndZp%^%U{xOYt-av*|ETCIX3I)4d2e@ZT?>Yys}}FS3&v*7ge! zB7_tA_mW`ZABOaIGmz7yLA~?ZBXj4CSCbM(da^d7oys_&uQ)`03^BNkXKb))N>hxm zo0tkd^+U00+@eb#ctZ69qrPAVtx>};_xBq_)*+7jv32S-!zcYdzd4Q%L`@EDYL>2M zf)K!DIp+IxoEd16g}CF++2C9(hO1YLj+Tp_wvt;`NIBwifCb7^4Q+N>m&g#A|4X-aWaog^Y^~S{UzMx5&0zTO@vAj+kocZi0|WN3BeOHymu4tH%DL` zTCFDixrCe30Q_gnxuiA%W&k;cEMm#<)!1c^9qE!0!YRI@4^oZdy z7Ik}5AZL$oSfUP}FD^{zFkAp_Pe3j2OkQ_6Z@TO?CMwe4o0@VakX(+C*C9b43i>>S zak9xnVM9%s=;q~o3}tFsv*(-f1k5|iMbD0W4U(qtpM01$XcoD}5__>4{$MjuC>A0# z1NmCevN_8>uIGCT+X&9Fe){|+1xJNMCNIT2SF0y199WFQbr00?U1NYk;7C8N37}k< zl~eGNI@Gym&&$940S33X5YkK=8b z{C*6+@!cmRoY^&PZooxepBt6AfzhqlDVCUdE@bf0n5AH+TS#J>5`K_7QrP+RaK(?j z;0>D$=I3U1|xcS*C25}n-=K567Cr}}d^ zp6LiO?iV4?nNWc;@+7zZf`65{y{B4huCYv;KaG=}*~mDBYRnP5hIR!pEM5`|qu4h&p@LNrrzSSRR z9$=5ZIJK*RQH29{A80VRG_wL9itFFVgNj~983mZeT_7jQJx*=+f6wA`NrOi;<;6+> zaD^apeL&G?lebTNT{B&pMPj1AWpP^~H7^PitND|R&4exj)CX*;K#-vdMkn6LabPuq zsj2xo;gojb({%S#N%Oin0tis##uIoM757g#0e;w3%kkTx+st+?eHhPPZ7Jeka9#U4 z?M87`TW(!8R@6g1DDZYbjDLIvZO;G|P{T00iy%xey|A5ckg~B1btNBOqMyT`Seai@ zo-`2|DFY@_h_mF@lK?(04%gub<>4bzTZtXrij_Oy{HYlXJ@aJ-4%hloDJc$nfxPjHLK{#RgWjz2-QnOfhY0Z_Cm@{f%|&~)ZnK;uDBl^i!v8nzuHQmAns0Ija%%{MZ~tjPJxRCf+%5j93rSi zU_r0|q}CHW9EEN@nrMr}yqG?%wr1}`i0%Us{Q?ejBM*=dG)}01E-Ides{X#Oh6`L{4$lidk%|%b&Hd!PfH}B)l77^thqH< zWx>>mU^E$i$2GF4JUl*u4zGrrJen~?!pi%gNB7JE^eKf(7{NZ^Chc28L=Qk=3zXvh&f{ECR&_qq}E>23o!`IrCpfSyKzFQSfy9ofLz2yGOmy%$fYDY(5>!zi} zYUL4l(We_wPGcZnx*qM8L%7LzuZLUmU8?|dGy#FgDwgz1*FgT{XTScyHuMwavfZ5y zL+5;k3wG(_9z}opbsEQxU)Ij-Ekp?fh=?a<-ab~u3FkW^~AS1qbH77fA+AvOM zJpA)8D)_LfNOEtRAcG&?leVolC|0hVcq*51sd=Yk;-(W=;ddDoSI z&n^DDr(1^-?jviH|Lb#G<_gob`-v$G#NeCu<&gE_0?qmb1gR;NM8crZT|?8%6K`gL9v^v6)Dow5rn*5gAGIj984S zncPJXJrg9toT@ZOAVALlv?z#yk68oFTHzvxlkQ(smR3F`si4uvM+obM9j`>!_<|Hs z%>crNS2MrIn8B;<^7soq?}vm27vCPL=p_Uj@V!5fUI<4JkZ)NQxRH66AuceXe4 znWhej&vbG+qY#NKU@|dO%Mdga zn8I_>=w_nud#KQ1d?8GCPe0=6Yi5Jr0Dt1&xn5F;EFx&7tUTM3PA9fTkKW*|nk8LJkizyZ{zzJJ$L!Dx(vntW|%$RCh1qz9bbFqXX_> zpLh7$7!*%lZmY`#m=c2o^+5vG7TjL)pA|Ux=Tr@;E%ITwLGgZLD$)rseZvbs5>lG$G|!7c!gg;)7og$sU&!oyD5^~$WwB;H z8D5$|-&QSh82o0~2H0TJMdlCDO`@wZm#vtHtBa;th#o;SE8h!SiH>SbC0Z{?UJHxN z+_4`?Mn(Z9cxR3xXFrMUmjk5lU5xn)WPw-Skv9#JB?^#<2$)Rsbk6d?#S59Lq9X?w zDZJgUfGuGWo3g;f(<~!`+c~C zaBCuj^xBnA;-up|B?9nqSLAZvO6b!Cjn`~3H0b_<6}o2_^wf|oZ528{ZACmRinE+2 zH-ZmdG5Ifs$Z2#v*)2MGWk@d6?e?C*}Bt#CP|4DrixP_ow-9ASKU5IhNla4)(bKY&cN zlIw*y$m|yU*3d-`Xm!cF4{2uXR2O?9J4Pc+gl{dd(QOoXxrv>SIb2B)mtzKUlV;4& z_aW^1wyky_=XoZ?ex;!f!#bz?7Th)OkCa8z8kD8I@pWWkw*_$Vlqe7;OE{>YX;tOd z@OibP%%8{dqwTzgEV|Fvmm_o)4M27(EUJuyk8V#8IzT;q3ysWu{hCOJ(>*`Spt$mk z4b&_63&Fs^Up37_nyGAd5BQHb;s-Q$*TB-FN^&+;==C96&Bm~WL0S>U*?WS0BSsyv z|B%8rH*GMMBrFV*zn!YCp|l;25Hn z{l4;GG(W!KXWPiKL>+u%HHG0*v0Dk06IBkSrm_y)IDBmO`~;YFJ(#c14*&cq-J0*J zvl)HtPf^k9;uZ`-Y(~eLt0P=j5rpYn|9>bt_jsoMKaS^KNxCTIHX@fw>q2g`k=$uQ zl-nu_Npj1j*+`{`xeGCO$(Q9$*hub|xvx?t#;{zr8Qbjg^Lsqbf9H?SIiJTlpU3<5 zdOdlCeU|cc9xUVUDh%b@fb|5mF#hsAH=uL%&DAe%ZNUsjjV82))m4qJ7RTHY5{>zy z;#XVMZ*pO##KW1@$m+sH^u*M4ah1}`_6Tr>(}4j zx*q-NgUB(H3EQhXc1@q3Pc;!d8m6ls%N(Jtl>*qGAFpXkz96i#S0|o`$v>>~;Jh7%s+K`dtsfFRE>sQ)HW(3WxnJ{UM?N9&b~gf}k?e z6YLLl9b;ZmWI54uRSbkGo;JY8R$X$$>On%Zz~p5C!$y}i3$Dz!8m~B~7cL<9-jEJE zvNYWlt1lr8DlhjeTvkqu={O#Lb3C;F;BJi@URqea>$w5-*dl7$ zR>4BUuT&o)6vAG96D-brp;AufX75HPr9_rbF4X@bEa~mv%E8Lui|z>30uxA7eNh^M z+MTB0N6xW5w#VlkeIVJlJ@G^2o37CY@}myF7vqNzA-Tj{Qne#>C_Auwec`o2rqca! z$2NaWF$;`tMz;m5=&}!7Gpm$ciTu>JM5wJvm53q#?gcz?gGQ<@9zO`TGg9kztW-m| zuZm%RA55=_=|EH7y}WG7_KmcpinV6C6KK;}Y4+<@T=PK_jg5i6l%QMmT&*(o!`X7` z`mZ_WXPWC8%xW-qm2$UY6#+I}5q$!J`dh1Rd; zD~)1;@&)9AN5HJ(=dNfWjhaUy?B(lOwsj5z*=N+(MR*@y6`?UO!EP`Kel~g4B_ZI} zQ@W>BZ|GD|G=1`c>LRe|*5K}$QPQnHOmDlFSx&ofklk(ZeU9w=eW=PISOUH^3)lk&^W{|)k4F>j~RA12kqanp8 z%m40D8C$eRLO#1_8DLavS*v{`VsyT%_v5>D`)Z%|n*(Z9v%2}c$>2`wwTU3;*RsV! z027SKSdBWg`7kyTNITHWS~>{JD>AxPKyZStTF{jUrw>AGf#@ey`FfIoM5x-kGM}55 zIO%H3%zOQRUF@wA9sQ0O9hCNTP6YmsU(%V2Ai6;x)Cq;+ysHtl=DU?KX*NJNs)^Jm#ENv}5vvUmw} zz*z+lwB^FED9j}7@$LEJCpT$Rwa-WBw+D}^)8JgiO}CxJ=o^(Rv-k!eUa9YOko&+@ z1$t5b-R}S!h^Be-6BnTU;p=k~X$Yk$i+wl@tHn_bjFVzm!17)x$d`OI@4V9i6T)&P zo@9j(!gpzz17kk*)Q1cE?te4`4xh+@R|SY11iu1{(cqhjf3L7U6h%fGsWC*sZ(fp| zeUtVZa?Wz$H5(O%U|Ao$hL8(?jympTrF~@Uhjn2a`}~ z>{4h}t>Nn#XGgsKQ=@_ul3fHA0c4p{U=Qg@1EY^!=zgb>(o{l^HC-5OPyrN-IXU{G zauQIIe>WZZFskFBAE6~*s+{q_zfHv?x4eW`PEDiP(yz(`84Dd<#})GJ!uQspi=UXy z$;0wQ?%RACs2t1q`#mP^sJv_03iTV6y0!A1x}|%e!#C3S^l>RS0?E%)X;~wRy<95z z_vHs^W?&$NkB{fDfUC1cPf(g&Hw z1@!KVcHwN!!I-SFw2<}6s}+qUryfV1`dw%JSHM?r*%A>9wns2kW%ZpBP%0=7dbeiU z;G%{8Gx@U~zaRM?>h|S+86ti78^5%Ff18#8OP3hx(!04izFhisI!WN?&8qD=J+ZBP zO2XaK`E8;r+C~_^5$C$wgO(it=m72s*C$Y2pIp0KKAl$oF_m4f>OhgivMk4MeGb+1 z5ZD4ualX;3)by4nEGy+TvsAE3TP-$hQmvMZtpch6vy=Jmc)^T%Ke<+mFJd^?%i0%N zWkoy76_T7SuXGA93RL(2-A!s?=4=nW#6V(JR_G4<+jW?v#|sU*ehab3*qd@1X1Tl2m4T`L+@CAnH2 z;>jmfDo!)Q-{e!k$dfB#_?F32^}6gF_vOF+5e|_OXexD434gXqz%I8we6wc!^1-c% zB&E&d$30^AEfI3~V7<*{0X)O*ugG70MY2fxWvpB3mS~!6`lRWqp^L&e)K(JqThJI^ z5Lq0Wn9ZunQ?B zL`8Imih0R4w;yxA({a@<+zK%kDKLjVuQaEnXFqG449ILYThWE7gQDTMeO-P>BCF}h zV~3x;$OATAC+$8s%7ottrN&I_lz@#e!KXny5Z*V@Cqi=(_1!#Ge3>gNLMZ(uvK20T zwwg6xG-kQSQI&=r79F_r4!H9glN43JIA^J5G;K0&T?bvjuL$7QO`m7T6C6$(OO6a~ z3%~P-54c4v=yi#*2q}y+t5x%=50S%%?QvlBpUJX9FG5!d`ws3x_Jtl^^pmiBeiu!{ zuF`AD%1I7Jn9Cz#A|dtxK!+xyK;lAk0qNAbK{aNQtfJuN^og@jz>?`B3*j!ZUZEBh z7eR^y+n>LZnMQkRlER-Fc_zt#{XuYTJ5^Kz?>ZwRXjVEnXD40K@cHhY+X%%1wG!aZ zmZSF$c6Al2tAC7hdYj{r;8R-ivLiwIiF)5*5J(-M$r3VEfNE(Nhuiy@0?tKR4m&)4 z>jFC4^6PT>Ya{Vx>O$govgA8SkmuRagHT%Fa!Qr{I_!pAaYLvqBO$-dId4`nWP`;k*U+(dk^Fmm*I%trT(h&8&0WF^^n7!Plsz;w$Y(1#edN+vx!ptSh{&L((xA9Sg%8 zyyfO7o0c*-*IdL~8NA$4C26Yz!5uUq#%+uI&Bayd1bc6Y!bQ4Eb%Nq+p1e*SY* zm5xAAqHoQ-VG89`k=t*jQLDBDj(A_hJ3($kPI?D{46iSYlWw|2b2!asJwBIKKDCcf zY4L^>*U^Rf1Y?HmuwD)RtvA8~q^U7tc>m1D*Brqu)%L?ww=AY$BuucF+&)COsw=U0 z;ta91{(~ilrEQBGCj8Qmp)62N{0!BQRLRxL^GX1&r{>wiro2Sr-xvMLnAc?4eRdrV zfP+vDZ{auN1U=@@QWvi)LDmzl?ZmID zfJKCBIP+cBW~{lBp8jnS0bcJ$)S=v_^=~^0E(bhL)s>?<0}%77@WqV{lieDJ6SAU{ zQ*#bY!0*2Y%M=d@{r7^AXu&5dN43gjXYzJ6+9!P!zsImqu&h0g)+j>wQR}bFk+TT6 zT-J$#<}u%4ZM*Qt!-`TqdhM8#9b01$gqZ$W9m7|%;~W<_cMMPvK{&S(YR)=6KZtCU zGQPKkT)QXE3uowC=tueUev_6_&X^OSZ>h&GNy+E^Y2HY&4W~Akj0L`JNsF7i+BAHl zs{q%{t|FsLESjWH&-`vZ|@RfrX%jDIWFAB+}rsT z@#B2!ek?BI?B8@3yw}9%oGPehK2q!`^})x-y)`w5Z-#ueq!FdCT>K% z3|jsBO`^fC(Vr(Cto|@=UdefM=)XPRT8e06l}jRb=DE`Q5PumRnTeAg?{W~@-?4D_ z9Oj$vSi+gzugbfsX4`*G{dD$T3#4VSv&cI3ZBl6OJ3L_<#6RMQ1+OF?naFSbfSBZK zmVn>x=?RY4a+)HZ{*ye_E}z9RuZEfgtfH1Mxv-~EAlub0TFsW&1lwPQ1?8G^{rqbf zp?1mWF*>`!5Wfca^B>QC@jR8Hx@An_$BOXeNB+er!$$D`A#AuUj04{w2^*0X+&_I} z*50TkuIg2Hfm?hT#TD5VT;dmgVP!3%7#M576;>IzwN+o4g-_Q9^=T&1g;uv@0suL ztr@x9JEv12!zXtCFavJxI@e7=+<8>av=kM6E1PJ;wP)FS@kTglFy{{(JSTV2T!#X@ z%M)JZtStp(rQxpeP408Qu_lJmgQ+#tQU)u=3Qp$|N1*F$GZ&oEUA}M$(t#iM zB zI7wG_=Yy4ppyOP~K5Bjr`Bd^wtGx5VVZ{U`;Hz&;&hYUQA$0Sy2h%4O0ztnV<8>x< zQG{viYk^psIzKtkzBKQo>wc8LPTjkxnd;nxY=_>3Tw;W73+*S$9W^tHJOqh^+tvyY z#-B@V;37p8A|82O4_nJ{D3+)`ey24e>@^__*>(sMFq69}d({6VVujwcU__~j|JaL0 zoW@uEvL7q2;;J++U|cWBCnhqORG@RLnDT7fE;H_=dG1S8d9L3y6wTS(9R(q@uv8qt ztUm0+GN0;N-O~<I8Zh0hf8UC)ce*sRnwMz;p=o`@q%$ByB zHG@61)Hl*4Y?YXnCuXc35WG2V5^I-Y8al_e(___$?KBm`aI0P~^*5gzm?bHEbVL8v z5+=HZ-@dZ0=1R1w{-gIWh^7Z>H|8yUtGo?wd&nE5RsHzFxP;wGv9^=;cOvqC$TCMv zFn<$p*L3EI7R&%!ute0UF-aR1&;opx7iT~7o_D)~XMT=d{1TG$OWKUtxS#m;pXhes zVn7*t*oN`Ka0;&#o`633*Uy2gW6lhJ`PrUBm}BnF@%9*EN?m*L1f7`PhyFeJodYP_ z7E9p@eL16# zTnzIYysRZrDK<=){^acBtjrRM?bLDHJU_kGGu`wnkTAYf!UwuGh@&7)LSb$Jyn@;n z3x2xI3z{}Ccxb%_LDJQ^`X+Dq?MPyj^Lc9Gn)utOCbR7+vu(o@KbtPpZcN7`uJP{6 z@Xbc$2sDGiqiKMaGn+5_E^6iuhn>bb?64cF1@1w_l6l#JP2dvd zna(gX!XM7(P}=zoT=Y-$qPKW4o(8zU?{ecB*285BG52Xgs%QdGm2JJd1q2cnPk+I~nS^TgAc!Tjhg;_ZCi zz6ZG9$R~(ix~Fy}DtVH4XdZbLd8P)EiF@6zvz^QIX8*ac4a`D1!E#@*pgHJT=Bpy) z;l+8FDNQItu7=^d$Rz&QNhN@@kas$8WjA;Y$3cl0H}q2;Lz(G%hd0XJTYeUqm%;ma zj)`ncMn9W|#szKPuHg)Ff?tuyDOSkKbm=wpI>&Q5EE|!vpDRDWNvq;7bMU(qqjBWn z1a9wY@2*fDpp@Y^O)Oy-Gft>8xL%!XlU&^AyZl2Ltc;$lZOANAk>u?JXi8;A#7;tn zp}tXiru}HeH58otoie!1hx0Sm0pZAe8yXq|dHj(P=MH;)fnUcy*iIQVN#adC;az6@ z?ZIVk?fGwy?n-+SraaZ65`1`k7~7aK zKMwtP(RP>m0|j&5>ZgE$2f{DBKnQvK zVLuPzk%B4DOgZ0Y7W`6QMuz-6_d9}8v|RSgGgVQ?!$49J%zN=gEYSH4`?w(2&^UY6b^JMu9C44mNK5 zlJ-Bfet%1#?508-pScqBWR|zL?ho2j^Zov|A6HK(SXY0L8^fhN(GB{^7PV1-zjnZa zbCqwM>jbyS4vzA4CY};E)G~#aNL#I;Ri$A5^s6Y(SK$R-vtO0X__Z&4k!zHR-*x7BwobV^$z>chBL1?UJbc0YIl8YN9Zs*fX|eMXA= zemTuEikCbv+i`y8*BNfl5$;7>#?>t|{wc^6y(YFRpqV3?dO*PjcZq>ii=0%;ebWL3 zxx!EVof((V_v9xpfX}LF} zpqy9E$XMLzO9zi^oID0e-m8${N#2Yw-%{`u`3q4NZ0S3Qsc)n#3akmydLXKg4cLG_ zui+;6=Xl9R$eaCZwuW-&Y zkgbh%oCrR73k1Fk_ZFv_oaO!GNPXeKCLzn5dk-d7{*$cbWwRi5OFPDM6fB3GRE@gc z%}Zv)$&|r5wqymuqS6nL0Rd;$jO`@-FWo z>xGdUq;;Fl7U@KJ@_aSEptf;&CE)A!L`CM^65bjo6%QqH`Y37B(lD4#8K?3b*Xb+d z3$=jT64Pz&f~@aohm6ewYB>_wd?s6Ys2jfqsYb4`ue+dQM)5bvVNLw6ELbkPxN{6b zL@slV9pq$%Z!Pf1yh4h(E^lZj48gbHniKG?8H~7gF+4eIH`*j0c@08HX5_VD8|knm zfPd6fA5G^5Z}zL&&g!ud1%jQ}(g9YFFhBj8EGd_ZMg(Zi&PEAd^_GmiaP@og{ZJ+e zi4`or`FxIwero2dHg`_qHZPj3{}JSiyAnww`5yXj16Fva=DF;8bA-~#k-U!}L09>+ zi{g~$j+@9Zd{@T8>gRn4)n5-mB1n3@OW}0Qr7^^ou!je3Pg%|yAO(`144DUf6%=#% z^#wj9`%Fj*DbjSXiO2zmJbyk<CK8I#xUlMj&V;rOJT#hVNo!bU`N z13!y%cL`3_?@!-Ca~2l1;QO{b?uYzhE&X-m`*bZQW?Jyy9nPx>xbqm$tvrs|yUM-= z481i@LYzdeK-5{@Jhm+Ml zfTG?b$yLwaD?n8ADM^tL24yhOQMW5hAHf9P)$lA;S(2PmZhmPoDOR6Ly<(~GJ`g=1G+&I`!{zHmlX!_G`>d>Mt=jSc@ocjH&H zG3a+Ch%1K7nyE21gaWNc#wl>0@W<#02Vm90Pmqdz)Caon8}7z?HbII-Cb+V96#E zWGvQD^tyN7(LGrNTte8cpW+rWA9KL^IiXtSl-u78}pEzTWPdJ^h86( z@0~x)O@^4f>~&YlS4IYm_>;GnWegkK3kpX{22rHbAXCo>&JumGTIN=qI!+x0n1#Jy zLAN$qk`8{ln!7_ja9FJs+egO8K@9lWtPDIVmbQ9syM@(DFjr)tt6-|BJQV>LMtBGe z#)&@R6>?jLKA!p}-OAx$7E!|3-Mx{(H@t-jzpxl#QyCh0lW_ea8qRM3(YdX9Sx8k}&MOAM9d@mP@}fUr8nOq0=E$j2 zpd+$EN~5E=B9P&mt&ELhX6w-BNtb_0Py1JHe%c!awr^3bF9JJdHIc~;0hR4kyg)bM#z!xN?&wpJ7sQ~V9%g;(| zXZJoYVatN44zSinfYSDw;=WVf7&XYL9e+uRL_4M|(HZ~ok9&lhQ zmZDR~H*B7a{38V467<-0+&Cmz@XTW>GW7X{sgIZq@4dDRa1d67xH9_&RYAPK_ebP# z0#49orv6m%|HGEB|7eh$EmoB+R<5#+tfHo+3w9wBxWuuzkr$3zpv`U(^(=#NP8WUm zZ2@``R?CT_=i54;+z^=rgU#*u055L9yEAAuYRB9K?ShD}L*^sMgNautxko0^EJmkxGC3^E z8H@|lr2v}vL7?QOycyqTk-RfgFc+9W&{NSNvAc+B=!)NqW<>F7GVl*M8AIfwOV;ko2`WTDjB~CP^@xVoBdVXPQB z3-e(zr*>ubV-3~3$C;fe2)Z&iCmSKq>CFyveiFKI*-zN_M$1Z za!v(Qd;hD;F7AC1$8ZkS=N@av%8C`$_}Ya$ncY*Eny2}R!qD#%F)g)2upT6(I=eaa zuWm?OOc6R@milwQ5B3tZ>I`+5)Ls%ix%(@wv9Z?}o;;NZC?Ymz5Uv+^GkplRPZLu4JaZ0T%2oo-bNKKI!e;ZBh@ z{*3!gbaVHCT!ts?9WF@lJM>KMZ&u>!2t%|kj?%N@X6ObYcl+sjF>V1#s1W|B>hkB9 zNhm!$j61wG7aVjHvb$2v7d^lgQ^>amTLvGNhkC*$fy_4LDE5+}{!Ll&YmM&_&)f1K zvOn0Cl;Dedf0pP!ULp~4yN0JSJcexN!!K}^FG}CK(=36Q~IfKy#gSD z23nBEhnLqrDb@Zo)NrWAEOG(gnL?xPF)Y$8~@2b}beqNiafBo%TPt9^i{{ zOF>eolq`)eHT_Ib{|S4@9iKAywYv(`TS18@=KV?6S8#7n>J6O^A>ph}pkq5Bd5+2Cn!e!&eIsJU z2A0jKf4<}Ham0?Y_Dvozb2$~A$XF~}Jc~RuXOe=;lK3}+OXKQEE6-_W@u=jm%kq#Q#ek%xMy5MO`$2ZZ@McVD z&Z54b;pt?`iTEf}!{peWt17IFDcC+&NIf{2UEcZk;j&m7M~lD3DcfKzFg&?ll&o<; zh{xoUWj|%Mi_@MaUS6A!pZGdbJq1up=CqsrYDgQVl^zxWZ zGDEX}&yL|00N(B@EBPp)5mCe$Zie$ooRa)wCA^h;6a)Ren0E2N>s)^7MSBHHdaO8$ zkvJJ#ucztwFDo)DeIsT-$Kc`sG8@`Qlhot?Vt;t;{Od!?5-*ToFl6D6;B0y01O(A%9m3Q zg4#?_7c}48lpZ@u?c=EVfQr>kwZ(AO~-QDS; zlCp085nNthw|}DLndzn{^n&QyIsGS2j>l(M1G?KKLGQA3)~%`~edVP7c;#Cp#dfqU z%mMjx4kvP$zlxz%Ru7-6$)coDPd{_sc7Go;31o*zyUZje1p-;aC|EA&&kljlN%NVg zsykz_9aFf6u8KPv<#2G*#AO+Q`4Dg2KITV&?H zJR1Qzz@8VU%)1|tV#s!FIwE?A?;(?sSLTVBGmrorC6~!PNPVGxg~RhVNXzJi z4H7$r)(kQ}7t6Me9Nq;FXSQ#sK#pA|FHsbGf4h&K+P&$#x!dF)_HU3JutW?IOnPvC z)AP8(NkHU0A#=Wy6sO1U*$`W?nbnAQgsk%qskk+<~^*#9BwI5yHg4-ic$oa(bQlT2bgqW2ivDQ33s>Q+PYuJkzX1c9iME|3OT z5N2WXhmCV3<0GR!EJ+SyXI4MvAy*@f|85czmyP_* zspXZ@J#9^^T_K7L&n3b05HH%sBc5@5*lzjX0NkyhPYmG{^e}YKLM0Dy_8Iv?3$C%2 z6>%sVy`#^%PtRiOj1ZyU)?oFx8Fm;w4HIy^lrOJJt7F}c4@h1Oi)X?p{AZl`d~d|y z&VCC2NmK^`dRj7Ub_i^XlrP_QodfgN4cHNyLhL zNMX>$!5X@!(bit&i!vCEVlE{Ps8XC#OkNf7M^$p1F%7qL4L0LuW1cG$p<>I!!9E$dSCvn-#rx{ zOx1om9yI#&zf!NPld8`i7xS9#fmHFQVk9cJ9}w4zm)~B?t#-L0 zB4Hw0P>qzhm=BV};I^N$rLw;hUJnPXcZMcBy1#>s9ecZv0J|!7-Z|iYq~BK08|Ll+ z!7WMy!5VT=mHhFAYWw>%-{?l$(No%kxtSxqz%0zoO|_f(J!n36NA5J5xv72Pm#3Qk z=D?CXbIZKCD-5yasOA2ud3U5VoL4Hb{O<~wO^Q2tZ~Oft4!s@M(WkmAey(*EEH{Qu zT5dAm+CVL5ot;Q5M3!FP5Ou1B(uyS|Uzf`|qalm^Idt>RQ${#}@vY1pO{vJl^0G8l zhlz|`y9rmiHhE>Cn|rv~wxSPq3|O*(@#2t=pAQiKSVtP%_1-zxA7K6 zdpGWf)5HJWX;3gRLs=or;0wp`_clM>|JHYjOu4hCI+E``8{AuT|4YQ<@F8a5kG8)? zpJAN(-!)Q@ONE!2!y4d@S7Wi8<2}njms@;P3wCorU?}^SW6D*pEz=)OzUM_H{IA>M z^q;`m1sEox=Od{g@x6}xjqNIH=6A@%(|=cS;UC)h-Q%ps_Xw@3FC;=LgqT`*0JxnR-gxS z#LBl4`$3Oagv_AaR%|N&4Y(51QNf3EEof0}=M?tHavhTj&Oj4ucbpg3h^{HX-P=MH zI&7MvBFmN%CQOAI)BqKE+8`R+n+vpI^>XhERif|5gZozgZI>HSkyk6ww@Uce-{LI< zh&F7xMLEPZs-)#=CGJ0d_qL(+KYCSgau3e^E&r<(@9PzMuPVY3F^%qEA8#OTOA~N~ zS8=EK-gM|2qRA3|RCzCd4?%pg=3f2yJ?v5%&LBhb3=)_NFgISezUZ}~R!hHn2bsa% z*v21OLG}y@%ABA7&Rddn2dpWvI_U}XrC)EXf1TyCerv=uA{w-&afvn%Ar@zl zZJoRn)|v|Y$;nzFCietLR{-@PG}diOKb$wZC4L}(1PCpsCj=-APRA*3X9w6c(}Vk# zHWa;ai@j_6wix0ckl}k6?vR+rv2K1p_vmv=1UPSyKKRUs9VGt*S;qC#E&dzW5ZOxG zJ<76&Q>3^hvqGvsFT&m)dhud=kw4jaOWqK39ET0OM*;fpacjqMG{X+VroBXx5wOcM z2;tx+^lg29~k2B*8Z*WDLafIrqGkq&&v-<{|w2z+Lk z596ARByAXO2_m>jew&MUg@Sz%tIFe=?5)xvz1vT4BIK!TqXI(5JN{wM& zIsTW5r0oS30vfY$0l9OY&)&2pJX7!RO*pz=-xqvfE=wGLYPO)B>H;1Q9#GrdBo%Zw z_!O4yBKfn|LPA6CPoCNhO}$ktJ1XygxK}qCIegny%kHBAud&o&RKeeizrdAEJ5Lyr ziFcKTzRaJ92EE&)+wj*d_)0hUoj3T3-QF-l0aLl-(;G+JL|Q3`XwEBX}3<6X|~CfCn@aJzd-R{>co}HwHIi))!x`5 zY#q-4{z?8mX;0ey4@1-L?!5&tfcLd|Uwj`qZ$}GtiZy=)If)xSB~E_dOHKO|KG*Mm zfJd{my>rR$iRmnJ@X`Dhb>Ro?pY;JuSzz(y#np&Daz;Ac*o$~OCCXfR7h(MGDwNm_ zZsbY6-7^ePPg^cRzL9d_SC~WmJiRurG+feLr-*__5SQ2( z@;Mo&ihBU~$u?TWiP{5VCpiDS7}hIY>EOYQAILwd{PSCGJgH{J%zjt23it%O8SEj1 zk(5P#hE(yDzO-bZUY|$L5Oc;IklRx6OXA6#A{HG{1j`!5eZ7k;X3hAl0kRj#HT8(E z%Dg@H&YV6?_H{GgR+am13Htwpeu91QZd7L#&}aqy=K_KazvTZnqXc5HZ9I4M68|w< zXURtwLLr*p;RxCT?D@X7yL_){ew;JMZ#68)1%fH#0X(viHpn*nJ?JT}(t%sc$#Lul zs!;O=R$X)W`u!Z;$*YhS?Nkgf6TPnz>4dZ7d0290GFFl89k7Bhrb$QKb$;QVd>1y& z$9U1ZZoCxRYEWWiHBOgP$_WQYA+88pMi6dBg?2a*Df#q;Y?ClXuN$ zd2O2OoK6-!{{lgeae!aXfxUL;+rDvyjI-l0kWa|YCCD#GoB^9mCY<4Sv^=G6+)70f zjMt%X?)3;Vf%X)MXG?Dol?DN`kcJnh9|ICmvdR>I3|iymNHj9(aL@vs`|c0qeL8!$ zWD>dP)lBJqdJJGC_0(u37m&|0Ly|R;zT!Ept`d8!Uw((V&m`?h3tEfs|CKJ2k<&L05H*pXz> z{DvB%7P--7xTl`f;@6P%1=kzS+cIQ77LoneZ=Buml|M#w!;H#e6S9i;m9*ijg?g*U zPCj31ys-#3XPo5_lb7jmxVyf`_$H_2N@sD2H`MK7Q4 z#e7h+M@z7kT;-CF`1-w0Wg0b7ogR@SMF`2HSHV7-;&~nA^HsDg|*M%0W8Mxr5 z0cL`TCrmna5~QVpJ9tU_MG-hSY!@A%aQKC8^(VwIb?etuU+koV7v#huW*FKJz01!e zJNO-w9#AnTu=MT;qAqo>RM9oXb=~Xbm-s(d<12GTWH$+;XYn)$uS>E#HBV z?cKldbfI_V(XFvrN(@GjzVH}F_<9=N(-juPqi~1%uCgfX^p{nV8ol+{vx$;7zP7>L zr4MAGkqy5@O61Zg_#_>QkUA)~kFQk!JJi>!tsj}_v?}QWd8OXUYdN<}rBQW~VUU;o zQ~$Jkd#eTD+;cEk8`inY8=c1=DFL2gptRoX0MJB@suyeGc+82->BBRCs0d)p>5UPz zjAX^NLm!yWA_seWU?}7KrqY^i%b;2|p%?x)LIybkSm7Kt%HFX-jxuzpQ@h3I35)Wv zW0E3TLH^RcAe9|hEwU+O=(QB#&=BWNy7SkkY;FaKZZaTZL^NNdw zIGjnF)9c{FN~}XawX59}-xFk{dZ`C)1eq-tzW(N#diqlKJzBh~H=28|%_Lo{s^)cm zAog8?f}iEdj)1ENnOTM61%oNH1Qa1B7aCBZbfSAYEGZSv)J@FVkZJnUn?<;xzPS(* z0zW;cea3x}hr-9#O^j zVRVrn*-C0SN9mP!-`(Ak-xFyw4j&AsQ|#r1SovjB76qe0dPjPmp&e$A`K!;Zv`p$W zkC+}Y+P=CW7Gr)*k#eU5AZCfW(lD2h09?wcPR}PK2Y^Q(xTzi<*VTZk;QZJ$CiTv4 z5M&;41W^y@msMtMIzo3T47NK_g>$ano(|8Aw{&MgQa|SFvAMar>cqKdKhu=;msLg$@a{E9871(%jB79{oH=L-kk(2ru{Bio@^~F0my0w=JgZ5_A z6{-8JlH!V#fp+?3hk)u@zXRI--oi$EK#wekBQmGTedGchK|O`uADyhD!FtB0iWhV6 zJEoVXdwdq^?{r>0d=Q`j^}vH86#>DAwWI~pHz4<8+}1u)dKNSn>(b3#Alr-WCAm%x zE{I$0XMg6%AKOzTu4q>{TWjBv(t*iae6`m4BTfa;yD zz$6g+M-D|JCzwU6DtVDMkG@DsE(pjCgW;Hwj?sB zjyl6P2V9FZS2gUDthn{+V%JemWW+QSu)H(&XI#9S$l?KG>^ZKdVj#Mw!&tl zxK9*zQ;J~_KN0y6@1%)Tl=Fi}wG_tSvs@%Z74o$5O0hj$kr==*+3s{DH943CdOGTx zXma&Nu2$56>9m4fnbTzH`Js5T3F*<$DNbj?na$C0Kf4jVyfWFTUh;8EsL|7JN?tD_ zJP)N))#ua_7ZN{EmJ(3YhxDEqC@r6g?AfIykRKgQEJ4n7`VGI=`It-S+~!Y&on zDjwLc)3jXrUu{ z5I@#INpSS<88~k${Fd7tBXS*#a@2?wc^DKvE2|RK0@HgQ?Nz4FJfag@I-#no8-1)i*cnFVhLUj**T(K06*4H=!Jpf8e%Q~o$I@tyju3j`<7lz z9I$}!NjQi5OLu?drp$%3T^a0uh(a<*77*SuQFCNO8*9q_);mLxt^c^qXzeK0Q3RT) z@Gam`Q5cKEsJkhDQa={yUvMx#<`b?tiw%6Z^!>{7!a0{un`Inz2}MFIDXai4e{%8q zQNVB$NOExN9Bf3eyXL}b*pW@F%-<{8;D??EO;5HvJ^BxbQE?YUt*3ju-1ikyN*UL# z!focHKK7s_=B%3rk{93$G4t@`AhYpX@t91p_86nF#Qb2iLyN$cf*k++ZqhwVz(uiS z3iNaCl|YF(e9Dn-)&bH&4@2Tal+bok7yK!Sm}1$>uFhKXH^M$Ik(rM4zXcmz{i2>^ zzuu{Ap4!`Mwf*X#q|my7-C!Syx-)E$nx7*#48SU!=@;HQ6-X3{v zFuP}2b})20N4a<6vP)s{E6@N$y}4(l^uUq$w&+BOSC{X3UN?TeoT8j4?)ddxaa=NI zj4Ar^W)4({nS1B-sH%L$X%;6?Rj*=7uJ;7v-Iwp$n%-w+^(4V#&-CmM)x#Isw0<60 z7Fv!_T0DT>Qjz^8hyeAnNP@;?WkOA_2L#fJjkBAr!Yj~r+_^F6xN&^zbX{q174%jf zyhWXwM)JdEtX8V$=SX}+f5%yP_df~`NsDaw4ok?Gd{N-GpjXsABQ10jpbr1EE+grY znut_I(hd)S)8glt+mW`Sue{=S^zH(@XwCC zSVUip%yvr)w_;0m&k+3T~R|7aRcB9ggRAh zVecRcn+;a4{-k3SQM{P@{9j$huA$ws(4H)>ywp>@?bge%TSKL8g0vQ+P|cY*m2A^3 zY;%zN)%+t#rIAb8D&6?y>F2UB z9+`Bl*P`8u7PExZ%qmfE(^6wTID9R0AO(IXa3})t@}eVHWAo8k?%c=?gkoQG(0|&( zb3%j>V}IKdUH@b2&7+}=|G)osZBnTeF_loMBq5QDBuP@KRF9bGiH@Dg1t=GKs7a~U(&Xw}mt?Le+bM=3{$f!PXT21*(GZ)2ReBkxE zq-9JzIxxG=9HuU^T8wgqC!T=wDV%f3wrhfR$4&<$?14SJuitsLFJ&BLoRo$W{VpV{ z^7ehvzu62nrdNNk(GF z86V_ML;GoL(yp~ZIH#97PsnZy<>!mdE6*DrY6VRwyIK{V%91Mobm}^;#FI!yIVX%! z7nW8|dhSRJy_MM%Je*Yp#Uz!(rB+?UQbj;GuUP$!{V?X+dL9!UPlF_RUA+VG7zrh{ zEBJP3*nsW?5r;SjO*Pmpv?=ImFi=6XjfZbNG=PTyT$;x`i1! z@+BqLgIs$a{}rb&9xe(z^1js}NPi_}8?{znRWU|N41)BtCtz{~J-aVu?obSNKl= z5^uzP@QeFeE%ok*tL;KBg4oDc_p(%`qrYyqI1h1GkE3+%!D`Oz=Qbm8G$ap0pZHSf z61F=66tuc6%%PyIo_ce&PbwdTiIzN%iGLs568s{7=+h7gmafpa6rfJ0L*+q#4_J(( zPzr0M(8yi`)MdK}n_<#sKdto0V;5&oVaCZ+OMjWK`-cBR!)=q&aE<(IXzX!Erm-Sf z7@fZGii{W!;@>?xQIQU%o#Duwh5ww#ZEgYUlBA0+z3-U24^UUdnfQOq3+&!4lI$0_ z_2b3gMS*)!8x&ErkM%p`lAO@UEaw@LigPW zAT-eON_si-^1!1ts4T;;J$8hf38$6xRO2{)6UF!2;nDajHhVEzIz2o?cIxc74G`xj$@E7I9 zf~3HD9pbhR9zF>E{1Ux;$s;hfJ((a(Z&y1Oy@y0FgRK zfQ~TgCG0`Zqaw@lFgfG}Q8Fj={3+>JT@g}u#l=hp$_xGBKMN^WB?rLUv}EYWK~iix z7|;$F{fED}74`#C^NXW{F>=u`F^B!`WhX|uHlqn)SGsuP7@@HtjgSK!{z`e$Kp>*S zgogSCO9goKv#=kXW<8$5MpNR|r1U|X9m(YFqJSjh&t^DD3p3Sb|K_kHzV!&YX0a4T=kBP&`J?$X&W*{z0&3^4YIiORM4FsW;<8r; z(kfO3(w3y2T8WK3Y`q03-2X^DZkHk(coud!#3y}{c773afk#=aGU{cq&yzdPlN*w7 z8&oB)Ra5v2T6Xsu2KBqNe7icV7-MZ@;a#YOI&bCwTHS)GHDBM3m6kiY@+@YNx^>1Q zPdq&gBl+mls>6F$71sFPE?)k4g{MBtvJ+sx=ifb3yqs^thxQvFf15Bb3Xl9m;O-wS zLZp&^{wTf7LD_rsG|N47 z`00$hm)B1`Sn+m1K|MVXg>)sm^c0PdgQ=BYKN3%L9(h-m zr8k)WccIxfX!4teHnL=|Dzx4rdHT|rPH15fT60AWkcJvV8!`LxywCXTl5+Gv&wRm{ z6uY}u*LNdqMpZ}3?|mBiAAT==p#iNU|FRa9u%M$F=KTzOH=6eXdHMnjs3)K1p>HPL zW$S){YPYkhpgdLBUKJ*)L0ni)86mz%a0172nnC-0$naYc=GFw+RRyuOl=PsO4~;7N z217RX_L`0p`d-uB6>rGh=I=l$m+g*Sklp?_CIEAnX+Kx)IaB{%`cCP8=sQ4n*SAo* z`tHB%9iOyFhX!9VqY5;s`;q&HNvD1jlloKf#BVmO_}s1H1i z$R3{Aj0e`V-a=WwmFRs1SMpJKoj#Eo{-htZZ9;>HKaAivBfcWIVr=Vw7Dm28c>FAUXbq2!bGLb!Q9wjw*!-~|!6ENBRM`V`LXrEQ)9Q{l@; z!LPsJ;l#Lai(#;~@W(zydaIQ2<44IQOHGjv0>^X3RIgE^;;=k7-1^^e`SbczzQ$X0 z$t8#@ZHNMTFl*A0sYA?_hUDEBy#2*1S(Lq8ayqRLmNY|4wXHk#!NFTt7YTurDxWrvochjaXZv_*`gH3G^&R zJVcUs{N*3XR!saJ9_>&mZmHMCqz~L9G#C4Y){5F^wHU~8H{1!%&~s78JgpeJsZwiS zd>iJ1Z6&wVRR7WJ!~B~|Yi@5+X^Jv7w%@H2+_>4n7_+;trdYme#7lK2DY%y_n{TOr zZ~V@n-t8$ZOW_J;iek@|>$~fGimOXETvAs$D>d9&>z5xFex5G6Gvc2=un@x8f4tL&;@Eb3-R|W`Ah%kzS5KB6Qj$&*9hZ_cG)(bgJ>6o z_(uW;FEn#TA&WQt=wEQIu0a(;rj6Y}gxyZyl_QTBF4;9Uo21AsVDvb$HrE;zCH!NO zq;2&d+MIq#rARS8v-;|*L+B-b>`}VbFQaEWM>%O7f_Z%AufE~Psa!niiOt_f-u^Cn z(<8=zGQ$#fbw9ylgS26Z4F0aSYsBH7e_H5l6yTW9F+{WMMA^f~eQs_=PS$d_JIa`Y z@fFczT{Vieri2rf2ep3@Oo@!O?5pv zT*$vXOWR31vt!xvF~CUrYMIl~a@rI44>v{DThZprzd~Y*LwTRQ9O7E zvggk?O{b+C^U4U0DGP=V{~IjQ?j=S}%9UyD7iu3g&=<1Ltj0)`#AHJTTAr|S3n_ep zf2V8rcWHrvz@J^@9XLxn45WU9tudssxr^)+TgmHdi$7q75aZW0g(;(CoI`tyXLufUpPYQOm&r3%3EZ)M|B5u6xZKzb~$0afCGWb>Rb}SaZJXPhH z%Jy9$$k$5}Gl`AZ;x%v;Tzd=mTa*N$=jt_oQ2H?E(AUUTFCmq~i>ZnA_;C+-ek+ID z@CVTS2vE05;;`yqYdt!d7Fr#To@S#R2tQUK-NKb>Q&ExE;My2)7`9}fQ~*m{^SBwa z&1cypBh|_h7twB`n!-Msxzu!+6syU$_Q}i;zUq{_k9C=JgMJ7i&%!tF;x^t2`wma` zMSZauL4B7Mm|IQW(fk|kfiayB?p9S6$PJp)uAU}^Bu%D;K z$G6B1fsKj6x+(Hs)JJ$@AFv`DxmyaSTZ-&Iw>s$!3v0pDyxd2KdVxKM zRzjB{+X^VwxX!)2A8!`HRs!G73HXj(1DZ_J?$$z9TwpVo>PVhoAdr;dfrO&g8lYGF zLl1llr{U!a@Lk`U;!$KU{0!<4H(e5$8kfsNLe#;;QPdaX;}T}Cz$KAIjL=-{13R9= zjcclKaxKsvc50uDKW>vR)6))zlgxL@{g$NrqdWBfeym9}`Dy>3ryReBRZurng?FC% zH@1)DW1{O*$-KJT!!Udj@8x`xcJ8`Ce;Ijos&)DkH>VI~4V%Do=?AL91*mmD93VrP>>eEc#HH@d*PA~bp6+@)QgP>AB`IyU9(7Rh_=nuWGIdFD@nw=rdI*ZoQ5sP z9Gk!27AEdPT{GFF{_N4bZXVbUo|*K}xkbiylV#G3+VtTIx9!|X2{U?!zM2`o=Tur% z)fr{3$z`JMGz`v_)2GaDo(#OoIq4U0&0i~j$Z1Tc2vkl;&g~n-6V6DMad=YyNFL7qIoK45AMszkNlGMfu47JyG?nA7&?_ZV&y#4C z3m8x`6y(~b7sd?FeY9BKrV4+Z&9{1M3GWo75V3N9+yc7KK8mULyn`%H!fI#+ITNr@ z-!!K7cU=-ucZI@7?Y)oBrB8MAyzNrf{j7{Bz60+In$8L8;qG(%%Y2t~L^q)16*nnG zT^->-+=>i_1-Cn)XKq6>@dBTP8Jc{vB_bKzm2t9H+KjM{w70>&!jR?_FOXA%G){@; z!nhBgp&A#?p;N&(oIr)UA(R(8*jupHoPeu3jRMS5lRPo!U0K4tMS=U%xE=WzmQT}S z+w_~A;QofFE%5mm{f8X?z?Uhy+evj%8{=Tv&s~85XGOh(VJfGlvL^_IDH|F|gVG-e zz{Yqs<{$VG_I@m2(0kgaht|TIYnwPWIj}BN9+pD>i^z{fU9LFC%yajd;O(J?LDz%z z$?iC}rLs@Lfp;Ret1+yjpYiSFsAyzUu26Zaus4o0(ygsUPMfB+Of%Qj>_8h6YC|(q zi9B8A4B6E{HG!*`jQA+w6yw4y_YpA++sdkRdW527kz-4axf&Y#uJ$ zhrfL38WJ8!p^Zh8i$%o9DFT=~C zo{coOQ-I`Q=%%7)Cs$MnVJot(BT8 zeG@<_lX4V(w!xLVi3RoPXo zqMwCQHSLM_Psqi6OFVg6e>-UXk!%ka!W`(|2uk@LlW$TE`iWD0G#pW@+JVRUB$&#% z)}~o-!vmw=#PE(dI+DSyl`XTb&5DEtV`b>ZnUrC{JD_S!fefA=N^^+#u^b5brv{BM zfES?P2jw1}X;^fxS3TbTF$Lr7We|@d}3l8yBD)WwF67()4 zSX6OYA2V{E=B~?N6JrE;E1{hQq>u}lO~>*%cNXzNqBM~|aXQfWVTuOKemX=8 z!~+f+4WpwD;>^z6UHIg*5h;CvT>Axlu5M}&=+{Mznf;Q=o5*WUE&R=7k{5=%_ToB*eI*4(Y^XWLhylwGpoxCM4Ink(jFb1;wn_|GtwXj zLf1y+Yt|fqOFPj`PE#o*CH{8fNZ8*v!IC5QIg&-iiJ8EyqHKd3w-Y@cozh9=b-f?x8NgFR&Y0ZxfQtDWbQA;OAAu<9q8fIcp5FyTBW zlcxTJcrOctKkz)7Zb?=g2d<#nMmzETu+H~6k@ExJ2p0*3et2N*Z}NBHJ5g#UVmlyG zPeNK2Na{KDlpEPWo#*7p6|RSdt_5gVQ3l zHe$qKaEFd#$?Xl&5PvgdHd7%H2I#*mc`w|u{%3*KAg%aj4^N&&9y-lz3quygS_`e6 zV#_vt567Jcpy`st{?y*4#~Ofxc%>`c8&YCp_Z9PbQN#G?f!a3Z6qb$QEhK4CvsDW% z*9Fb9{DKe6*HrophFndzC?B~Y6DVnxBLOPNUA_TII`_@5uZ1MSGw zxQ`@ClOI?oG@_8l57jNit{MGpKwp?0Jl$WKBg> z?linY1=|-E|6u&h-s#zYzwE{MJ&!NCxw-iltQ#8fC4YLvtKJpl(eb*~PLtdDiLh(c zLFCdevT8-?kzmU0C$W*Tzi3bk(XO${2%g5k$}+bT-fyh0ye%)(w}X zr|PR1;?^UaVf1K!v~Bah(8VvQ>@zN*VK6DU=UDJBb2WjY{ZU1|H~ljA2*Ko6`AF9_ zkWQb}EE_GAtJbR3LJKSFfCxd2uezQvavRveLqt=Q%iFz|!2|+%S76xa`oG+tItiC_ zdwT`H-FzA|Yh;SNCZ}3?Hp3OGvp{Esj`JEQP2t7X=w$^* zEUs*yoEkmH?Tq_+fYKg1)sB92WF%}(*EoTwE2}gyy#=|>Et`KEKAeOhIEhQMV_l-O z2xkNeiMQcF{=+nZEz%=!6K**cR>jplVRw|eWi>S{R>s5O=f6!!taY0k!@IcJw{Wh) zn!J5I1^7KB1hQM?6l3fKPR0v%gLQ?{AmUn%H};muRBf7g(m6zyvv^0^5W3;ybVab9 zNgsYHFg;tUNN)R;_Md^phGLavNXJfT(%^C3R*o?K;&jqG7BK`FlYlR7qK`VgB?x3+ zP-H{_Y2<52F}O#+v!;;&1c`L!P~H=|+l-ZTkwJb}h2+RK4)OFHQVr@J9};Mk^_Cdo zdqnzZZZ|X^=}1_B+h$fKMa{@9w+DCMh1Z>j?e-!n0L{pIfdk#EouIyQ!P3*MDo$%l z?wld(G+f`lki>}+#}y*qp^@d($1Of}Z5_ZYxi$;;12$-%rS{uT0J}mAsS}cRZZ8?P z=_Ney+8%A2Svd0ELMzX91gO?H?;FEdJ49%=Gnjh6|RKUxXSpK$QR($TyClVFkGp=137GhsF*REbB`7I4^ zoYM#O|7si5JodR3>P)Sjpp_0|=sKvX_uoww$Xu_7btcdd8oA-?q|`z%2+sdudcx(h z^8HK7c$6_@#Oa7Id~@babx-F4GB@#e5;b~h~p9p2Dm!#Ou3)D zrbj)#sRjsJUx`8POrups<-g*pvm1~#H)(x7dwg)dO%KJ)-au_tFl@8a(xx zzx9L5<|)S~W%Lqk8jT+|)wA?Zj*M&>C^M>US$f_gw>wU$_lcQzQ;No&3P_OG85}l6 zE_{J}cX5C;dtZ`cb7AjQ9nNjYP00Eo(RvcQ=g6Sr3);cJ*&q!S!Rz2dKk_tx8ouIp zxe5xmp*{&p{UeTkhGId}kh8X@6N(9kyUbf{4w6XEBUh)B+v4HFBz5>*Ju>w+mUV$k zn36%>YEv9ZYya%1yj;kxT(A~wE8mFg*-K69Aj-GMx9_Sionj)Jt7_NY#BS?mh@&*g zUlkVJ)X@?5LcZX;nY&{`94J}m$s>d49i4v=H#@L}e-(WYu<3`3j9$??Cam;r|6 zC0489gp06_!7tiFUZDp*bHTYEF4Er2Ye7Y=b}n%U2p$l)2;UEoWDm0WUJIoP3EP(9&!L^JH>_W73Aknjb9pX?vqnz1jAFz zrb+LAd3)KDx}Dx#v-Z-r;oSQIgM6bDK-mi$YVw&lnJ7-T0b0nur_15+GjbEmWlyB< zI-cAui6<#ahPa%yZcq|mZ<`)k4vZyjSs(K7l*znWc$VBd+IMK}D`Coz^Uo2&717FH zP?3=VrO9GkbMlEE;K4+TGXHEo&D09FyB{|9v_Gru4)pPE3t1)XY@(sDg~BvJqr*w$ZL%aq;}Za#!gw+ExJcA$K3Qj z?lyDKb=x{((0@U%Cg0X3!zg}vOJJ9^$$e|(chK588pJhgDcP0Mqz(6|!t{Oc)M-z) z+?s#EjCO*`OCDZGKC}3PcBM>o`ewyrL36kJ%EDIsGQQuTcw3ZrXdU7?5#)%?m zswwqeebG6H2Ox(Bul)d4B%N-AQo)5UG1Y=pU%JM6=NJ0Wct=sJG!4^RF!d!Xx|==Y z{^3W-_bpo(Haab+vIFsur>zjMCRF}-2u-v!8;cWSgXpY@nN2RFgzHcTUMqS!>g*yA zJw4pf8HmSbt*`TEKaEcc-ct-P7^t)-XRH*Y!zvG4M&UFW99o)C`w{eguQJcVT8-ivcYXQ>Yex77zZGmDC`;LJOy(v}gxjU$C=6GBS@t3YxqjK5ZL zi!VLX>mX}9kUoya9_iwgY(AmTVDT1wyk0^hsTvSKA5v?UckzN~!wV!wH`wV04)zmQ zITGBN0Mb!igPzmInH-Rs} ze1r`eW~(Acb%Z5PWw#Yq0KiciK_Gf7Zg`bOl+H3YzAGTJSJ7^CksXzXs{=x#l~Bi! zRqIbrcHnbF3p{C|mBjMX%G3|uKHCc z?R$^U!doN38ycNCaa;O}9%wDipNjd9W8@v1Z8#mW!oGCAwuDu+8#5nfs2wo#>(`b)5@%z4X@wd!fLO&=t<< zM_0;QF$p;2ok^(6r?> zbLxD8@0>7IFA@Df_B_1s{DH{?u(hR3i!#i6?3w(bk;Kng+FOFLe@@i^7LDa<`uc_H zJDxrITn$PeF43<<@1*JK8>h=srS)Jdu-&@ok*buLg{gJ@-ySGO#;K%1al%H8%-Yc_ zb~CI8z>-^^=A`VCuIj|+&MwuwlA5PoJK}@><103%#$<>8)k3@<^CA8))DcKZZ8!)kh+>LL1*eA)2kkHOXj&9C*WO z#6{>aQL#vZ7(#0)!4y5kHBb#TrRfNbr;kVmmZbwH$Wf_%#I-Csdd>elPd1+-_#k<% z5}UWcWrNoYaz40BXs)+Aqz83Woon}x=BCNR2+H_-$aTfW=dSw)Fl5Sb6ENa+3cL?j zyy4j>fVa4#*KjMxY#8L)FJY&E*TJjTA7asTmfT=v^C_~)3xEgqA=C|0PBX8@1t+@? z;@@yeO(qbWC4D!h-0T5WOG$r}>_6xy13h>DQk7+DZDUj)?R;Z;YZ3GpYU|VZ@LPD~ z2Y~_J2i_!bWJ5{7zk5Q%XQMNsb8q<^{Ssf;b#XC$(_VAdH?JWvm)E=zYE$0$;pbu$L z47GX~bw-_20E@5$YZH+lE?Ct9nnf}%)Pxhelp8QHLM4{HL(NEXgy!!0@NbbF=gO2E zF26S`LqR%%^AY8LbKiYD%h!0X#9+d4NKQk^zvekX3yptornq28X1|{Z8_u&&@!Tan z0NV=w%*8I`P_PGrvmZ!jaqMA&QTnKQywck+UJUM?Z_~(*KYwm~F!G0T}Ze=s?9kwv(xZ&pz+j0r;(P)KvzcJ-l{tk z)JDECg+C@V-C>7wjsdp5+o%qq+t?IwJgNze!UYX-@8;5L)DCL1MVW^-#l03(}} z?}H`z9yiT69r&H8=U?b$A5odgE4ZS(UvPl0(77v$-iO zfr}Z&xE1!9j=R{iXL`!D-}v&3vXxdzzI&!&PXKRK#Ulg}`IUgyWsjr>I=zKT(RL5% z@`=#eThKmH(pB6ge<+;~>a?IAIAfml6(W%d^kJxj6MEIxi=)3ynu-(jbx?Ggk-&6P z7RY-Idp+qOSlonPcFWJO9$xM`g+lN`SvT=^d1h^F@~E}ubrKLZ?TCtkOcRlh)9aPYOyC~sW3 zicsk!uCCGaZEkI!%-(2#R@8zKr9pJq`#=%-{T^h-=+C=Z>cQ#MNd*E}%!{w~xGQX9 z>e!)7oU8AQv^>Zn|OO`I@UKhi{*_+^k=rlQN^Ep)2FzbxW8W_wNn&0DVJXbqk^8 zFc?((;JZ%PGSKhvk0NfwH8QxUPYn$|?3D0hm9NV14|n52M|c~@Q{EIsTMxi0vc??d zi?zjWvC~??**TYWp zZGbV^9r7pKk{EP8nWO~oO4CEa9wixfoTSq(Pbh;pp!&?%-Nq_mYU)^D*$w-v@UG?| zMq4UWBE>>^v#BinQLmx0yhCA{y>>_3FEP(+2-T4OUUgYyhJH4>yPam~MJZdzT zXtxF4Y-(AC-HyM)oaVynOm$K+e48d4^3XaRn7cVd<`!$e5rrQ=_nW#}pUfditq zc8a2kUbn|LsExQn%0FMVXtZDcDWev2Tl$hLJr=yzfnX`yS|%7h@seNh#P40z zUXJndi42Z)klThJr;H7xtJdzi^>_p8n|tJc1qEu~&U8}JYKRmkP61gq*RCEl$&%e= zW4Xh~=*f7r(~odGb$m4MuJ`V;Ei2>*=(Z<)7C~Nudvu3BN7Q0%)#_sKyslI6RM(WR zG0l^w%KK)L*g)NPcR7G-=kdB->8+jG=BLa5?N;YG3^H>9T-F93VbJs9H|%8|omsW$ zGcx-9hoASR#3_>&V)##)Unf1{N;`j#?+bsaLkfr}RY{tSWNI{Q@A6Z7;t(6ocr&}V z*L~pjD^AML8TMNo^fy(Wv^%NLQn*Y`cGck@q>P}` zwX$Rar&!?+{;Wf@G=p7*I=vFDgVPHC^Er40CtGf{sAv_YAW5w59m9$Tv8x->zp!pT zNVxkFphbDfQNy)X{1kB4jDJ`@GE~7>>G93K^!?{CekAd=#iGM^tFIR8K911SU*!0C z{9aYNob&N3Pv*dh-#bnE>}FRR1Kn?5{+pfA?X>6_P%t~-?`kruLsGG?*NmJ`rc+!C zc&4aorOWrdS4>b9Gf3_}45PO8-a*l)&w(6W)3l0JQUFY4p)EzQ3{F>BR~(!-t-j$v zLav^^uW|Aw^G8Q@h#tn&sqTG4%aGmIx4EIVHC&I`fUm%K4e+At+XAgu9zlI^GJY2` zd+b1>{ihw+Q#&TJJ`uFQ9QJKWcV}DI!(F?Ni?T%<_cBgh{;U5{H0AG*yRU2f;PR5B zOi!a=)Y|P%t{lslijV12hI9RPs>ZhtbX9ylr+Ydk`NPC(gE7uIQn|9ev-=*P2PUgRX(Y8grPfN9{VyIp0hvk zJjUlXS~Dh|$j|hEJ+ThIcsFiHzrD{l4t9jU3h z%W_BwDf**;)z`nul4+$FZWee{E_^dxS99g+<1_>11@22ovs>8636}X4;BCAZPWjaJ zK?W6}Q~ug9w_-&zE_d^RrVLD0+>9mE*4zv2XD9W^xrUs}YUWRtX`y58Z89%(Av~6A z2z{~*Uo`r+NoEDm+LW8}hrAzsVNua$4~@3`v|jQ?%S}1mAu?|^emPgdB*E8~Zcle# zXKG(Px`Su1mX3wT>AKkPdqCE+%)&U5Y^Cw#pVY;+E|1k$UM^NopK;x2M2+=dG))_S zmaRZFe=rzUO%y)FK|56(L+KG4Hgxg~r$(>`>`@G*uweUD=CQBh$gB)ba*%CCX%NTy z&u;_9I)TD6SA`R9AI{Y!Q#)6k0DpU8yJW~;_Z;cM#=3dmO<1AmWb1IFTQ+0At$nDV z@zrYD+poFRSkDt*nl5OMRey9s-;aOLL}C7m{Ab2>`G$?k#@L$1r08iqG}w(gU}W}O zCYKIPf19$UW%Tzb-S93B!(+9=+h+U zwkFimk*nD4!|BhYWOu;x#?*+Zre(hW@?UzpJhhyKmpsE9Z+R3rhpRHz` z&PiQ(&&c3(?bu-+yKr1j5c0Oqra1c6IQ@gx2FBM>jnCenpNf_ym;Q0zn3u^FYr(I=XgL%w*x#H@`pH0-VklQ_^pa-WOIw_*9Z*)uR z8_1s~Ghb?%8)0ko4Es3e$G1qIQf)_qT(-|JneTsV=V*Rkxn6m4CIz*gF3QYeuH637 z{KAq{#2K^oo0ng=;tOIlyM=AHE@pj|+{n=7;sxeP1%Y*X@qsD%8obJC=U8=N_UiuU zyW94O!$}VRA`t%5$2tyE>enhSVWity%Tm@X$maW%sx9FH3x9NjrJ7;EDs(@+H-BO&qvhS-#XXbc){S~aNLFB&4pag+YY)TSFN9CGGAWG zdzJOk=_USb#8&G5>K!^#mRz57QY@tk%=11JnP5zamRSz6woaEj)v&sNLa*UuOVdNr z?*Q~s>Fi!?&}++dHrlZ}Mr468`7PfSsscnF8wqr9Ay26m>L@E62n*Z8^Zo)@(hcHI zl;(TQy`7Nf20Q6bA0^-0Ur3(Yx|mncXhW)6gYhzQsKt&U)rw|Oa=wk^3ReKPIA?c( zoe+$hEq(q5@VxE&|L|?;{I758lzf=CwJtoSNvJIY7p(FJie=D9Eam;T_r^_p0?cc= zS>>ulf(Dc{t97Kltyh9t)w~SP>!wc-b||W0s-TKp6Xn#-PCt#^h~vuZk7q#8LaCVv@07QK>@LJ4Z}mug_ZyAg&AinAIsW=7NmfeybJ?JHP>YR zgHAQ^O20ka_4{n7-lRiwSIT{G$sCk2L8=?g!i1F9`_7v|gSBP?dN1>AGO>e@5=N>L z+;x&%xr5%Q{LWEo)#~^ktCs%MC6%X?zk2erE14I@C^^t^m^DB9E6>I#UP>YDjSGs; z=!+XbLCZuu7WyLaU-gv**07INh$bk^C`>F;7v3dxN|jgP@rJj%|Es)O^Vi>6XH8$P zqNLL7e-WTF{}%#e)vvHstY@(l@M&rIO~2iYe3DZindJt{ZAVg!r@NYhh5}uLsPmKj z-^j@_p7wIH4;iy@|H+c09X)W4S5JYV=?F_5`wfZWC6oAU?xal;)^(w##U=${lp?|f zMm6$ATcJgo%EN?4bb4==3no#IP z67QhZfe)-p418h>1!6Ff0q9ut1g*9iVBVVAIf70H3=RAwZj!BZjkCg;S=1+(kW?sl zdz?wg6k>NE{tv*{$lf+kzp)hXw-9-6g@%9*sRdoSv647@A6s&hNX0n%P=RFg zKZ=MIvYaBZ66z-lwJ$Oa6Ih=65ug1MgUy_wsZtv-f&!)X+Q~;_(qQUb3*`wfcYYgY zmL>woEq4WS`sK$q_gU;m`3haj`vuRQ!hR`CSm?HsO*4HBq=D{X5g8yyXv(fjWKpQe zg6H|L2hzg99Qi1oX(t(BcMwj!2eY@zd_b{4$B*Pc>!2K=O)GMFf$V9fPHUvpumTyB zCzIq?uDsCr=|JbNz$y_xg;#OCWy#GDoZzNPA9Fa=otZU7yy0_P%v-N~vqsb&% zvmr*wUmtW)yzi*3()7XlOOTHB(+_hR-@MzxTZQ3e_^iW!9}hdUXPi=@L7jCiLO0;? zX`fK!5j4%#ZCT@BHFTvKncWpMk!B|kmDpX1*K59XXKw2Bb`_e0of3o{B25Im1sLHE<}qb4pQ3W~_4itrP#{`C{P~!Yy!Ug2^2%t zUi~3E(W2&ye|mdI;ii$FfhvQ~wBW&vs{+4+inXow?X8myYr}PVS??^8IzsXfr!IW}4-Do>n=g}~3Li#72!S0u05Hd{#g!hvW%8WKWB zMwS2&ijWd{*=Un#Gj-tNB-wNVXc$*G2jREE-X5UoKC>m()CH_@aacMPF&EOCqMjjY z`G5--9Z9I2pd4Lb{rp2VbwRe&lHY5<@!P{j$Ze~T#znR?`kT1=dlq{Q zBu?O6*Zp8@E<)S~7g*Dg{Vn9YtB98>yv`E5nV6wKMdyP7Ej-iB-F!TR+KSj|=x5;& zyLG%KUi#H;vXo9KxPa@l=2|dOKcc}Ezrd?sfij?tT;PFiw`6h;-A7*j0VTGGNSb$^ z;CpVDSi=o$@~Z}Z#D3(vXwyq!p4ue3ZFY!3s5lcQbuJZ4DUvJ5EyfwD=2Q)?ks8?U%bqHxHX>-fjLefyVV|9|!+UmU%J zyC9`4)SI;bjc_+Tt_fIc$S+Z6Y?!)OSNcv|#CTU46ZfI%(v5|!8)M)>c}%8cfk7Ev z70fvjp=NincF7T=p%l4WJx=+#E2W^}lQ(NWqivsrM(z@Q`Qot|=71ykuV24%%S|mz z2S3x(U4IG(j`cjw5sy0jD)g4oo*J)RTV?id8(=bl z4OQ9XPw!;K-&Mv${5w7og$`kgs$qf8Fni_wPXuFz=8|Zk2*E0>`e%tyR|=8!Ky%(O zIepQUiwyq*VQ7hIw}zGu`Ewb67XcI;#shBQ-u!N&k=E`L%}(_EPS;4>wcb;NVO2O2J^T-Gr?(T0b52 z1Ns=0P6+6|z8xzIo)j^}W+t3E!HrJLSAZwCTSAvTWd$VnW5(T}A(O=oX`mDf`9?awp3!2%lomSl$;h4 zAWlo@YZcmI-IAdjnzi zNK!;vOu{W(r9=k+ii>2AkC1Qoi%eRzz6bxCkZ!Hz1`(y_!j)%jPUYx&Hfo8=Ha({ zmW?H(E8H9VYuQ3C>b=tCbhE7HDN+@RyJApSxV~ums}(!NA~VpXUddS-zw|+4fg?I1 zfGKwB)yDCU8A7%(S5btR zBvF<@i%OAf*=7>P79&e`gRzfoW(+f9=DO~y@9+D&f8YOd?sK1WoleI&oimO1b-iEj z>-Bg&p5sOr5HAbERP)gM?xqDPA9r^(aG?+oEA;M9#29?tYlcT;qQfK1n6d+Qh4bd^ zG@5<+{O1lTONiyM@cm+f4k_C}Ihd$D`Q4EJU84QeJhoW2ttU!Q{7OE|`J1*=tFnpbz3&9yo z!d)7N@u<*BM9@U@?ATe61JLoAxfvs?FFlx3 z3#*uj$HXScWVMwu6$irZ0298~Vct{u-$tB9PU04H+r*&SJ|?cYP}O-|!erIv7U&tj zY*mlih2cBK%!@S5VO*c#spqChb1k9sj$ZKI<|?R6;pH$gpYdB)ida!&ZUSVa@2wfC zBxCs3<8#n2Nc=N+W-@tD`$eC2^KWIMT7W=pmK-Xi1%%+VBn5hxu+PTn7C8GuSfQV& zHxlv&_bUCW_TxeYp%HG}q)DphOQ7v74sLn&Oliy^UCCeP;-TQtP3RQ04_nGLo3xSPAQYH_i__}##r)u~1TraMGGRRQL{5IRD**4#=as8-@uD4B%<* zHm{fN*zE0kv|r4fh9NS9SPE>)$PKrl}%$wl%SPd@!P}Q)Th*3T&`Rw^830#kIJIQ%)@axLdM~kS4 zsUn5u(xLFkqqYY-NuMLq-;g@_JtT~IV$6;$=NI`)F4;Z>jr>jTU6ClPy70Z9hcniG=(xSxhH`a*JG}brG=mvp7&55LcINvBn7A+LXsX-i^dMDoj>C`?|4gRV!Zf7 zg3W;wLPYCJ804&A)Wkmm0y?}aPB2f%w)tDS8|T`#fF`41@|_e zg7jCg?Ejzj_DKqhfQjU3Ma<|(3MAfhlNhPYbn4qEuJ#RXLY!qQY9HLJ+P}W3A@QjO z`hCv1tbeq&Gb@yy5zN_!30n1w6O~o$W|L zCx@9gwI4FH4e=^sPHqtHH{$BH<;g89mB31Gfpp|ZLCs6t^>4;g?RW=V={9;mLGrHP zEn%0r4xqK{be_IV``J2+h@noqu}u%d!JGU4N((JPK`YfDzO1gXXjE|7U+X5fMcrf1 z@!hJ?;ueXgt}%(NU+*sL%FrKnsJQ=?9l~V);ZR!0A;mGyl@S(V%gOEpbmLt%<==KMo09m_n_WB;vc?@)pinai)u9Es1{co5$9HW zVR3sAr~Cwz=7r0Q;M%8DH#W^lNeW!o59F;rK1WI;8pq-(y&PIOVpiE>%^X{DLdJDX>dI?4y*yc|5d zbQKn^mW?t)X||5`j}tEs>md9p--yw*eZTCzaO_BBZM8S=9F|Q-`4yl~e%=@}kZ4cr z9O(R$2*;yD*8fjDO5VAwzws!#pSP|%&PS>k78HCsk8?Zl!_#S<*w2Xv_=fkZ-9`re zS5R3$2oN|7@5ksst!?m184-U%f`IB8X^2C$N(>Hq9lU9It={Q_?OVWMo!9f{#?Zko zu}_a0wNL)nvj>+q^pWNqGU_;GpI?=$#n}-`ags8O3fZY3|l`WgHdg!!C}t63+VG1|C|G>q%*732$^ zMi)wHrS%fecP9{b_S5k8O%2+S18s=XhQ_FAGrJuG5^`w{G zg{{48n;+geWg7>qfDsA)HKx@AzUj-&Ug$r_DvO9{Pr?1;>!HvDgE^~?J^|)mSR!+^q4$pu+V_WSQ#kR*Krxw>a$eDA4Ki|07&9g|4rCf; z$uG&!PV(TjWY@>Ob9mPgh4>3_fO$LZdP1QyLou|e*c?*9I=xY|8AxEB{i3E>QcFCM zv*lkE86S-07>LQwQ{mYxi+LDVt&)l0<0>vpC7fejVLhKvaFnio9q3ywlHC)GBt!%XfaBPs9^(AL~|TQ02JhubJtz+G$Mnm z{--$Wb%fUb5SdJ_xMB)5r-jPC<5&-DA0ug3-sgO7L)Fl2Znlu#-0I5tBW;QEc|_rb zn@?0BWEZX8)p(YG3WNcY8oN;5eHlKsTpK6sMjjK0FTrUv;he@*JL&b~f(5-cC&8Ir z(6Lb95khk7{RY@a)MZgZ*vi!?mP0Xzl8EG@is7{Z5+@s=b-kMQ(4fx2-5C`HR-2m$R66vWqn6XydzR1f42F%F71M zBWyc$pFpQ?upn6HFUw4i8!%0&e)Vn*dcf6YQCFX{;)@!2DDzoQ=-Cf;(ku$D|1(C$ z#nmY``SJT=aLgj2Kt8@$;C95DKll$=w``ded#2weY#`BuGF*(;Zv$a0__P^6DUhnm- zBWwG+^M#}uv(7*t9H=FMhPaBMr}01$8zv^J+Br7ZKB68x9@Q1%#=4K?srHWPp{~Cy ziLY96ikn7DF2|Qqk>Js9HnzHoy)bxZs@V`KgLUS=MAmhD+ z2=_Y3grfqjlA&p#uyoQ=P#Dr_i(tuVIvB%ZIjxaKc%)!Kp&E0t?a^2pO_fVm;i{%^ z8W4ffTOlbasQe#6u{O&_emw~LjEUUIpyn-0T;gI(U`r$ELx%>Vh)#XDm1NOnCIx5O zAn)RrlhXhXFwve(Y1G)qZ);0pqg|OUZ{h!U%7EN6&Pn@4^aQV8vYB-7Im}ifuNM6t z?S02{<4FBN@;zler7Z@oZ0q9O=3RzFw`IaHZf;=Pe7vBTav6|!snl$vADo^xkwu8( z2-&DLu@u)ymp}Sx6KJDxxt}B{HO92|pW!2@TY}Xs?3AA1Olfp4$pK7|VdCd(=<(!W zzt@B!e$qi{^c(b5qyx?{bIyIfjBUfH+l=eBQCd~7SU5pV`^tXh>$iVZJCE}VjQ9+k z=a-6$+iR4gHXkum?jj7(2F4@hlb4ViV+muP{HmOK{?CA3?9?pbfWUr4=G`b6-xc$j z)X3!?nYGa`8<}7t9rg7i7vr&omUSRtawwd@dF5NLmmwALZUVe9Q0 zYb8L(Ds!z$&$c*C{3k@4&Vs+HN8FxTtccIX~enzN$NJ9>dYQa|vciP(ABT%H@api$Q@hL6Gb2}}6*!IS+6OpZcf{+y#H-np z*O#Zy;-oAcLu9QL45Ck=LWOU-%b8kxktelN!cQ+O=e*gX>Ky&NF#iDBc|q&@?rM(5 zB^Moc{Y1k2Pa&JvYHu|N-H$dGlkLcOlJ@~?Bz#a#=Tqqc8BSu~-DNlIL6qI?;T z^qL2R%mD|nMO_n@FxdG~QBb!Dapo4}bx6>0 zp3jubo)^D&V6aEy2G5;g@S0qn-fi=2BCQ#H2pZ@4nsbA9Lfh5YvTs2e_-dY`R9Ifx z&_-D-F&v?+pxT#v4-p@#_I8`4{V}^k9X*Nq72!_=k7N0Yh2*^y{(-o%oR{ppLq|x_ z$)GCxcB)HZ=@DFs;TbnjKWmj>eF-vtXc;iSsxg4{I1=ilj?yLe9^zMRaT&M~lbs*9 zIG9#k{TT|u-G+~VaHdKyVisk5p1=lJS-OsBQ;k6ajqfG165yl7V)_3e&GL`5p~_HG z;a5Iz&X3%98L-dj82yvU>r~1XU%|2pe>`XUw7>VH$1Yli#z)`rpmS z{-V!2$2(n?&epcwM*?+GQ1~vcb|rC{zefWkZe5rWw^R?=78W`~_29!yTs22!{e3TQ zfv)a7dytfL&^QUAoZ4GOMiO%Q>MazpOyUPXmW>Y>hT4O0a+8>gxK%A6Ow0sa@_`P^ z0kamH0=|?p=nH(7zz=?f5Gb7mPBnTP%+iL=HNQ-(Xrg*dHda)tA0+^LG%6Ako!``yHFor%QX?8{UNYt{S)gO( zo`~=A1}|4n=B1Xt(k+(aZf-YZe zJ~g^Zs7A55`_qy8!t#^p5O#iuYqC`AWHP%XMV@(Gh|d=`eyDieg}K|JD204c zpi4T=)<~E({0C0Glu(*}d_@C}Jx`T2BA9(AKF2FB_uRApra3>DO^-61`Oiz&Jbk-~ zcH&admTm2aUR21Z`o2Gyn7CCYf|KxkNurBOI;~V~aa}4h zE4kl~6H{(KTE=(_Z+6X@5i&sl4;6*SRss#SKyrvqkKR{rza+cNY*ZulCh*Qn~| zk%8Sz2E(V%1963DrJC)Ye%Q@-{;bK-6bfd;S!4G$U+UEPRfm$;TJ}%*4v%#73uIpf z1;R>`wO`I%mq8qKElu~DJ)pSh=^$vXukmlw?|UAhE^nMj5TQm#wl-F~CQ>uFfzP!1u$8-pbz)jHm8i$g zYv;YL>1?}y@fQ}Sep;lZVRy^5*#o+^9vcPkU*qn6D@pgakOP}pmdr!b5_p`+DzmzG z`N1MUK$eQ*CBISQJT{r24#DSfnp%r)0;dA$Q$_hyDn z4Q5%gnLbA5S{98?(PhfA+op4}k?&Ysk*69P{F9&1$Ere8nFR;eek=z%VQy{2E54>~ zaMnN*nMDtXzvXhB_z~%+AO6&Ske{!S`rZ2renW%iVd)Dv=W&El*@@+4kuLjU6WZmH zqDP9%ZL*mM6LvM`W^HXc^@*(;i&{G++N|cZV>j?ok%MjEa_1hhT3Z+Y&-+YMX87Rh z!_5oijPX*0+k)xg^$GoWU-+78^*+{N^$%6#^*)=bq!eH8QiMa?wBf;lrw6Mll!ncD z*y*l|RTtZqAK-+Rs>UY6MCOq))o)|oyZ$C`5$5GOy$rdlx%~xYJ`E$o(c1MPLo#g9 z9C4axwH>#;>D0%`4Jm3|r#U3?`uOpPgHp=lgV`znoA@%l>#Syc?s;gn>SGN_&KW zBMoTQ!Hy+s)7GH5L7mV~Cu)2DT%jR}OnL0OD5?InRroTS#MuiMi~(3^77aWtbzB{9 zCDauC)QgHC!0SQ(TT8`NSz!*6w06;Zq!K}e?aq5i{auZt+9-c%B6DpmN6`1Ng{{H` z*z3r;2AZkvcQt}@R5(z%3BISMH|K&3cA;UyvF(gWlw+LIf_9;T{v+5sY`u>=z}Ibd z$1sMSokQ5Mc}4DZ2mUqk@kPEE#o4$*r$R@XkW-}^(TV0$5qNKMe4#>IVwGkvQxZE> z_R3@THT!MwT&6a&wU2rjvYN5~z0`P-n#iuA_fDJeHtPybVcp-dk`D*ppe0@ny#F}u zblFC2=dPy@gGx^Mr_>+f#gl@4}0a=!r|VK=Wx zlAu*}U8*1Oxr?d@ZRR$PbO#0pZR1gQ&r(=R@@FW%^M^UUX41+7spqV>yr#1KR%)a#Z1!ZUYXHYWdPzI9?8d zFEKQaoz$&TP-4^6x?=yC6|cCJ^rR`9XXB-OPYZ5LF8Ch0&6n6u%;tXqqV`JAsGp%J zZF88dP=&YB4xBS%vAp!WQ(M&i(8nNLcwz0de#S$122^e#Jm&UiHWAPeFYlO+S zhTr&fiFA^KAkd5x>nV^>VzgoIM)-j9GXdXg_p@8qQ?H#oHj><-izp0%qquJc%XyrVR;^w&ti)%^I2WUolNO-zz9jt0#bZN zPHiN;YA9EuOE1E$RzGdhc7bgl9|oPKNIj@xAh&~5%2gKpVyo2+wxOx~y=&9G*TD5D zcb_*WsCh$HXT%9>OYqsLimTdnj2_3(QS>?AknXwjMX70~zsSW%Q|A zQ{4>CRIs9TJ8Hd%?mxJWr?uD~Db=q>3v2G(EiwL=_V(j4Y;7de z(+5}gH>yT!{XHPTMi#u?G9D#3p5<6tac|@g?s#5fkl6b-MgEdFeru1eQ+4PXLqgqJ zYxC@slROuqkCp@g%K08R8QFGa=Vcb%ega z>A~Mm&6&XN*j%(%tLDkS+LNWa!fWNCj?}x2&KJ^?L6UcmuRb_*f5^Xv`=)U*A>Gff zQPC2OwJSN)E8%EgU;(zlQpmyuJp`!n6TXd7xr2^azFPjs)Kd5>xZ4>MWjS5>(hyFK6)f zTe+?rcP9pNSq=`{$gVZGs3lV{9pJcbZeG;7yN>C2DgS>9&A&kUN8lIuwIe5V=a$&qZBsgJ5sIN30Pl+g0xeo2J9S@ zg;##N<@-&4iO)^{nb6El=xwiy!jsbWHhvAK==HJxD9;bUsfikCC&UNuFV&WTSZK&*uf*;wxIaj6FUCiRAbQh8f3hw?EBwtHszRugE0fi6iwAV%S93zWD+#W zm}stqD{a>1sxpQ8w0Kd~`5i^!gE=k2cJ|H*MdEi(yeIxCc`>gaH8TD`NX^grPQ=R_ zttT`xPH_#_Z-xBdIUE(RCJ9XjM|c|1f^bL8TUR2EZ(OAIz8uVEjRpUQPL!1{cgnTb zaM025Z~E>DHP^oHn$4jszC)j^;1u1v@4xqzUhW_QixujDp#hDq)HX=06q23&k4=R; z2TV@buU*4QLA%5Bpq2M1_Eq8{dd)MkT9A-!vwJ?SAfe*B^3S?t(jD4tCt{bhpzZ~f z^8yGq#x-!FyoEH#NOQ(3Y{em50+~1evSuJH{GN|MKlCC;{-D<9Eu*-BFzCkZ+=3OHV zbb}(d(*FQwf1+4R%U7T@sJ107YVf`pBeQONU1g^2dpbHMgMW{%X1;*=*ii`&7U~cm zN>Yyt+)WxF5tLaIOy^*J@TU!pZ_j((W()Q4b)WswXwzsxt^C4^*AsulqVtmBS?L|` z`CczLgCnYI7@nOS8rmWQy~1=%E{JUf(Aa|!QR9RM9gTuK-FGCd1dV9|+sqK^5o44V z6*CGCFt#{g&zwPR;m;l$L{&KeThjy&T}kgy=FFJ2Y1=f^H}HzxGqmw_(g0uXN83`z zEWkYA_`~pvM!YtA{`>!~=ET*{Z2TVBeyyZ5>&FsU{!ZuKgfI>ViOl!=%edVzicql5 z(s$Oy<3;}rHcH!n9*)-Yb$RkQKy5$%$5k^6?$62vSw3}`72o0?WcR?t-Z_q-&#YEe z9l^$jmLLrtruJfL*8t-2v6NafOyy3|>jPim!Fyf7c%G>*-a}7Mj{$oz9bqr#eb|dR zsT0Nz^yD&VmB8{~@OTeA_dg!303S4U2wz!kS5Ml&W5^2rjR^HL(g*ozvC}r0rdH0R z7H*S;bTZ&Bja|*u>4^meK2>{9+_GgB9{IZiOv=^vFH`j}rLKS7m2qHr_?na@>9amK zG3(o%q?Q*WA)m%?&CY)#bgJ|!DaZBbc`)Vi@l`hY?>lAgv?>rTRMSRXI~^hay<4J|gP=25c|o2k1g8WvI*qE}U!iW~b>YGI1WctDl-Vu!LJ^9CwBG#w{m5 z8~zoTbvk7Z)9x&2v$~W;?EmdHo$ez=jO8GoX3^ACsva)s_lz;nM*Q^I-VA;*VuK%c zjMpR>NE3W|@mM;E4+^{vmyjXxrn6~pN>|;uu;Xm_t)C#38$;jnzDn27|5N;gnGsXf zl9Bll+$&*+?!_H~<~F~6rVxO*t;gikw?ZA4QGc}WfeqgmyHP!lfU|o@9j?^uGo;(S zmJ!`o1Lbu+H?>j{W&VD~i$z_-f&SV^?+B$*3Ok5MvXWWZA&WS(bd8RTDrfv2KOgY2 z(eb$k+r7259?e9G9)f=G;V{VOzOS$&z=3_x@k%Vzyw>7# zH5R9JpA6I7erdlXl*dpndgLhfuO$v1LeXs2RWng5YNPy6xq~Z9Kkc1pZMw)K*G@|* zd1*q2+R~ zM%u%dFI72kS*`{`|7B$iQz!Z_X+LJ-c_w5HKBJqv$I0I&F-mhSw6hcZDDY)z-_7!j5vEwKhRd3$cTx*Fc!}tsB@>c zJR&8~lrMfht}C1=ED$&C}yJ7jJaVTO+pJL+(E17 z`aA5r_F8P*-ia=9#g*qKH#RvPd}BC%>4u;sIG47tdq`)4YUB3${zzCInC;ngs0pEYIpy z&x%??agOZRYZxu0-slGe>aQ_BrmVHdHsh7S*K~;8Cd!Bb1O|JbYRxTjex&?;$RYoC zu0@kt2iZORwraJ9`lK*|u?-7GC3hV1UiRXsfbJK-ibzh6kX?^)cd}@1(MLnw#KM#Y zcS*>O1Ka#!9pw@mLa&f|LCB5*ZErsb0CqE{zIV`ooQb81Ibf*_qQFlt11LjXC!9Hq zAaOE{$zXI7D6$`XIEtK&KCRKqD|dN|r^eo%?9Jn7MWS+NrU$Rk5C=LFPLY1U)1fAu zQ1GhdKrKyB^50e#Iym`fpM54zt&Cb7qk)*7az7h~iK>2Br)@M})P|ojM?IhpRdVaN zXP#}Y1-bP&AEC$V59oW&3_M6XiTnDDiVcWt(d19?Pyf6fQ;*w2vMnlf>~QW(pS}ol zS%~c!!P(0@EChGhTi*fhYtyfQ70*iM#bBgu^S6%3#c9z)FkQFhk8!1*@hMEzgE_8RsM~^%582bUGw6qEq!7$M z1Ea!Y1UBj!xRkG8G?MWq%;V%V*WT&W?$F;xSM2O^*k1*|AD6A98LkdG>J0yW%tn-7 zP29hG*YFJ&tq2t&kB!vn)!6gruQcv3+SA9=%j|4asPXs@ury7}bMK;H?6L|ans@r? z-an57>I*4e4F90p0sO-TdDcjc7dFZx#xA5#QCQt`;BR|Lw4O>rjf}(s{G|hpRj1p6 zncQ%vk$l@fL|o~q-P$cHk^hV_wu+?G+eRwSg45-d&j}kF`MB)i;l2FJUMuA0Cz{wMILCEu-UqD^EF!GGw^$@o6B^@ zhl?Bl74}aNj2KacP>26fCrL!0!t9;?zIX&k9K6 z4yTB3b)%eRAESSy;-1JVu`BXR)v($aNKZA43rB{igoYiBR!)e@O}8vAdTB5P{#B^8 za5w{RY-%!EwkMnI(@-3~!j+2ut5567^l;Pu^ql|6;{ay>3G9UEgA%T0Jk^~-b3Buk ze-%NMxmI1(da%n$Azp<uMg|!N=Ag{%|&zU-$&)W60aYA18>&+gQ`N0So(N%@o`NJBf zq|u2*6|jXo46gV_{Z)SX59jvx)lm2!me{?&YFm2Je@j1E>o2I_UE(ueozfkO zPQZ+}b3|1V4IYC@iQ4L!c=S5fC&0hu#{Rm(v(lebqOC$oQNsC}rM- zxeJIlqz|S7)FMTr`WrIfy_VhW`mlw;64|I|t(^C0lsCF&Bm3;0i@V^ng81K6%nv`x zTJtu-u-0mK6kt;HRV8E-~oeZ3N1RQP<6-L=+ zOQ>+AFLCAGF$va_F^7l;A#A$vjozPoGwF~L6FNE$cqaestODiF%{$ugy9)X!+S`?y zwq6#jCh_}{=iJHH1c+;(-!NDDN;g=3iT7ZVP@-8E^cGv|y-ipU96FbOG@+1da*+j= z-dBcJi+EFfja$sM<50r63jM9B0&+6{^M0-2qeRGwP8izt;prSd62bl2WL`?bDQEDZ#O( zpvM`Q2|mI_-hDiMHkF+xwT;3TaT|e5(k)jj(~;GHa6Kq~1{ZxEcQK5G)2RV2J5CtR z5Kw3K1Jt=%9;Mu0bWCUXdwpo+Y%w|4zv)2>_tDDqvtS?8)4vqdLjWCv@J)|yP8wre zAZr&4MyV+dU4IQlwf@O1%27n~e~BiuP9an>gb|$tS)DN}aeP(4!2s1xWBP7jQ^a-!szRvm;$46o`R*_-q z|5~?oF^MWq1Le;X3tnS`N(V=8Eswu3Y5S>5^VjEzabctbNvyzLlHT=ekG(t!{Ps#G zf-hXAzkaDcU(AYT>e|x7vW1r{djLL^CN+QtsoZd_Y!nu94x{5Npo z%3G$I3A3=U&%kG_=NxHK@lR@5(zD@x!O{@v<&Dn}P1Ei+)=;DXICBdKe&nUTii$R( z&K%dyG$mOpqYk>XB7MU_Q#~7$Q_h-C`@>8}M?T*ZG}zNno?NeOiS-b;hn(h~`egis z+VKQ>8#e+|F`qdxm{D`due_#}aG=3A3T3^Vtk0dDvLzD7c^)^|J$4;%8ng58f;-Oj zXjC;Y&ar$*)P$GtJ?se$b6T&-TvUJR3L*b8WbhBC&_hn`Hn?=3+1O(m&v$%M=EHFNhh#aOJAVH^p3=lAKj6uDH;+2L;~=A`hgt!Hg#oS zWYSFP-!KNeIhOm)?*XuJ%<_XMjX+*5XxEJ#Spa(n`A1u*x%_z_aAj8;mT=ghRr+O)gmB%WBS#7)MR3c6C=ZQc6#E#x2adFyKD zF8VYq&tIy!ZzZ5aQBui37;$o1v{!@palI$? z&q^SDqKrBpV_ph(u-BZ$no&M=&s*QF@ULI=eX;pa>W54t!_}PZ!WVeSnSIy~8D2PM z&yy)>SOD|#0g7;jEY>s~AJ`_BZaXUeQ&dqm=h)SF^55L#pwnjqPiOp?Gm%Qu5X!cGpSr4C2{_{Gzy+eyw;xFG}B}Ft=8GhlV zP2Xvw1Qh@BCwgT-P~AxS22+2hP#WpC_?ZVf!aKJ}o^hIzDXSeKYL-=CZ|U97a4m+* z$>I4_FVfz0t3Si|+0VR(l)E6$UrDK5cVbtb2mk3jf1RkAyentj_>JRuoGc zD+TqQ5>q2+{$?fJu4ZknC%@O(rpLf~*Pk16XF8&-A{lcn#LT{jDLpM8-Tmg|CDq(R zEUf>K_4g?C_NyiBzwo4p>5!$8UW7Y<5Y2MQ4LeRv;)+w2LSwIO;gs&*_)nKHdGJ|x zO534V)Pcc#?7--Ye(t9^t`Z*g$uKVP)IR>eX`8`IW+MIiC8@#ppG+OOVRI&I>uCu^ z{gCC++9**8#e(A>MvC&n%(7xOgv5&2F}Fyn#h*KV#X{VuI?X-VqIw_xNvb8<#kqfz z;&yS{HD_Umd)Ws1p|KZSNVkulqp5VJPl`4PBDHr}(_40`Sns^??a{T-Ym@8Vh>PD2 z+Db^`h4Q0patO6!3(3oqDTqxqeU*lf6OTK)2|R6{|B5Ak-u^0cp|Lu&S6+#g+P*yr zc)b2-?TMG3=DuRJ#a9M!1*cZcVEor-g+H{Ug77YzZ;y2}Dss;&mFypTd;aNzH*YL$ zu1X*|7P?tSv>a6LQs^gynG4fLkPeY1K)&T3A6j}8^(k! zd*3abzC1&|5XTX&4yBIHcpm%aW}&K;qx?z28qq&A#(tF|w7j5Be{AwC ztgYi?=i2D_>uiqPU}EZxO#uZ=wW~WQ*14*T-$KQ8=%O}e7g1PAHP_4*rsNJ6{kRghm;*Cp7s5lw=>*eDxAYA|zHEqD zLuXHV8b~vOsp-u=#l9v|WuFb+O$drH1`mQ@B%!#?WQD()ZhC9#MG@yWX5`)UA&ae? z&fMAWxFNrj zjBe?*Q4GL&Zflmu4-J`$)jJkD<7?*ZER>>sq)Gyug~B%gYju#Z>*WhyNzhV1skWFD zj`(=Uf`bCWk*Q0CXujC$Uc)clqzm^pDQ2Q%r7cKSrNIk_$zB(SLPMi+sfw1M@)^G9mC+J1be-}~6QxNiX+0T|q+r~e$N zmzsi@5^HZhaD-jdXpKS`Y#`gd)SkWcX~XQ=QkEcNh5F+JD#L2w_PCMBeqy<+TzPXq z@_`PFbC}l!vDGj9y=rSRKRtYn$;*46lGg9DG-I@1*SDd5 zC@Taza`0`C)%|n!jNYWBx6t)fM21ZFQpC=3E5WXaLxh>>_zv_r%z@K|1J~mO@9g$X z?P)?hi`L7V&i1;OizZza+CLbaTRow(J=cr(!*V+zOlarxou%v3^~B1+6l}1-9&fn2 zrbMuI-nXy}z_hI{l2LY0Mn@3;#2)a?*JDI|iQW)$S0-g`5K zDy04cq@L$Mx;m(Rf+sHCsk$J2y`-5IMR^U(J{5@Hf)wGXWz~De7$%a^2Pn*<^RppC zM+kF&6f$f9j*U^fhb&k0%vbV9Ie1DZ=~)M*%asV7JFxX9O@aVDjNA4;;$Y5Lc_HOJ zuy2?`a+rgXXstZtn8o}qUup->#*noA`c$5MA36ABj+$;7+RzL4*=?mNY9{rmAEd6b zatD#gwuu@;{bnN1j-d?ifJ5GF>J9!0{aNW*I9q0!Q3yv#c0<)YhQ|+$V}gEC9Xz~P&B^-HqS@zz87n)b(qx&o6}G2t-mPryK^9JShTfcm(HZdPo8@C za(}czZ9u?9uiOclt>^1&nIdZq;P{D>BN$ucNv)G(GtI2-5fs?tRl*+`#AH)1pa!i; zl&dcH_pK*|W6oILKad5{%*>yxjm3)kHbeyv@3u5Dz*4MsTkgCOl?_>8dhkU zV!5UKLq&tiF#+ZNmY~T5d;$1r^%LkU{^4Mu>7`416$kA<(@Z--Zz=U?cPH)Br#`=e z$nejV)Zf|*r(?%2_gp)v7ejv2GiWo~C2m$UdKE${SkG&mGnut`n&z)+(Xu}$#A~DA zX@;gl74Z8jDX!r8(tBvGvkj#=!&^!ja&d#sx2;yvx}?A_G{Wy?q(bE&qp;JBYt1VR z5X45~d|QI=3G9BmA|P=UpsJ1oPoGO~jY#+bomZK6Wv+EaycBFdgS_+mvJ4B8+W?v7 zM-(NH@I}!6e88}ibhndq(i)5kC%6+-GeCu}2^thboIt<|&$mK#q3opuSEU4tW&9JPq<|xp!>I5+e&Zq_ z;tsxE1GZj;&ak3TK<5$2qCCOo2kI=}szSp$^9&`FHjM=CV|VnA+ei#@PS=3n1g!ok zv%o^a9R0FHV#GZkniqVZCVmn8a~KpJ@46Wed9)4DB z*jK_k)^6WDo+a8CK;MhH9&2|&AooEuYp>Z(+b;(PF2{P@n8~*MJn~)a@qYJNE`6!c z7$O?f%{|?#wZZJX&2Qm>rlBJ@H~E|gx5&)v%9O3QZ_QxJjdf0*-mB*%{IPsREI7OSe;k_PO+E(Z$S%s2Ubry6*Id5?!gA6W5EP z6^GRw9nwEFWK)?$+NECYwP$4ALt!p0GwA*@*~}iW3%7#`MD}WYH2Rahc(LD2R0YU|f zcC+UiZcmVOKB6-pfxl5}GsWEAaEJA)~g&;W%85N`!RWvllEJ5>kF2FleLZ8yl; zF!bZUzDS=l13X1#-*@Y_K z!dX}0cRiv4m4ke>lc+O-C0{!5x&f6)L)`}r<9)aA58ogixkWJi#d$y@7`AirH2Ih7 z0wsD;mAy9Z3zxsFu5w$w2x0*Cl^cs>gx%vFk5UMSJXNkTs^0vO@XfB<8Hgkj#oVpC zZ*_AFrAh|o?o>1Rce?*@l8??tTz;0^D`&FaVjJ*r>+c`4OxErb*kgZu^v+3N-TYW> zBg?hU{Q0AP;A=NFai^=y?0x5 zEExF7{QkK{2v?oge*@~Ujgt=6p0 zV*?M*zFUzRSqK+QPBH!;*4{g+sjgl7wId=RpdwNtf}kixigcnB0ck2K3PM0YP$^PF zO_Yw5C=!&ytpA{eamXX%iCzgQH6$7Yo4*mGDI7(kMjFqLXl#HS`h~g-iI1 z59MgEGQ;9vH5SQNceMW<+^q{rqvqrwCpJuK@TfHk(yntyHdANAD`fE}r^yvYkPxE< zG|7?l^1@;x=tt=)@{|Vm7^aBNk1efv{m5eA>i2^Ks3~uI-K80hT)40BJ_f;c8#R!< z`E7YZipUMO25V}a?=>@X+^XI@T5Ta*R)T6o_H5{f;l~dp!K-^&FTS0kZaYy5j?4+Z zJ^2JwZ{0!@E{1$#9h$)9!zC1`)!S6RmrI}(2#J}-Y>$s*5FhPn+40hgxBm_+VwEHG z_6LD%S4QW_D1>mW!Il|xp1Rb~*gPbw2y7wZ<-)+OlwcQ;vFl{T1H#ew(e47-q8Lu^ z`yoBXJ<)vwk3KY9(nWfkpWH6Y0G2J5JH;2a^eovaYJu&Y`a8IHu~`1-QV%RDjr8-F(C}g$8nO8&IlW z@|byJ{tiB3vc-6|aPSKBro_~Py1i~6IBI!n96JsKH9WOCfM4P6%@?(s9Bw&m`837h zEwZrX`^=ahsh%5~A{!L-N{Us3YK)ETO@z)+kg$wQ!o^F?^<6sjNQXT8U2A9iCV`CE zyWS>zzN99qI@y&oamFENe0Q)F!7bE`(?H+=p7O;x9+o_Y^TCa->`fuq>P!V(Z%$Sc zOiN^4-n5zIU8h4It7I3F^^KaWKGe_l{IaFbUE7j1sISh*cYL|i{Ry{M=we|DGKE&X zRNxbb#>i$y#lI+Kl=!l^KQuA}D=YZ3$`NoUBBXj2QiLZ|1yz@T`$McYCPm;oj9w?& z!nqTxJ}rvozm!fjZES1bGCWwuvau|&sMdYNS}K(kXrV;*{Crl4g10X1Q~U*nPaK<^ zg10V%)9&xp4LF&UE=i?~TzbQtvESnE^JhP4(_%Ug_nc6@=1re)Do27}3VcE#))9-{ zvXa=s8=ge^)m6cn`5D8)J*bov!045`xhJ#Jjh6G9Ay@ zFKA$f<8 z5dmgyd@41=*vw2sDZ5O@An9nq=HA7LS0RdxHUmtcV6Chv)a7e2M_dMZ`#}(xpj^A0f!s+IYCr~t<*rBPZrqH z4i?}|h(Pm)F?DxvEe}R--;8QSUpy1~G{}3)qB3Qha3hk^9sKB#&;ZR_hY;&#V6fi* zweX-ROnv##g*El7?M1+MP6EU2=aKW@wYH)%2S|~IkVzw;HF9gYkCWkuEJsK z>30* zdtXanZpz3i50e&v1^#FxTP9ub^WDcK@WzYq;G%jD*o8!s$y3GQo z>7iMlXM4xy%9K?Vk8AiVxZYh(*jC|4>-fW(`~1E#0c;u3-vV*hkN(s)w^!gwN_QSy z(~yjc*_`>L@2=zdXdiPk2~lfUDqU~1wDUb3rmdA0Oz>PV(T9np-l|=dT z%;853l>U=aP;%c(zwJh)*VmM^>Zs~ZdRH(*dp0S7o42+w^m6!7%l8a| z11@TDU45S^Ek(BjW{Xn1V^fr;Zu=k#sQLR72q(LtKa_q|O;3W!@Q3+%2UVU0_NKoQ zx%%jl1~uWpRNiucx41VRUP*)R!Ea*<^BNCl1k=@HSal~@k6hu^^Yy`u=##$_2qZEz zoh1;0C4Inma-bOXe6*1Vq-sg4Anhh5vr>+s?$jvR&0?y;StA1^>7S)k%zk=Ud?R<$ zwB#Hp9~R}z_X&K~JI?rgICb6~6IW4UM+FJ%_M#XBmrWX?dBz~&3 zK1{9V&ycyM{N#tN;x8pTR*#qKQwuB1i??t46t))19z1SIFJMs-+%w#SqBfot{XH`G zMzWrzINVU+lU|_BXxY?quAtTlH`0>9LSmk5kH+d6uVpHmo_bY&;;x;cdcjSiG8C1e z5y+z^htY9j9@En?S2z-rv*TCFK4=OFetwclT6>8^t&5&MZPkLS+}_3|pZUa4XRwiwn{#0 zIy`voik2F+aJ-NTRhlNhkupxz+%sZw+Mt(vRYR|<7#YF!k^+12ctV}^!|2A6k%m){ z|K;qxcUj#~!Ql~QwiSzeLpc_fkJcaR0cCGeNk}oHd#5X|r}wI<%^^)$X{|`l+gChe z6#{PD7K%2?QuQj!=b5aJkO33tI?8J=p^jQBjd5i)dSbz8cd&R*`6vdT0BwYaCMoKP7AD-f zgZu*D@4~46z67t*19y^9=T+H^fYsIeQ;hqpC+x%AOWaXV_cDe%doqR5I|bMLNUslO zLSK%$pVuZmDI+e96|lc-vbd*o-#c)h;-301^u;$+;T$mU%!uq&?pOq(58+8qG>MJ) zMgXmVA8^e&(RjV;h?2ZBoz^JkerZPBM+kV*4YWe*1xkez-t+b0Tt;BX(7|te38N)28E1^!tC0RzVCj4R~*tyPb{^L-+JuPzqdD zaT#C32s=smN%cZn?16kOe4b$6jRZUHpU9W{*$}thr#=C>Np#&Kd|NugvahT^g6M}V zRiGq$e)BkLX-zpb#%2mIHc`&x>SB1EFv}ZX!q57hL?CVJ zTY!NH4Ue+$r7z+iz6#{tS2Z zJIqNKOW_@JV!PLN)hPx3`!VafBO7ctU6b?eqvvlrK2ZnPd$ zy6x4EM%Wydz)4KKHCbHfk#=;xsAX9%*cgyMlLl#u%p{Ck7)G6NfQACQh3>^HEuQ1cg(l=G{~B97k`&g zpK!~@mq*&<3ohlvjdxpJtERk@hw}FJ@Lj+IVZ_SWGoGABwC;1|)E*RQ^^zl*I@K56 zxk)O4K)cg4j}G~mkbhb+b6Hy+jhCU<-AbEci>p8t^MxPmQ5;DrcE_v(#zZXg5XDv0 zCla|^Hj{Eb+E<=-LZUF%ceR)7f&R)LH7}c~WA@jx%Br~7M%=|3EMIHM@wG}Uwq9^x z3|66DWoA{Cq%j3Kohcxu*Dc0A{XQq;!6fm&atRr@)H|)`c+4e z@*hJL*y;Y99sOe4YX*1U*Ci}Wnnp0kU!ir@aQLBRba1Pd__4T9wu_8`YNA?%E~ z`x&bB0?z6FR_7H)nl$yxYw*HT11g$o#u4dOrG&u_?f-h<10SvftVIu2^f|iSTe^i< z+aAP|${JXAsHhd<#QaKm%z9kChvglw7hXUij7X_s2)kwoZ@Oo^h_;WMkwgV^i>QGb zh|yern>+QWn!DqVJ1lEnr4)4XDM2Rg?-4FSN*63DuY`XOInaoj{ybOU_IeW_mV%+% zup&t_;@7Fl2>SJ9b;^_$!7y4jiVkIzdx{m;H(vt|wH{q&}gKhiDckr|DRQm{|6 zIz_;930}DSP8~CcBZ=XIMXr%o;*o3H`a9Ip(dzwfKP<*94koc|gozNkR_*(x!y@{_ z+@r{p+)aDNDhY3SP$UuiJ+ znDl_wjBD#6l-$$tJTpkRsmeogR5*rYPobYUcTZ(tH-qny<6w)v;RHnSXhUf>ZNqAW{nHhOU?1REb>ZB~^Yu9+n^{^lIk zKkpjDwD$RWM}kQ#k=H@~J3X{gwIts9gazYI_Lu=y`>5qJ@4$|0$aEq>b; zdA?tw(8<8LVe=wqgTpBm$A%1Nmq*Dd2G~yLi{k^CDd!y$!)!czLfJ$b4rBmA>Z2n= z>f%jR&6Ch>|39@=3o&oZt+}l7t8ZgH6GoR;onwl#^(9NLe57`)om%bg{81?VX1O_( zwhrupVS2Q4H9GJy0+3`i{FpQUk`P6yHK(U)hfhZNhFX8=6qyQK*f;-T$N3{0w}o

fqqLQOldfRyo}^rE`cz6QG|@(Zr-z~tzP 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 w(s!7NDZ(4oOQ>lsDx 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[F8`GMV32wF_jZ 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 Date: Wed, 13 May 2026 20:15:32 +0100 Subject: [PATCH 43/48] fix(salti): fix highlighting in terminal default colour scheme --- salti/src/ui/selection.rs | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/salti/src/ui/selection.rs b/salti/src/ui/selection.rs index 0f9cd9f..043a1c5 100644 --- a/salti/src/ui/selection.rs +++ b/salti/src/ui/selection.rs @@ -1,6 +1,11 @@ use std::ops::Range; -use ratatui::{Frame, layout::Rect, style::Color::Rgb, widgets::Block}; +use ratatui::{ + Frame, + layout::Rect, + style::{Color, Color::Rgb, Style}, + widgets::Block, +}; use crate::{ core::{Viewport, codon::TranslationOverlay, model::AlignmentModel}, @@ -208,18 +213,25 @@ fn interpolate(from: u8, to: u8, alpha: f32) -> u8 { (from + (to - from) * alpha).round().clamp(0.0, 255.0) as u8 } -fn blend_background( - base: ratatui::style::Color, - tint: ratatui::style::Color, - alpha: f32, -) -> ratatui::style::Color { +fn blend_background(base: Color, tint: Color, alpha: f32) -> Option { match (base, tint) { - (Rgb(red, green, blue), Rgb(red_tint, green_tint, blue_tint)) => Rgb( + (Rgb(red, green, blue), Rgb(red_tint, green_tint, blue_tint)) => Some(Rgb( interpolate(red, red_tint, alpha), interpolate(green, green_tint, alpha), interpolate(blue, blue_tint, alpha), - ), - _ => tint, + )), + _ => None, + } +} + +fn shade_selected_cell(cell: &mut ratatui::buffer::Cell, tint: Color, alpha: f32) { + match blend_background(cell.bg, tint, alpha) { + Some(background) => { + cell.set_bg(background); + } + None => { + cell.set_style(Style::new().reversed()); + } } } @@ -252,7 +264,7 @@ fn shader( for y in y_start..y_end { for x in x_start..x_end { if let Some(cell) = buffer.cell_mut((x, y)) { - cell.set_bg(blend_background(cell.bg, tint, alpha)); + shade_selected_cell(cell, tint, alpha); } } } @@ -335,6 +347,7 @@ fn translated_selection_visible_col_range( #[cfg(test)] mod tests { + use super::*; use crate::core::{Viewport, model::AlignmentModel}; From 015214acec19434e0af1aa06d7812c7a552d35a5 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 20:22:11 +0100 Subject: [PATCH 44/48] docs(readme): updates --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5c40c97..31e587b 100644 --- a/README.md +++ b/README.md @@ -193,8 +193,8 @@ I plan to add a help screen in the future for reference in app, but for now here - `Ctrl + Left click` - Select a range of sequences or positions - `Middle click + drag` - Pan. - `m` - Open the minimap -- `t` - Quick translate the current view. -- `Shift+t` - Full translate the current view. +- `t` - Toggle between quick translate of the current view. +- `Shift+t` - Toggle between the original alignment and the reloaded protein alignment. - `Alt+1|2|3` - Change reading frame for translation. ### Command palette @@ -228,7 +228,7 @@ Commands: - `set-consensus-method` - Choose `majority` or `majority-non-gap`. - `set-translation-frame` - Set translation frame (`1`, `2`, or `3`). - `set-theme` - Set active theme (`everforest-dark`, `solarized-light`, `tokyo-night`, or `terminal-default`). -- `set-sequence-type` - Override auto-detection if it fails (`dna`, `aa`, or `full`). +- `set-sequence-type` - Override auto-detection if it fails (`dna`, `protein`, or `full`). - `check-update` - Check for updates and show the latest version. - `quit` - Quit the app. @@ -251,7 +251,7 @@ Two methods are available for consensus calculation: If there is a tie for most common character, one is chosen at random. -Consensus is calculated in the background +The defailt is `majority-non-gap` ### Quick translate vs full translate @@ -283,8 +283,11 @@ Gap filtering changes the visible coordinate space. The ruler still shows absolu hidden columns have been skipped. A single jump is shown with an arrow pointing towards the side that has a jump. Dense regions of skipped columns are shown as a run of `~` characters rather than individual arrows. -Gap filtering and translation cannot be used at the same time. If translation is active, `filter-gaps` will be -rejected. Likewise if a gap filter is active, translation cannot be enabled until the filter is cleared. +Gap filtering and quick translation cannot be used at the same time. If quick translation is active, `filter-gaps` will be +rejected. Likewise if a gap filter is active, quick translation cannot be enabled until the filter is cleared. The full translation +(e.g using `reload-as-protein`) supports column filtering however. + +All column filters are applied after row filters. ### Constant filtering @@ -296,7 +299,7 @@ Like gap filtering - removing columns can change the visible coordinate space - `filter-constant 99` hides columns where 99% of the positions are the same and so on. `filter-constant 0` clears the filter. NOTE: -Gaps and Unknown symbols (`N`/`X`) are not counted when calculating constants +Gaps are ignored when calculating constant fractions, in DNA alignments `N` is also ignored and in protein, `X` is also ignored ### GFF support From 7a7664920f4d6d699db09ad7e6156ea396171b3c Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 20:28:56 +0100 Subject: [PATCH 45/48] docs(changelog): 0.9.0 changelog --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9508cc0..3f9ebc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.0] - 2026-05-13 + +### Added + +- `filter-constant` command to hide highly conserved columns by threshold - ignores gaps and unknown symbols in DNA and protein alignments. +- `reload-as-protein` command and `Shift+T` shortcut to toggle a full protein-translated alignment view alongside the existing quick translation overlay (`t`). +- Experimental GFF3 annotation support via `load-gff`, including a global feature pane and a local feature track above the alignment. + - This is only visible if a GFF is loaded +- `jump-feature` command to jump to named features from a loaded GFF file. + +### Changed + +- Translation handling is now split more cleanly between quick overlay translation and full protein reload, with reading frame changes updating both modes correctly. +- Sequence type detection is now deterministic. +- Significant under-the-hood performance improvements in `libmsa`, including faster translation +- Refactored the UI into panes and layers to simplify, and migrated them so each component implements the ratatui widget trait +- Some UI changes to make the interface a bit sleeker - dropping obvious titles in panes etc + +### Fixed + +- Mouse selection highlighting in the `terminal-default` theme using background colour making selection unusable. +- Ruler rendering bugs that could happen with filtered columns. + ## [0.8.0] - 2026-02-26 ### Added From 15e53fc665ccea3fa73b1ab7144e01f74da780b5 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 20:29:27 +0100 Subject: [PATCH 46/48] docs(changelog): full stops :) --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f9ebc6..b15e691 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,16 +12,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `filter-constant` command to hide highly conserved columns by threshold - ignores gaps and unknown symbols in DNA and protein alignments. - `reload-as-protein` command and `Shift+T` shortcut to toggle a full protein-translated alignment view alongside the existing quick translation overlay (`t`). - Experimental GFF3 annotation support via `load-gff`, including a global feature pane and a local feature track above the alignment. - - This is only visible if a GFF is loaded + - This is only visible if a GFF is loaded. - `jump-feature` command to jump to named features from a loaded GFF file. ### Changed - Translation handling is now split more cleanly between quick overlay translation and full protein reload, with reading frame changes updating both modes correctly. - Sequence type detection is now deterministic. -- Significant under-the-hood performance improvements in `libmsa`, including faster translation -- Refactored the UI into panes and layers to simplify, and migrated them so each component implements the ratatui widget trait -- Some UI changes to make the interface a bit sleeker - dropping obvious titles in panes etc +- Significant under-the-hood performance improvements in `libmsa`, including faster translation. +- Refactored the UI into panes and layers to simplify, and migrated them so each component implements the ratatui widget trait. +- Some UI changes to make the interface a bit sleeker - dropping obvious titles in panes etc. ### Fixed From 3406d077be2eb01f7a4ef8ff63b06f7593003fac Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 20:38:38 +0100 Subject: [PATCH 47/48] docs: clarity --- CHANGELOG.md | 16 ++++++++++++---- README.md | 29 +++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b15e691..791f9b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `filter-constant` command to hide highly conserved columns by threshold - ignores gaps and unknown symbols in DNA and protein alignments. - `reload-as-protein` command and `Shift+T` shortcut to toggle a full protein-translated alignment view alongside the existing quick translation overlay (`t`). -- Experimental GFF3 annotation support via `load-gff`, including a global feature pane and a local feature track above the alignment. - - This is only visible if a GFF is loaded. -- `jump-feature` command to jump to named features from a loaded GFF file. +- Keyboard shortcuts for translation frame selection: `Alt+1`, `Alt+2`, and `Alt+3`. +- Experimental GFF3 annotation support via `load-gff`, including: + - a global feature minimap + - a local feature track above the alignment + - hoverable feature details in the `Feature Info` pane + - mouse drag panning in the GFF pane + - `jump-feature` command to jump to named features from a loaded GFF file + - GFF annotations follow the current coordinate mode: + - in quick translation they remain in nucleotide space + - in reloaded protein mode they are projected into protein columns using the active reading frame + - when columns are filtered, features collapse to the remaining visible columns and may disappear entirely if fully filtered out ### Changed @@ -26,7 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Mouse selection highlighting in the `terminal-default` theme using background colour making selection unusable. -- Ruler rendering bugs that could happen with filtered columns. +- Ruler rendering bugs that could happen with filtered columns and translated views. ## [0.8.0] - 2026-02-26 diff --git a/README.md b/README.md index 31e587b..28642b0 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ I plan to add a help screen in the future for reference in app, but for now here - `m` - Open the minimap - `t` - Toggle between quick translate of the current view. - `Shift+t` - Toggle between the original alignment and the reloaded protein alignment. -- `Alt+1|2|3` - Change reading frame for translation. +- `Alt+1|2|3` - Change reading frame for quick/full translation. ### Command palette @@ -221,14 +221,14 @@ Commands: - `clear-filter` - Clear the active filter. - `set-reference` - Set a reference sequence . - `toggle-translate` - Toggle AA translation. -- `reload-as-protein` - Reloads the entire alignment as a protien alignment. +- `reload-as-protein` - Reloads the entire alignment as a protein alignment. - `set-diff-mode` - Set diff rendering mode (`off`, `reference`, or `consensus`). - `load-alignment` (alias: `load`) - Load an alignment file. -- `load-gff` - Load an GFF3 annotation file. +- `load-gff` - Load a GFF3 annotation file. - `set-consensus-method` - Choose `majority` or `majority-non-gap`. - `set-translation-frame` - Set translation frame (`1`, `2`, or `3`). - `set-theme` - Set active theme (`everforest-dark`, `solarized-light`, `tokyo-night`, or `terminal-default`). -- `set-sequence-type` - Override auto-detection if it fails (`dna`, `protein`, or `full`). +- `set-sequence-type` - Override auto-detection if it fails (`dna`, `protein`, or `generic`). - `check-update` - Check for updates and show the latest version. - `quit` - Quit the app. @@ -305,13 +305,30 @@ Gaps are ignored when calculating constant fractions, in DNA alignments `N` is a `salti` can load and display GFF3 annotations from a file with the `load-gff` command. This is currently experimental. +At the moment only `gene` features are supported. + +When a GFF is loaded `salti` will show: +- a global feature pane +- a local feature track above the alignment +- feature details in the `Feature Info` pane when you hover over a feature +- support for the `jump-feature` command in the command palette + +You can also drag in the global feature pane to pan around the alignment. + Currently annotations are treated as "global" - and per sequence annotations are not supported. This also means there is no fancy business that tries to match GFF coordinates to gaps etc. This is mainly useful in specific use cases e.g: When you have multiple alignments to a reference sequence where that reference does not have gaps inserted (i.e insertions are ignored). -For example running mafft something like `mafft --add --keeplength` or using alignments from [nextclade](https://github.com/nextstrain/nextclade) +For example running mafft with something like `mafft --add --keeplength` or using alignments from something like [nextclade](https://github.com/nextstrain/nextclade) or [fastalign](https://github.com/Sam-Sims/fastalign). +In the normal nucleotide view, GFF coordinates are shown in nucleotide space. +Quick translate keeps this the same - because quick translate is just an amino acid overlay on top of the nucleotide view. +In full translate / `reload-as-protein`, the features are projected into protein columns using the active reading frame. + +If columns are filtered, features are projected onto the remaining visible columns. This means a feature can look compressed, or disappear entirely if all +of its columns are filtered out. + ### Pinned behaviour - Pinned sequences stay visible and remain at the top, even when they do not match the active filter. @@ -322,7 +339,7 @@ or [fastalign](https://github.com/Sam-Sims/fastalign). - Input must be FASTA with equal sequence lengths across records. - Sequence type is auto-detected on load; you can override it if its wrong. - It samples up to 100 random alignments and compares NT and AA character fractions. If neither crosses 50%, it - falls back to `full` mode. + falls back to `generic` mode. ### Update check: From 0c8e2a18f9c889e367b058a916c732b726a16b90 Mon Sep 17 00:00:00 2001 From: Sam Sims Date: Wed, 13 May 2026 20:45:16 +0100 Subject: [PATCH 48/48] chore: add gff gif --- README.md | 8 ++++++++ assets/gff.gif | Bin 0 -> 834589 bytes tapes/gff.tape | 16 ++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 assets/gff.gif create mode 100644 tapes/gff.tape diff --git a/README.md b/README.md index 28642b0..bca9ace 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,14 @@ dedicated translation tool. ![viz](assets/viz.gif) +### GFF support + +Support for loading GFF3 annotations with a global minimap + local feature track, and jump straight to features with `jump-feature`. + +See [### GFF support](GFF support) for more detail. + +![gff](assets/gff.gif) + ### Themes `salti` supports multiple colour themes, which can be switched with the `set-theme` command. Available themes so far diff --git a/assets/gff.gif b/assets/gff.gif new file mode 100644 index 0000000000000000000000000000000000000000..e84e6f1b15c6359cb7e177ef8682ce81fd82bbd2 GIT binary patch literal 834589 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]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 z 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≧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

n*JmWjlB+Rke=K?V%K=eZ)dK3_x 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

~H4OsxB<{mt}942%=<%#Sry zdKVH+&cXn|I@S8Y2oTdDfF5TM+?@u&08tLAJk2j63&Z2#*4gnfh4CAAa_{$%rv|-EKt8;F){SQWYk{x-H z?R6%0wT!FC_2Rv+=J(IdyBYrY!Rt}8K2Ch@9Y(0)EY=lIy0HdCZ@c`+1XwYt!-)Z{+VV`u~`?;02RtS2$(%wmTK^m zc9bW^qm+%EvwSi3M$KuU-Si-IBUdCu%yro6R+i;7M2UHdbHmbl8lq1f(_ysFVmo4f z^RsbSHdSL4OeDZp9GcjhO4+tv$fu?&Rg1#xS*)cpjXWG+acNkMrCGO0xzZ)aL~DJQ zW@F`^eSSS``;^XdhQMY6elkOgq{{q4t=IwVfq3e=t1O`lES^iV=7wFRK#k+b*Z%+< zFfheKfR%QO^I;{NB&kN>Qqv%%{%QU(0ibcc0xDUty0Cz@G!|2Uo(4?E8HnXe1>@2K;#B>WQsHet<2WeoL!60eX_~;a z(vhpq;`yh|5F%Lg7k~voP9Z>(CTGOHwuyhWt9jybi~7Q)cGacso6BwF?4%(icsgAI zK!XdyRIIYj(O{#2EMKYO2yVCqIbC---I<(~K!9It&eGXUbt1p^F@^aJz>Ic*>>U%R z2Dldq?2CJ1ueM}aud9Rui7%%a9YU?zx&^l2VY^ThtQBe$o{$5N%~^4-cfI=;7E5tp zOJHRVhnUpEWy71uE%50s*rTo{%SFgwi`(NC%oC5Pk!VO*ahZ@kV0Wp^yO5y-A!~qaulHOo;hHAix=pDvs1MDd~1OYTR07ihg@MX3Raj9Zk zy(}0YoTSf40F*po-$srSdH^UKDU<3weN`F7NksbN&gLxD5N9` zlL|S3pCpiC@>DZr%w&E5;5aFx_oNK-MF|0(uFm(jL-6oqJfaX!SBIw;9Pj^HA5@L< zbB6gXQ#3QOe0O1se4^My;fsmcaXF7e0UI;j6=}XlbP}c`qfcjj1Q4iPPD*=q8C9Y)L1@lI>0Jzj$4y(U1X~YVRKi z*L^h1g8{LrZhv(>LOj0clrw1{zyKilFcm?%%6tO&_+pjm zx?O$mebJny4Zz+F38vPA360AB4<0hN0aJ8<*o&8$&_3qx0cNwS*gcYd>$X|l_Cc?j zm2vrgg(@|F+w6yl-rI);dcHrtZe!`TwVBu@9mhU*;5`p~ul)1HGx>S_n^CMl`C%tG zL%jmAFdgWV$FkWmBtHqgiBs%nrYUM?waB*CY-?a-9umEqhKYr39tdd85#1ZfCx)Mvwj>5qvdTKZ(c}LD`YU$F| zw;bha#+=t)7-TjOL>Zl}z{@r(eKyCJElR4`(2`J$&+d=Q`O-FFzXXJnY%**yOAIKG;}oI!{;71KB_HAJJ`IayX$DgBGj;iF4<{s4RmuSh^Ga;R$IM4 z&nlNy@<1YpSNg?$;~>vwwxw^n*{#-UpB)|ao|pOTjgRb3!o+VFf4X?EMO57ruHAbU zDlrAKo%nBb_TY+n!`I`v0Mq&48@d;6uKG4vhrIC&c^ew?t{<=N5ZF1t?@NODhki*g z_M$omb~3r?c24xRiauuA9oBW&QV6o|#)zALK|P0yO?~_5$2wsAW$<1o>~(jy!oilp z7sb}lKEE9$YUq?B?^ntPM+wK^pVncMYXQGP!+s}+oqP^3BRPxT$~YVfJD(5xyB7BE zAdLDi41gli23#~p6Ih=Ju^~dQ5Mg0NcnT3wM5Mb-q`yyOcuHhkAR-?TnO-TjTDz_# zEACExTOA2xUU=;XaL~Hxpe5rltQTr?nDOG9sO+CWPIVUaAUu})sJ*g`gBs3>Iu?oz z|F#xt#r=X89-##a-ko?Ol0d-bHvcFLlW_|B?_Px5LWKM~sn=Prw7S0|QISeQk;;mZ zD*BPCHj!#qA}@qRs;5LEsxnTBzqRNcF@HYlS2)tz`L=GI?aO~`s0RI3c*K1>oT2xK z^Y+Flbux1CN4RiGl(;`8oHL4B@uz~`Pt)&kH%GB!&JpSL2plTfRw&x;djQs~zg$|d z(k=ROShQ10v~y9k%k5~_`_XPsqum#xJ=UW=zeiu8M&nU2UP3Y6iZNI9V|>=5vx;d~ z(-{Ah|NMor+iGJ1?*A8%9TOb;pFcA^^m|MgS9TOLTtF5Yu>g(KkBv~wyh_Q8!eob~ z#6~(>1>OD~kP@5l^mmv|b`*DP#G_0*joai*HPndqpsBpU29Oh)~J82$>v(~m1`|w*IHAq-6^_u%PCW! z;~M_SwYzXw*ZQ@4->-F2uiahG2n4{w+Oh(r&U)3)dVXiQwq+V?WMB_12Y$~z3WL}Y zGW!-1`b^FqtY_S#CiFNZjJ`V?T~8QQJaZsGhx9Whi_Wm7wB>xlxMX4&HqIm>g2Fbk z*A+MaJ#hgZZO=v11VWrlp|ACmmTZ#VTuFKxmh>(qX}Kur{q3Zc`$-?3CVgB;T3t_C z`<}E;O`@QZH-wTm6_dC0lecY>KS?G#I%hgKXF3x8?Pe$M#U>a0J}HuncU=Cr_dR)! z>XhlQoO~pdV#iJWW&^d$Nj{LIzE-DxQ%pJ1hy3u5Kgv!yOG!C*$~=3Q@_QkLgsw2> zFtF>m%wp+`+vt=>SfA&cdSy4zu_)$Ew}p@DquEu{7^Ne`o|j74G+MSth|g9kTp440 zzQK~m!Yjaits+ozp-wLagp`Srdf8}PBx2POCH=b9`nF+#Otj3Kj?4GGUvxyvzPso7 zG{!?b=IgS9cRa79IIe!hQTzFrd_JziU?>LpmZOarHdf1UwD$0eQw46Agn}D0R#WgJ z^l;f$i+#sh7#G#{#P;Y|zl2|R>bmBbpD9Yvu*q6CLe=awkIUV{7ZDP9$mZ~UD&%g0 z`uDYw6fjC5QR8THsz?-NohR=w9Jr@AqXa477bqhH?4!yCeuFT~0OS;wCo&75n2x;Q|9osdT~=?ld~pz^EoV ziHs#+q3SDcL!{>CxMrxXNPt)&e-2sHR5F;fRfvAS+gzz-&hx22GXl_TDnJBClzaS( z6$Z*!&UQ$&XR zoAV{K+8Zmi@&X$43|#%2bpM|2wPyRt1h(Ar3=FLAh%w)9%O3f2xg%4Am)8E>H`{A} zq&yRJzxz*nKzE0E$9_v?k4$Ihgdkr~{f+;m@7DE$9tS;qd)c+)eyQ=9T*s75epmB~ z=h<%Or!2Rx{j^eH*PVL1$NT+VGrVELTUxSjn^!lrK&;%fXvnScaq{FL1$s%rFod`+)R`mOpGXo=vBwO~AW>C`E@r2O#QwMlWR2 zDT8fZQ}g>R6&(*%%os4^&^<~clOOX6Cc7y2j1DbM&VRXctIUd9bwEPxQ(Q&EL?`F_i*0j8XJ0=~iW&0V#(KPTY56wWL@kIR!3^N&WK5BvyD()gX zvfiX_*cx5c11x>e`QJPdm5-R*TX!uZfCvY~K0Ox~V(hKF-9)XuOmw6Yy;r#hC2bw< zA##a6|L0yF1N!6PiL9?`=;g7dJ2?0%X^w2PnV_(#xtnwun1;L-m$f5-yc#oAk;=X%n+}nFG<4}BIem zyT9M>54h*t@ww;qKJWMQ{dmUlgz&Y>_r^SkY0>-fI~=$>Ydx5!@1S&lOHeyJ%(R#ky0Tl0Ju?IeEnKwZ6G01Q9j-E|8U8Pxg{6STam_ zVt-}q@eHORui@*(`pjAJ(>vRhFYYxAU)wk(srfbe<=of$>s%cZ0AY~|R_=^HqVFLe zutWY{D-+{WSp+*v>k)9+ca@sTGx*5lkHv z)Z4az*J);i^6Zp{Q!Mm06X)y4fl9W4-#@sSac=vf7%z?@B2Q{|U09dCj#ZTwqk%zF z-H0qI_mx&(WZY;v0O`WzG9!5h2mah zttXEx1yyM8=y-OT5|t-(jg+XYZp0B}7l^S``hXeep}poTEHyvvo2n+msM+V@84g*L z%G=3I7zN=fja8gCQ93`!g2y9SZ;utEIy*8T5zFt?QmG7RABEKOkBoZxU+Q7aR%AK- zoqQ_Ev$e96NSY+WFaj@m+$*-0)c3FZW8#mYcQ6a8#?Q$$@Sm1BKFJNpuV^X*(Fe*5 zilzt`p}h{vGr{&E4Lh-%IMbLzY>7!ajBxXlOC$&^7z>N81{jzGP*-dyMUdOpW?({M zfr}&22Z~t?Fn$N+jh!gX}LeMoBAmV@@?N5ZNN(?vMzPS2i<72Ye7msP)QTjs9pRO>k3ZQ9=>p zb-<7X64d)HL8c}i<$^#&5?I)Ufl`bC(l(DXU?g&i$sIPh>)$uEb`AiGWb`J5f&_G3 z&RI4T!1iZoL>;h6KF{z>V~AD(DY7dg0;uIZ0p-M=f6di9r2871M{B6Z&|G$J-zZuIO9=0m(OO; z{A!s{+gPOc&jy^{U2Vnf!hT+d*vy0LIV*f#p)g?67ipc}>CvE>1S;{yX}s+s)pe#= z$M~EJ%IZ;n0ZTu#8zp`zhg3TmmUUgi?{HgPpSfMr<-CD}qsQI)zt#S@^SEPC{d&Pf zumua!k9nx`uz(a45-}4eaTaCd4dx5&qI1{4S={fBhF3w&%;Dz-$K?#{eKaW|B9d@( zIm5TNe`_?EK3I7l_Tk+_^sh>8P@rSXur}rt|Ji8>^hQq&--Q6ke;*re`13Y!pxeN8 zs&*k1uO=S2!Qh3IPU)psAZUOzD_%>9Y(}N;8^MSM)4eu{`aB}j2E_eJIULhP^kaEH zI<7j#g4!|h+hj;wcYq&zC>n(5V4cZ;|F6Hc4&vIf5rsfbIvLzR8PWuEZ!)x~jo}c8bZ$g33-lcf2DTM(+3vXh8U05xd*zifhk&fsl z3m0ZFj>Z+q=fi8rumsRd2YBX@j4&^)C{K~;h*R1Alyu;&tUiE>p-ZHAO67{6$aLxU zxZeTfw4FQ&LpovsP<}s|JP1>cVaa_NS*3c!VkJgi=gWkCx@8JlPMkyaG3=U+Hw)}A zl{UfwnZE-D=bo}5yAXaPxX7>**Ilg41S4wbuwV&|PB+hu&V8Es1f@>RKwx9jO{twF zfw5s?-AhVjb?fFt^`yreW%NE2mD_(%A$>&c#*1)d5MzwrmK1~|52xu=*>xcqh@N4U z8Mce<3!rmrzVe|AebWBD7X2m`eGvo;2Jpx-70jtddud+S7FEMwIwg@LX%+spe?1zS-RU1Q4`=u`wVTug1Q+QP8oICu>Ny?q$1m=Y6uD z#8nPFs*Tfi|H!Ikn6A^Mp^Kg8M&1V4mTt+4c!IJ_*|NcN(z`Pq#5kewlA>(m*Y_k` zoB?5uym%<<4Yo+ck7cw=m!6!)*qkQXvrx>ESb^dZ1slR{7r|NPt@mvBc^TQvPT{{I zV>f0`=gL?(m-0S^Ku5{q09^uSFF7+?yil@2ph)j|OG4*Jc61q8AI5W*tW~j`aVb~c zVNS!#M=_-IGm%})C{^MOo&s5kO+dLyR;Asif?cZmc21sIvA*a7Tc7Lpq-(?p6J5!g zxH2@sS4^f;OL6|HmhbKeOUGEa5oAtFo&LHHYtg_3IZv`aB z1w*0xN1e&S@^&I>V)Y7VEd9$=EKZYgev}9HF$(gDY74f;3lbK7+n#1!hE68=rziaq z_+nV-bvtMWNSh3iH=*a3ccY|uE}=2fk&Kl8f0q!r-b~bsIWDpbc`(Z`z(8_R=zNZh zz*+z{35Acv87v#)n#V!iaRzuWcsdsu%!=*kMJCX(8#J{sGWS{yN3$|sSY$jPn3W$w z=d%DCF2_~fV|nj&9r9zOs$$`X}H1Na6yP%tdm{pmG>CD2VrhmOj7k;V38(QV4&)5b|^XT{WvYkOIOO1_bb z82+49Bc$(~=l=OH0AEA@oX?Ms^i_$W*M1>4M}ZK13^4}^W&zOlSMk&HJAwSX+{JTldIy{dvE&K-dKq zI=@0?fE~v62)pC=aHiALYT_OfcsL_oM3)!2$R2jU@t6_(z+HJmdaWR+vpY{Z;4}X+ zfb9TC9pL$|^3m@ZFjkPT$Jf?IdfR3KVp18)$xxABbok*n*}gi7GDho8y`s=-wHb1r zAjH4|Zo3M-0Dbdy!RRu*@yGejPxRggi=0)LQ@HM;&7g`0s-8k+*9DAUwa^K>*aIeP zM1E1g+`4SjG_A^8lnHS88^|K%>w|-{3RHUS57w{~aK^Z#zDb?r#r6-WdLJ8DnItn& zC0tdt`mcGl`hn_|!K&7|s^D)`D|pZrcufKsR3T8^D7z-Fv}R!J`S@5+v$2SH&P0{F z%66a%=VEnjoJyonab&JCx@ax6qWYRwaK9b6Bc!I|ZT0iahhom`)qeKNs)v`pzGey4 z45%lksI9N+u6LQ$T(eVswEPdf0b{QUUI5~i#|6B||2ED2pO8ddSCIKh1rB69K2CQXboJLG zV#ggZ)+tVaR`{mNv5BLx>QRNdqG4SGSih~>B>CO&!M#A&v`Gi9V z9NlHeWXenWRZlh|Kp}dN<$Xxk)u7|HN_094$rEp69TT+Q`896p_6oFTaz9)0uoPjzoH*_BN156R#h0Lbd{VcR2 zw2_G;fY$t%t-mhX8amA{sDg$%k7slas(d(Dzv^}VG0Jmj!h4@Sw@W`y=Wh$kwLU_! z`6sDUN9U^W^yq~hI_oI+__3w>-(eIZ?oU6Z{SkuA(bCOrGjY6cJjf`r-Aebo%hofW z=1U>EH!eoL*z++;-mhTY8yTO!6V?m!ib$ zA5i#<4ukCPmt89O;v7zcPCol!EU1MhKXFv~a7=yEYx7BjTAZ`+d2aO8gNNfU64MU4 z{aJ8}KYgZX8K-2N8r3WOcsYm){L_T!EK@)<7CM1wnW7D6HHtxP5hOsms7sTxiQIZ5 z?ALWDnu2U&8;Kl8CUhHh(9LWBx$fM3j$}kMJumJYABk19pOyb(hv3&`#9`mr=)2py zQdNHiZkTHpNymoHpSeMY`hfP;HO@%M|{vmr?PLbzxiwIYO2RAg_sh<2HZ${?D&P6Wys6so!cq7uaUN zQb1X0+mU}k{1y!P9P=k?Qt1~#;sNwMB@Z-kHtr&;>pDH`8Cb+|gSAp6;laT9b$q@i zb=81Oh}pGPTt~hHSNx@5sBHPZt+_@vBmpE&r}N&HEOV+i))zXj@Hsc*alQ&h1X7`0Jb@1_R>$l)G2%5qu z>Rt%^40id;z!i10_rLgUNPhEJJw#_Z7&n{tE?+T zrum~)3#7xpT}&2u{}{9;_WcqB3X@7S$PrykwN5--?oiQAJkwpIWJCB=_;{|L;#9w@ z)TX`ERd}j0KZZJHbw}An-Id^D4|`v$4YPmhpzw~8uc^K_?VuZ+ zd5Z2q5a^G*36YCcO>ui)WrZ-pawUI|XOoi&maTI!%cYxlilCm8^!$h*LA$(GfI zmalAe;RWWEi|-y4sT|qb3zNCLtYU&I-Ck+vB|h3Oi88%r>YFGn=BW6|{T(QM{BE#R z!pi!q{aK@D?Zf)mdhONf_%BSW%WJRUQ-=6YKOl3cDkmG*;qC1sZG^e>(@z2@l`v(W z!ULFE2~=78y(`A@2uX{pFd{NLj`rw*etvx2sq#s(tgO(}3LKsWZe(1y*-eg<#1wE$ z_L)Wt^uqQ)abOW|2?|&_gaH@x(R?}w2$(h8w2)0!^%lE07C=kjy-vQ!JAp|{*r&X~ zz(+@F&E|)1gwiec+0eP0fG=mZD;aCD!J)ej@trLUelU9`Q$)VuCRoV8en~|7SOag2 zBuaqdy~lPGhYoj18dPA%v$q9K%%1ZK>;pold@#!tA%P33N?73X~ThWx8P7dyTFvrpnT2sMf<;nwX zLbh*aTudRGU6N{mB8vIDR`7_`_KFk~0W=RWihcx9S!oMrrkU%GY~GS}rY@+ukW(1) z!i8x;bwAreX}H6vxgNZ5%J!Q(tX#4}lBkE9LSv6udm=(Weq|0qj()V>RI7_F%NDKz zY;_+y7;_gP^t8~~+V}2PGxC(BHsUj~qXoJXV5J#htdEJy zB+R&v9CFwl#7BBNkLhm6=!KFnb&qnvq*j*sItg*ztw#ZR>nWibEQ31iLQtZsc=A@Y zFFqg}5=>QnWvtzl!zho-nGB1*a>%Dm%}h+ag|Q^`1`s` zJwYm-kMiKox%JoXDX0O~U?f~I4>;~VdM4L-Mz|FZG2UfZ4Ukc*Xfm46DUzSuc$gk3o?OAhUE$Yql=Jjrz_@p6-fyXr_?t3^pWtCdGuOh%y?XUSwKWGAqz-MmD%jGtgVEqTcSib!I)n*(J zM*f_otuY`yq?LYvdd@+#vh&c3*$2Kf7NinIA@3<6LBlfD$w1PXe1L{Mt%_pUT?bOhopj2CcixB=HZh ziQXJCJLD}4(KnlPBEYmOm2QDhoo(1Jn%OJ%7-TsBf}ROAl`x<--R%Q`v~oIeRGAyO zqcEam3Pq)V!)-H^)4@PYkIWZQ+mUbI=g0K!K%!ddj!FPWlY)CzF zVkR9K7Nuar0Moi+m&D=N5O89Ht+4DfJJI$zE^l6e^pRt}$B45ILnCIjLL>0Xtv*rov{IxYpE1ik<{T>64lOKx>P$>*P?;H?HYVa>y-Hy z@(_us^I8+)F)KLHR%lWezKH&yPIgK1F0PY}qIo(N)&*EML|rPod`K+ekbGT(*!U#f ztF_KW(4cSj>b!W+-z5Ce?Td`qogf3s?jaVWZd(Pneyl?|lO1}FB_@`iz~|By4W80O z8tl%7Cr$D{4e61vu_+aD;vkYj>4qzZQ8GxzkAa~NgXJ1ZGR-AeV7ZNFC4mBut~*jB zr^pOG#WUdjP^q7d$XDFMopj*jVG^=~nylqTi*vX^gBVx#SiTIyMO&1i6lqn?=T2XB z3_IwoQRq~ww9zrEJjbuH{HuP<>LEJe%4FDiHp+cHZa>r5J?6Zg_|QX;kzw4aggbO^ zY}ncE{2vT)FjS#i5M+|(8xM-dP%)5MGwO`m~sn^WvK|eZXitcZDycd zL?{T{Ng`_Z-i)SaP-hXlr8wRJd-MMKVgj5h? zS-a%9*CDdg7QwwQ1{j_D-?-BW@{CM}k~fodC7SO*VJ8fr2)L7DTZ{!HNPN_Fa3^zS zX5DaZz0Zp(h*X*#rw!|Vdpy+pTue4DcTGS)^cg-wMraV!IfqKc<6TLp;B_KO22@Vt z)8LWa4G{f|13tj5Tl+tlsm6CU&w;4gQq+OiQUu*|MMw|tUpn}_A<9`B2@!t zR!zKBKe=orSj7LgDW!h5pU7hUZQw^%X8hNS-xW#&_tx(Y@n?>G2PTLAjnfHRiIXF9 z5O><%c-5P4{AY3gTzI2~#~UQP0pM@AsR#c|V1Nd{gV2>>^lEfd5?GBY2oHIx*8mYv zAFiUcQ^TOrA;-KZt9F_&myvUO2%ne2Sn^Tx+@f8G=Ql9uwNd^00&Jb{0gwIogp&D0u;|Up;nnW36@0(C0?^7swbh!To$^CB3VxPO;z}1aT2S< z*-9!0D*<{6ERYo)Z}k(Fi-Otsi6xLWW0kSBKTY*$kn~vzFABDUg=Wf&chG(ZXBob}U9DsajT+YYRf^Gv;(7Dzh_Sg; z2`q(0tg4h-Ox+nNgUFYh%^j3!X7~ewa({@7|ANKtU@UrlNi zFtKnLDn;@Jn5alXe2GW6l2QT&Wr8z~9^p95?yFt+DYX3V*rraME8sr;z^H!3yETc7 zjr`CZ0LG+Id|8xX1yA|rE6Te6)OC+vh~Mp(ts^^{SZ+nRQ!cfUOxI|pAUq$W3+bh6 zb~dLagl+a{zxn>(q-X*thG6lL0D1iYk}^h2*Hyno&{Jl{_r0+!alBKmi>e&6Y8*S) ztUF-FvM!Ok+x&&v7zg5I>PRNGQ)7%7!s1M?C&3)I+Wd04OOAZ}#7?9d0s&K;C4!v< z;Y4>d_ZRi5ipTD{YWgdC87GG~HyqT6C#PQDvnkh{=hM1TUR?LhREY(WVA>m#z%v{% z9#ADj(|4*^&skVE;aCnaglm49Dzi`?vl2e+pVTwpZNRRE1hM1)rN{y)Gb_xP&@sU7 zSSmPxEIh;zfb*mg0MZ2LpQc0XXiz;C543<7vLN~ZM1*qrA@ryu3%-F9Z(>5JbO+Ry zL^&H}#e{3J5FB-n;8w%^BGp6t%*K9#wmSKJnCLG|*ihh&u|WAMIt-Y-@Z&bji>wrF zjVtAMe?#^c1|f5KVJK3%;Ff=~EJhE&x3R!qSU0bXAKjC|jFaGTQ8+x8c7`f5X)_sM z4S^Xq51HhuKT#r|BnU)vRdvU2p%8m8_fcL@Wr_@G2=8?RHS=XF2jGGzm&|; z9Sm9a^>1q4k_;2UvN znTRA35Lwr$#A!3o7tYxLW<2bzYFc78mT_)3Csfx3w&bZfZJX1#qF4@qrx*G4^>H>fC%?`Msn4R^S$OiVo)jNP&*M0K6L$wEkcqJXos8Ng zBVuZzeeUF$KEw-_30#;(gb+=9NEk68&)fR@_s^nyxU7VFn;0J&!Ha>_W8zGf+$NSl zUmoD2IV#~y;vwU~zi?tZ07K29LJ32?L=$H^b{*w8K?2F26)Ytq00tj8L*x(%o*#!* z#tVNwI)^`nwvZB+ z96&qP$&t4Eo4jNne|R#UqFM9B6jj5Xo% zWU{nl%0D_RbvuP^d&69xSVr1ox~3BSaaH-}AiAIhj!@G!YL{v1bR+QeY}#el^q}T+ zHE_oJXmcINt@|Xz9*IwNDtIj#8^d)|@{Tv8zt36%vX`8*`KGe(_R6rdZVErW`BE>a zH-{lV#h*fcEC;=Pa7u--ar^k?ocmb?IhP4lG+4-$FV0Vg3^{jR{w4brQA?}{s|yH`A<`6x5$Y`MKxH#nA#9-$$mXt8p1f!J0YiX5x)j)}Jd zjnwHBM$!orPwR5ad9pHXU8MT4qc_M9xY#utk!*Mbar^ zf+DetE=U#&?M2fkvaTe1S4@5b`LG1XK)ksFF8*oSFMDO8oTQ z7+s6DVb#iQ5m(P62r=7Z8XzGh;vQ$Hj+1%JF)GgYUgcSLUR)P;l^9iu&gOVOaMtva zAxg2qZOq2Q{t!GP?<7_uCap<0rRGX?!S$73`x4%u%B)<1T>PTrT!IeIK#r`3EdLgA zpa>KiYB~NV(~ zauS69w*Fe<&xy;I;dL>vxgX;fDD&g_W!SL1w77wtort6zpDJdb?K+kVfEGe|i@y)Y z5As`bFA__C^xL!e#2=ys$?~-G8Mo;O+WTWY5+9CoirziNCmG)||Af6zic?gtIZK6`x zgaT#6Ol zLu1Sm#J>u-MsFKeB;$uF`y%L7|46SdcoUH$uS+}EwobJ6pn+Z3d3HaRO^M5|xlVfv= z;a77EaZPeE(bG?7fiDXFwHlbZ^ACIXz4P0#+_%{3qBdXDS; zG?HRC<=JY=SREmlAr-%Ww5HTi577&OP#xDH#@x!C!kXFCUl8beEWA? z7az*uf#e&CcLF)C_5q17OYbR*nC!?Q&obuH%GzbGh|B^uhl5SEsnh*WswcShv@VB* z4P>H8X;O%3!N$`2+Jh?j8*SQwcdA@s364(}108U}PE@793adNS!ea7I+nsuP?hwyV zpE_KuwgKyf{A-&ONKBq{tX8z;%qlxo%hGKJ-0mp9uazZ2pQ=4Jw#rm4SA1DmMo+7L zq3+}8R+93h%2~;S8QA066{=V1W&fp=HduQq!edt{ZsBpYDK5Rk{e58a1}@h9*_TGp z=$xiTdH1q*;19LK$hHm7g}EqnPh!bi3Z}9qJdL2@ILeS1wRi4;M5yY$LYv@knlK)< z#ic;(r<+j9M}TpPOnGyZHHNF&>M$?^w_Kl;Is_yHi0Wr6Ywt!8K3Gaz3KmJfo5ex)MJ*QfOr zZ6rVHdG0f>z9o9`US9Ey^{1E6F+WBhipL)8T$9cM3kHzlP}+TK@d7^PC5a+|%Pc{u zI3?K|ilvov4+mO+vTHiOGsI36qVKGA7C(YTN7h=kHxZ(cL2$Z&B+KdrA;;I zsk<-+m@oyv(s_4@w>iMS>O_Nd3TR(2N7_LtUTjYQez1}uu#|6RYo-a7_B$?_-Uo0K z$Q0u-K!%tCLRC=Um>>KgergIIi{c|`RPob#V-)7cR}-O;)#up*KiyWn~+cV?a6PH3({0Ntdv&&p(xY9{1e`jB>>% z_MWdiUZHv%=3x2Mu_F#HNgd7c!N=pa?acUSCj$a4<3*TN=0f?DZ0ANe78-$jY$d3D zq@agrNU@5`{&dF-lyok$&zdH9TkPqI?Fmqp#?3acBxozu;2)D%<8~YoO$HeWJ-+Os zZ6ajfQ2lJI#7asGCj7us;);F0!^=lqr~m+@C$WCA(FTsR>Ee4a!4cRCn^Kg7($d-0i}jYZAeaH2F5y0}K|fcCe50Em zBG}U4lrD?$*#f%zm*e=$?RB&!>AlfCT9=;B)k!khI5X#_+h+o>Qk;1S*A^klu34G; z!kp(W`EhnqSbF@Z0$P_!I@mOtajPW#%p~bm;s>pBm#2NDxyXZ*A9R>Rt=I*jsXp^B z>3NmR1+;p>YoA*gw~L__N?kuw14hEUDT^au9w(sr-0+jO7vNH6;og!WR{mO5j4n@7tDaOyG$>cnZQ{kMv zU(Z?6wWo2WZ&+5TEi1 z$|w+s%a80;PdZ%Y)AutTr%w*e=9Qrpqb5N1rLx^&yOb%n|eCx z<%__7W@~NwH1!{bC15AF2@mYcR0A8%;?FBFrztup0)=VuNGW*HQVRY^d_cXPR#QhD z4SH=>)6``L+c){#Z8pkg;v$ul~E zhtsaDU*yYZdvNae zGhI&AB>2x<=zQXZN6ZVmdWZJDNY#YFKnUx4a%eRzR7+C>^-uz{6dIw4;tCuJtEYwu zC(G0`!z7l%cAafyAId6BL>8BZ|7C}(BO*XP`*qJo=wC88(kfrgL3sj^#(5{4JH<>V zKrOc;eLBU=Lc`U69XT-}W`F2nuTDgb44+uTCA}z;M=Qz;5oI`j)TsC9r{jKe#|7jX zK=M>XGa36S6gx&nU(5!JZ<>f_gQ7VBt4!QdC?>E0B;G)LH-_54qp?gf${v)C4>YFv zo!SJ4kg!XkDLQO~l&-)@EwUU9?8UPfH^5gerRuSe8e2DJnJKb#yf_|w3*g_N9ZiW& z;g0YLQU#o;=+7f*voy@crhiRK`hdRBnax1QZnPO4xJY&8{$YcVOxMSWfZs)7Y%+kS zAz5Egk^l(su_1&4cNfJx=)kvIGI0$&J_T$M0ccUZM4O-}I`DBx>@XduTNDc>;UgJN z+&|FPY-KGvAW5UY0)ZqN)IUZ6XGp&33?L*syLAJ>yPQ+jqnE}zji6^e0-!iLAQml) zq#-LPN_aZpM3o*-kiHrwoHYVQ(!oCyQT!vIOlskEH44XgMK(^NR-+5G+W0 zOB5;_;9Y>nF=gvOZZBkS-`VuKRDx8c1FCpFtzbeUEXTysUHz5#i92W01@fue&|e`-+p#OefK2i!_ZkEd5l0SD#>9w{N6Hq;nt#R1`yi=@q zXeN zL3B;>7PBc9FE=F!w-zKt(3<40N+_nGs z{yYxe_r&b3_&9IRX#-KgP|#U(XrDrPXIm2ES2XxRSNdnDcD!!jf8heaU=f$rw?b~Y`QHjhZ zcuTu#fpVsGb0r=g#yaTnpeg>8Ss1Oc;W5(q&9gLGbB{La{9Vsg?R7N+b8l4HOO&TszXN zWZj~ASLXUgQ?T4)-87kB#*Ys_dkmN8B&#%=R3m57nyub++Wyz9C;KFSt?9+(Ct}r4 z@_=>&l_px+5g+uElxHmg)h**WY+3ZvR|2g$Dux%+o<>){ayVhH| zrfTbJ!Ote|J~KvFAN4qJR>K4uCeFa{tw$8nl(2r?ie!XS6|HgJjpVs#7%Y7XF^ z4cf{#q9~>>*}@4|CDZd{Vs1VTnU#@>kv#lNq?LSYd~0ZacPRZVsa@~DLdVc*`moC! zJB@N{wqsZ^e0WoJxE2&P=g~32cKW$KjIJI2x;ru-d|7mE=`W;rt#_RcFlWpwUKWgLm{K1wu9P%8SlI$Cve!e+!f3?Zy5WjjYr-aTP&K0 zDR~cEd$019E%uxpF*s&uJN7eX{CdVaiSrJrM@P~J$F;Fjo*CmOzfQ=jO`Li@68n5g z|KH?o!AWgf4c&j^M(3w0JSUF+8-v+Sm3tKKc>Te+qPrOzPjqHb#wt`Z@+B zX&`ZC`sqQpFZ#X`wU2Nz{faHFAhAGgDmEtUT`oo9NZoU zFEuOpg7Yo{kQ({;7&T3hneNV*k=mOjNzKW=7@SEL;%*quDi!m{&pFkZIrY6cO{sb9 zWAnOR^LnxK`gI>stdHaKADdT?vL%o4I*d%b7R+K7mOSThH01u`dAq#@s??&xu|-F( zMd#Q>*WyK8uUX-lc~Plk%CTvSV_*EdzWC1&SC5+7)GY?jdZ%E2plt#ICh@tyMDD z+K&}H-CJv|LzUB(y9vld@AWF$x#n}3Q*BbYA?D|`&udKbb4C?y3%=Hh&U#Iuh zhxWdXy!bj=yx!UXyO)0Sv{$wFv4w{--@fgA^Sb%vvte-=_51JG@7u-S|GxOXJM(>S z?>iv90XEuzp5B08-$35qK)u|+eBQuuH}KM%f<~K!)0;xqdF;R@p&s>^jF$ZFC-r?( z`upY(4KqZ-D%}6kP5YsEf=`a8A8rpaqLed|Mwqugo}7SZd${in9qM=xqs-=+i^zQ38%M{u5YK@ z-%fqGo&I?{le?WQy>rWGC+GA|?)9Dg`#Xg%cZxpm6mxe9vygAe*s%?4`RTt8FZ>;2 zVHZPjpF(kqH0+Wlf6eE=^(X#TW&LeG@%J4KH_Z9(g$8bzw9C4Vd56cm$VT_wN58;h z2EOkaXzji<`o}W*_bU|FbmG4{{{P0Axcbw$G3mY8)BonVn0FU;-|#A+xVumB|GH1_ zeIa2xNq`*3_Xrbdbj)wf>(B0IE+AvfA;-b6QYI$fJUL^ZGOeEWH` zOv$6MP*H~ki(3k|#U=#~i&nX6o-YzaPjbK56dpW3lT%>s{@8CIW)Iq5Gxa=rbLRQ8 zKSTH4R+!#B_>(VVN}D-S{KfiJz4Xg#yB)D#C%#YV+7{|xR{r(+_Wmb@HnvBEqSjnu zPVdaVSsGd%y<~RdTgIO!Dz4AG)`rw-oYtFd{70+Kti4wAcp9~KQ{Iy8cu$CkIt=I_P++5365$^X~eL`e_*b=Q-H+GpJFzHC(N z_ud!uT;+aw|9o}F^S$GmlmVgYtbMybe)_%Ks+W97x@HT~ z8++}4!yOjBJn89H&77PGj6V;inJ;!B82Do^fFJt!6*hGuTgxFI}mIj{_4|!c) zs%Z7P`hV3Lm>&i8DXRg1vy87sA>ECLNQo-N*l<#-wL?8J*ebPz&uT`zazLW9` z6>|+6vi-w}Y0CI9EB23QEpzee3%-sg$J2F&_ZW9{-O$Fi2NNuISuhC;d|bST=K}kN zut{hiSiA^12Z_@oQ;_>>@UloTe(jO~75cp1G&Uw1D&>f4`w)-SNBRWrPl)!8C-F6r z1IupCe1*wJw-p}T=aX-c)Pc|zKmTMZ>Qr0JJ?hm!;SYL-Nva8W&@1fvOv%^yNy!w; z{r?s_B8H6+MODEVUU#=U~^)8=M# zeggup#OJfji;J&`sa5Bg1YdqZu*~9>qA%3{Ns_ktuj=3LX>`u3E9+Sg&803ci{9V8 zW_EGx^78qcFKRrBA04}P;q8s5kB5~wBmVC~?FIvJ;VO6_PJBAs1Y83Xhx$RJyt7$# zcrr42LlzF6W*JR}rbiUXNmQm7PZ(!oFS6!QeIE*-9oZSd91utnpMs#`VO|NxC71G( zB%C#M1xR$^4SKSKY@7H2mYlej2%FC}986S0~pn2ON!P#&hD6nzTZ3F5yPX)ige zZzk-JKsR>W0B~VsV!kPaOAuT*H2!vaWkKKEV0<+5Qn#oyB#_==s(Dc3zC z+rqShb69uI6eOwnowGR=SR!0lK(8jtiE*zX>CIL$LfN1UTm4yZods7@V|E_A0oVcFIC_IprrYQj?4qMGCHX)^dM5*IxJQ{d_(ioU8=CYDXA5 zE|VoTb|7W0IRqLLFkGA zLx!Q#J;yg&+73*zY{N9Yz-o2mTlc5O0`!X!zD*I$LQ(kTCr}N+Rnm24Pv*lRg2Eq&_GX2}8Cw!{AQExZ4B-XJ-kcN|_H@v8_M}U*s%1aq z49z);gNW%i(o5`7ER%Jm{OG$VtEvsd_zEEtS+=8NEmh1^Efo1>FvAYBfyhA$YkF1= zm9wiQ8EZb2*QdY-TQ_`lZ`MuqHMe*$5=-kXA~pP9gaB?I)Mt_fH8^-dlf}&8@|l7& zRHgQtrVeJ4+eii1P}#G;G!2iELAujSc-K0tx+)ZH`Sq7n5(}u-5L$SQtJL|NqyjGW zMB1Au-lmN|tegCqpZphuChzj>Zj794JQJ(be%dp;D%p#we$P+-Blos`R08ybMaI(| zwuAZV;D_U>?~r87C{vK{tWpUSxT=<=3o3qL8!;p?M!aFxu$^bP%8~rU>@xc{s39Dc zbM@u5Ip<*`I%2(AW{PSHbT17){qht0BAd^_%VA!2&zJ5(onK!D?=|NIvNAA;X(IF< z$9q@$FBI{?rtm*kM(B1la*PU>-?{)qZmi@FS2y|cj4@LJnazH%)6-d&Ni~vZCjnwO zd^evk(-K!Rp6#Mo3iFj-=?Z#~o+g<7}FNQU9Yj z(=tGnoRN-`jslZsJ(A#ESgsry_A(9ysdR(r2FSpPIvC{DBqYXfxC_-u!z8UVA~=99 zH4@`|M8=>zqDdN24Xf5m$8qsCS{9Zk%ll^&_wT2k+vYC$L9l@bv*596v~hLy?_WV> zrm~2YP#&!>cwP0JRz<* zRO5hsUy968z4Wx{YyaW0;}T#ArnwLLVY&g-L%6yCPtEHI!mXtJY8Y70!TehtP?#sp zyJ$ZpCQ};$aX0O`ICIyTa{uD3d+C+%!Df0ICoi#soG>l-=(a_gCrrB+lvH_d@{~>2 zb9(ou+zwosO00F?sUcF4wTA71`z{$;oAC5S_@buJ-i0zAA?NChv1lK^8=e`1XP7ur zWuIe(J$1{6_x&^<2zBD~MB#jo5{gSjFH!}?bI@w^Q-EwqK43a03&(B}@gy8)@!DZj z0?k0NAzCEQoc8e*fH2NDfd`xLd7qVZsC5-#St74iLfnyP#03doqGNhlB9#DrYWDGI zyKEvYPt#QH6kb1v*>L*7!QOp0JNr&O0yO>3zxGH&^=qGy_+VPy*y*mZGmt^c&Pzv0 z3{@`8mzgDx&p6Zzb5pz>M;$yvsr;{!%!;}u)yq$=WU7-gHaP;PQZJIG?wJO`?HY%D zPpi0bGxsGG?Gd}~4|jP~!_V}>kKqBtX_b<+*8i9m?d#eyREsp~#YqEH5;a55)cWFI z3)LiRx82NrQxJFJgeJtceHz851X|zgx#IK?&{Qna3m|jluqYsc%`00(3?$|;SN>!t z%g`_g&=F!y;5ta6LrA38jz$EUnZhZlKpn10*|TDBCF>lrVmrJ%F7pw3eS}s?)kna? zE9v~W?{Q4$9j8%(9^$Ag0^SRX-8CT)83_p)5SD$hfg((-5RIQY@%ok)ZVWa~Kkf;? zECW>B4?wc05Q>9fkbc{RvB!gBZ&n|_{q}gNrFM1#{pJ%*i<5QkD#%sMv1#29!UARG zXV>A1Y7@rYxIi5eEU=d!%7YGfX6MhslM*0Gn~qO!5AO~NQ)2RCoAT%WK+D82gJ0=s z0k}G~qN>g8E14E&7m+5LPLB`ouMVH3zdVl-q2$fuVeEDh5gr}m1|E}O$G zNHp*+BazQdCFUS=fZbXURF3TSBYKcU`@tzd_9qB|1VCKsTlxe*BWULlG-(7)yW2~I z>6*#rgFLfK&8Y#@Ymynx zA3Nq`IuU1WRA$u(vo?0KmUL0;0*Di3)+xcquFS{2m7ieovA~ zjgRI$TjGeFb2sv}fzCNy%k;=e*Z^U9|n& z4$S)q&D)guhWh%1&G~vi_O*R87j@PzAa36N?ELWqb8+2s(e?AeadQDszW_Pk$Shyy z@ADBOb0@I=vDyoV?)#;c`Tb|)7h^Z?QQ&_}#rKq)U%cJi#Szz{mcFFh)j4WyFJp zb$h999k~(gT;A$9^cP>X=v4bRv*Kg++1??%Cv30o9$SV=tjr!(dQpf-H>q06%lF_0I(!snCO`F{c~(v6G|3|Dlo3b{(6s{=VM<0Y>4!QP zhcF;SfHy$|xSa7Ij0_;B>P8edN_Nl#iWrF$3FGM=5pVdo7a*LPt#3-pPNWh6dPK~K z|F9hWaf;(~ zFlK8>fKlR-O4*R3d~N0YD+B%Towegofbkshh7gH?V0975_cu!-=p}IcGN=u#id(`x z;W#ow1;P&5)&96dt`!Qjoa%UdIy z;8qYpm7|TO==%BC5<~U;X7w2y1Jy8v0ggy;*xuaAzCMUv2mjNS9OmAFw?eo__-xg8 z8s*Dshr)0vVUE-=(%VqAiD1>>RR^Ik#JOb{vJX?Na= zBY;9eN4mUU*;=FX7ig-+OZE~J!_)xB%1lG|B_q{2>G)7lWmr@%!vs&Y=wQT;X9%i+ ze*iAJyNsW#qzlAo*HV!#iqu01gb+M&4ufSpmDwXFAaB}z+7`su~N|~Jh zbLi1+_XP0+{vWHY3k2J_w$$D82*Xc3lG3yXOUMhmBW5B z3bzl~o@(-pJ4`jgGh#TCkagOvTBu|%)mRSiQg`z_?om4OwS?4&a4K;9d3!9ECVpH! zmJ39Yr~$ih7X=owu1O@~_$EVWH zGf4`&2T)1DIlY-)Oggj|fas+P1^_goB3;_RV}+YzFq+-~guvb$SEag2tm?C4$Aba; zaG^HivE${NfddeAwYZ5Nbl3ZtkDkOnHimG0KaLxJHX5g3Q)1^W<7^Q}$pN3I%Ew$N zpn1k7WPA-2oUs^86(5iDhSJ`lkE=^TEB|dmi|D8)ZxU-FM@1~fzQ*|Lq6Kase8rYZk+g9z!eLjzL5X= zO6Ti_`<&BaocYhsQe)dt3SDI2fkzTv(hFZ^`bD)PJRV1Bom;KNB6z%=*N*De~e~MGE!Q73SrJ0)a&;nh4a)dY%xFF@Z(c zBeGAhpiUi-W2V{R3G}j(5wlj^`n^XDqtv__O95QD(5VbsJJe-8GZX=jUFQ?YB?P&& z##{7DR=*~?tVmc<0Z(wOA=`(8N%z+z!9<=*d|2ut;_eY%!Ax)=0%!Z8IJVRQaz5C!aiG4co2;^zV-|+=b zyDp@EDc!{6Z`%#gnH#5{eeoT$I@|IgeNq=P?tixJ;=jfl|9r9_Zx#M_Eu0?K{WCf0 z+j;ZM9feSosf!!`vMrz*;7iV1c2rjzx9W3>@^phU1K)eSxggx!7OFlwB{Wi8P8YCNga^$}uA5 zW~YkX90d=@D+@Fpb7c5ody-h4HJ;YG`}LE56IaN&)J*IAhzYb_TvviE>8rhPm6Y{w z!^88NZ;es@TlZu9+g__Hl&{>6feDFSP)~VEO`FN^yUkx}etwrNEGMTuGr#?Ap?&Gr z@g5vet^VWpn;s3W$0w6FlRie5jsD#jJF#SW`p1@;65xHX#qb(;cl!I*8_RU|TJdcl z{F=o_Hm#x@9%y*{Im_3;b2;!JFZM;(%{MNYV|MasIdZU!oz|imHe( z@*ilm%#@cfQJaB$|=r{Xd!brAd_vxCM^bo3lk5%WrF@@=?oE@0<( z?RRt&;{MAG|J&|7(N8T-bIvoZjh&MkEq7rt2iy8Z_qTN14>X!+XXzYnX=W>4@oVdS zBCUCQ%6_P+{Z+7L%WaOd%jd3Hx7gLxBJ4 zT8HD;2#<}@5HvCnYKyrod?Mhss|l4r#3gR$pK=!JC(ch9#ZWz|K!fM`6Gju2m)wuv z$Wom$AGmgO%CNp8MgH`K^kPT#&1*duE&HJ}SI&G}1up`|MBaZ@*EfY&C0aNsZ;Wy*l2$s)-)oprKbud z4@E3zVV|)w#_B+RRJsl~iB3bvLHhPzd4V9W)OBYLj|uv@Kd=895m0<~pX`)61uj=f zvD%Af@Qz+hL|#6t)xxpRLciGp+nT4_IXy;Z$w(K(#5K2}#@%rQ37T}2FjSppKhYj@0R{ZQgKC&T}tlDus# z2B5^2d>Q&q>qjYcRvo7 zf#6(~&NhsP5>?HgH$F*Ty>;ia?dScq>Tb(E2F{1?*^4zeu4x>;aOLMihs5s}7yulR z{x4$7>dL39w0LDax)%WVAs!P>;J?I;uR$d%Z+sfa20C3G##!&efqR64^SeMWauT4x z82)`L-VafzxcD7LGLsc`kr;S zrQFvH{@S!~f2X_s+&@hUSaWfZA1!4Z&Q5sl( zsz&BKa7;WHke^mmE@{afG`$YyPr)?k!`@hfmf~!27Fqo9IDGc^GEdH&M2jBZgwH!y zLtr^Hu>o$D8kFyCFfELo1H9IC1P8O=?q7RyMh^eb?CLV`Zx%^tsmNYjM-2oK z2g&#IIYYB`1O*ORZW#yD*gMIRSzv?3Ss(RUxB&Mow&3$!hO{i8;mb(l&E;vRMl_#Z zcV~r!1`M09fpcP&)S*#+Ov!2JGgR-jsP5+T=qV3=wppC(dBb(tBim|&{9$Fv6 z75?&D^h>KnABdCHV)v+1im4>w{7|7V$TBFT-~-i|0@6hUSmlXM3%D0$1*Y3L#D&?S zBL31b%lr^jt_XA$1v5HGL7J`DfSS4*(JdsNkdkk9(f(zK+ch?Dm^!AE3DDr{%O$yZ z2uLxXYcyE9zA-KO?1d)~;s}zzH%_YxH>ADV1_7C2X7a%UBMUGQ+CSWCsO;|3JG;UxtGf_3E#F&W>D@HZ69n^ zL3)377O#s)7(DYk==p;R-tGUW+&Jc)4Dk%*b)fWV00ZKyjtq|a?K%W zJK+)E zJET1at-J6qjsmsd11m`|A1W*!aXEr&%HUTs%LF1wlZ{R={!PR8YNb~yN3aD@N8tQE ztTNl%7XV11n)*>+3yqskE*c?ohTepO5|k|EmF6*QrPgTl zxlPX#7$4-vdM(i~{W^^xU0&yOUD>&z&bdw5MY>%2=xC%~hO2%?NUFq>)o1&A!N(ul zgz_lC_}~m<(y;5K@{`P9gDBCZ@eIpUSVGrZ!+WrOmGqM*LB6M#ev)M@xfz!H^3imL zW$*B*^;LKJ+NoYey*L%^XEl~u^(o3?KF%tdKJ~uNm(G+jETiD(FDtlLD|}#u&tBrnno6JB~gS&byfyZ2-y_XqCZRW{TD8z9zP73B@_HU`SW<|H?5-cg6c zKQcZUiS1K9-08IzGre|#1GbESF9AXh1>QV&^w^>JS4oazU+Yy)H+(p49eMW`D1Bgb zpFRBS%9_!PjLGpQ_YZ`dz6dERJNl;&Uv``Y-l%jx007}H{4?WZ#pi%i)Eq)=ZYDKWdBD8w3L}RhMdWmXdiH`auZSILrS9rwevM_p>g7ip%j4B6QW`7HsaG=8E83<~<*$E8yMEc)<|#lCzp{GDw1jZI zk)Ud$FB@sT`}W*i{lU(gL18xx&W2romVJU_V|h>g%7FU&%aKdF!GSvkNtY`Q^LCD_ z`h*#1vzQE-H6noZ7ku84WgzO9g+6kjY297!bwhsBg`V{S>B@-Fg9TMh)NxjJNp#~* zXi{uEv&|s#2BTr$Q{C^ zG$W1wu4>j5Iv7A(*v9@#j{ZxF*?`pXUun@H-s>UHG#=WwWW8iP^lKRjZW)0!vx+9W zQd-9TN8o4~FVvbSZ<)BRb-P6U+UUpS%O5|y(42bz>`v!q_k5$O+rfKu?|zic60E;T{S|2#rnS(t-kzep z$Y@<`@=e%a9oC|&Fk4?XXuoP}ebuA=dZ6|7sP>yDt#9VF-@a{q`(Ar#t99vzHfOJu z1JhYXw=GNPtjM>msOr4aX?tg^vufG4YOk~A-nQna^FFxk{ZX9{$Sp++P=t}&(R`hc zN9~`y25&U9Z8U7HOGkbzj903PxsGi8bZaQ~wa(TP#=CJHHMhe3L>PCa`57$g`A$ro z@xjyS^jT{e?H$Q;v10CewN#PC`NG!k!MZ<=o>)XyQBA4%{2>+UiQV9#U0!+n?seT? zHSNC|bpN!q|7p_w%h$0EwEvyg{rC3E-}mkRHgxy4+Ic^80bknzye|Ma5vb4s+?N2< zC4vk(Kqf?pRR?505$cct_2_^eBf?H_q5pNj&Jf{$+IJ_HrOP`6Zg7nqZICyKrkG)* z3)s|gSl}sq+0dCH+d_XD$_tr)%D$%Qn+x zAAsauZOeYpA1 zH89f#mN&Zt+rJxa81P5@pt0_tr$$E>x{oXw1%K!c{$dpJvpeMcH;p>FvtSD4(Km`x zw?>gQMahUP+!HR@LjfDAUp4gdNWn7=)m>8#igicq>p2$w0UgelahB%DwrhhyOXGE za?0e+DFc)6gGpgGha!#{dwUoshnv{!OG!S~bL`BWs8^abJdM`lRvScG_k%q@TK}gy zq}D0DD_VqugGZz9mz|6|g@8Iz&waTAF$EM&Yd}q@)cx#5Aq3Qr3T92f5T-jxbs$4_ zhJ$Hl-a)EOZZEHh}Nl&{p z5ncH|Pmvy2%L*D6zA`0^ZRf+gE`IIJ7yefGDYbB^SMwf!wEa~gX;$(zRl_vx;=5iF zJna%MHQyzzRKbk&uD8U)tX#0C{GwUKP5MRuzEXp<@(Q!d2hA#L%_^GHDk^?mR{B+u zmsYvZTWr%;zF<}<*muRs?5fPKYmfS_3!2wFFe|#5#^gOUyKy_MWZ3lj^VBO}elc}V zUp4t%z5n<1@V*;Y%r1+WT{G#gaOto1KV6e?y7KU^syy@3^QRj_%<64^*FHF1d;53Y z;nPiHr<+64T0iyI@cLT*n0K7`b?yA`h7-Tq!_BXPPhYR?uRYV>@M!y@M@p^cpZfp$ zv^{<}Kke0!1uM3;VgF-TezWPjakuZv{$JJm?<#!Z3oJiZJu|;~=5EL(0F!j~Qn$sG zWW#s>nn@O8k=bwyY5p+YwJ{w>Lf~oAr9k;qpz!pK?|7O_D!EW4D6*W4K{%pJ?~T11 z9D5F!h#VZ-Zy}#KnAdVufJ&3WlkF275#nSi79WSK3gPXLCf?CxID=S3-S>N>;df+_ zsqox8Mv~E{vYOU%h#{4!T@BYE58{vK3xf(;*4=_b3i(6ccZU>afq2J%io1h~fM1HU zGzC}s^NT~)wm;Q8?-LyR34aHb0cLoue`?~!vr0oH9-z6y_anmpsUeaUz(XY!_mztd z%+=nf)DFFbC%xi9Uh@W3rtiObcXrO@z>@#Ji_K@}1-o8|oy*t!_xh))V&(l6tAEy7 zX|Mha9tL+2X33nfU5;iC#lc$60#x*BPr=surLOHJ_}d5FzIE`gPmk_D_W;>A{!^J6 zR8RwzgZD~!GzA1G{4QO2maL2)*cR-0dHw|H($EKYs=okd=KNJQE!H_}}@Y469YRAqm%Hpy5mQr*8nHyZNprr}G$WtZ8H64ZAjE ziRia%=0ht1mHt2<2X9BaDpWKsVD>kEi*GEMHFoNI4Fn4BF!J+P&*xb~sX zIg+%6nR*?GtRd5rekcLkblK>j)Cy~oiMNuKYAf+M<~8n!Rce)0am1)!sN)~xe2i8f zzUuCEG8r)w_tZ+#AYOLF=z|04tiN_AF0oF5rT5~8o66UVgu90hG9W$R#*OTQ@`}mgS_g4>L)&ZjmG}mIfMyh~=T=LNIwOk=@TeeVY=fv`e zxJfT)LaDL^B%eCFT=Ga~Ikc80f=-Qiq;oOzgRB!8(V3z7#A_c)mG&B+;m28q<_J(M zs6xaUpGy@mN(&Wk`Q$|>M%*3oj5p&zDDd%iG%Je860&!k0ota9f@shU>Q=eA1an1{ z5%epA3aR77m&!;0wE2vTUc4wHewj|yZ*oyt@O{Ky$J&q*LQ6VSeldR*t+?LZ@2& z?jOktT-!-5@IG_Doa%jILjAR%#I3wis05(8Hd!E`mJrgon^cf_@ID8|3Km&?F2e{5 zqcx^OfiywX@u1F23wa>9W4 z6xsd>3ie@}za^f-%V3hwHiu66Y_TJGSeC@q#zhaE$J`EfP-l>8!s_5_*>%6oJn`M!1Ybl>Soz&?nAfmEOmV1e6KZNlx^A^%BkLRr05AtxKpI z8e1H{n1)RAZA@!3SH?uE-1$@~*kA_KG4)f1Vw43wm3W*Fz8kl8K%2DXC0P`f?0aZ! zOEe%ddF@2o`M3rDBVw2qAJn7Rac_y+SD~$R$GkwsT|ZzG5f_rI30$hm>Fru5dfMpX zABKb4$8Wbmcn@Q!jkgyRxhf)Ow_|9$|D_u3h(V#~P^8$x6Yp)}J8WiH?Xd5t>)0); zR8)lGVZemG{@tj?{79XQ%Toz!2d=Csr&8ZteoD0mRBKNkWLj4}tE3{2I1bBgv1h_wKUZ!vc4$g(9yNk3m7 zk^7uF7QC7v3+iAaY;6_AuB|JO!bC6{fLakxyzl}ArssLt+4Wl#YCIiIazxY;>Ji4td1^jvASJ-@nIDGi&sxErBT=DI2_pXaiUPWxwwgZG zNdI0Y7+slhIC!3>&kU>8jbTIT@B;q#tVIkKY3}=W03u0D46Kn3mA}JQ0}yvS zJ)z#Q->|0~snwGoa-GBn>tuZGGz~d4f!S&-7zKvUQ@wpxCxK`dNCOQ=NaBGkMK2P+ zqLLl^ z$nGv+p^#7fNq8)vDBi&b{D73|QitHknF{}DHt1{1lWucvcU9+dlULNHVhRUztw9_s z!P-=q{GF>q;?%1P5umb|m&3ovU~lF}0B@Qq^pGQhB4>$HG>iF^1_j~8mhMFgjp%c% zHPn+0uA$2JZ*p$>l-WY}W`LwpY?@?cMqmZ}4KXJLjZf8V+L)$_l(lQPPLq}r>2$OO zr`}9G0}8vF+nquNqI<2wg_c31Fa3c$5{;njorT6P^jWc}praePhsS}CXWxD4>Rj-( z+$@2j`}zEUQfNkIH7GV}oT0**&qEGDT|5PN4uW1QShXP?e-0pTp`V{JrwAF|pNCt& zdJ&^u+18ejr5ukBx|=`L>uBUCsm1jUI=%+XeO}mST_{Box2~$(6QlZL6d~ zdtW2JoujbBbTYsRO$V=U;o)m}NT|iMzt2fp-@mFTJKex+$*9s=`BswSV^{A>5>@p& zS;wU!oS%1>^KZ-YB#%!rvwtOw_BpsUwU@t~z4?Sto5PR9rWMV#rWn;zKC>ZvF@9a3 zO2N1TT+P+V%>EjQ_S12QkbnFK7g^rHu-nX+e6{Fgk2aHpYXH22;4W9IaUA1xv`3$Ag%Q?;@AhL|wr!-zIe72}oQm@?>!zf~0`QSya zM?ki?p*99H|phrk^ULP>6iY-jA9rJ?bdwi2bTN76k zHqV|a*Y2!x1Bdb1ui7Xb=A(!Cg0=u?3R^e@$^Y|1Y($H^KLPCrCH6&k3Zp=WNDydSNEj1p&RI@y zxr1wihEve#2_mVa-lN>7vcx|9!UH}u$?JgM=ct&7ShVFLuKG@A|x$1)CKd41aOnL&^{&80c0~APw zzGf$Q(ga+Qs-6IJJ859*>F@YzL304~+w?!{*oUUhqVgn+Kj<}J6CS_@SCT}6m$9pW zDc8Ki@>ITiL@3=;^mNNzwKCoL>tsqIS`k)4d76p@1r!t7IN%?T z`cm)`-Jh`oT2u4ULKh^E(Df|!j=2SLlyhDMyUy@q|Dy)*_rv_ykmZjF&FcM9U zbdXfIjB~Co>S2nf4@!zIBOrK;eyDU|sN5>e;5!ZJ3t5jU zJQONjg9qAjs%`PW*A#tWW|^zFtruQ4e-K6_Ny0XuMY{Hp-yBMxGV!?wYw+-LCU}LT zXz=W}ITBP(g;(O|oO37tiXaM^e_EjPVVi3H6ahXNQalls1YpV5fXV@gF#Ox}){q>M zgBK^ter+3;fY!nzqew_hf<^DP$vpnd!km&c3!E4fDks94*l>kVco_3dZu7w-04(SfdS}T0I@8CW z2S# zBZ5dLysLRgOTeS}Wq8sz@WywE6@cW)dh|0x_+sf;00}2J1TJSHJgMqIwDHmzf5$nu zj5P@eS$YOMnOO=?VYYZLclYQ$N}>o@GU3BsDhpJPBTQt9v*@$pW5yI0{_k0REcc^%MiIGRYy;Y5x3 zjBc=9lRLrX6t`F3+#YziANZcY_3=2B1udsS_hzvmtf(aUl#uU;=ywT;ZZ8ERsBjF= zyP^oj0>HF;-k8oEJf-NfM)A4)-N(Vj_XtoVpbQ>l#0e|Q4x{+RBn!pQ=_DH=!#JsS zbht(w%#0dP;M-TJdFVvwA-81IBTsC8sC*9%&`FVhIan|mDm>1X+R0G(QLV5WY84AW zgEFZs-d^{gVgaB-6oFN)gm<#G z93D9YfVMPXuT##vdsgbtZj7B12m$Ig^KVrSPf?i+r+-I&d2!@o@>7HXipms&_V>4a z!XwRt_I(IUi=)2fmL3>C{8>~g^cVc-3(VAaVJ{#k@fSF??+EV`=HF$wV$NZCkwH}s zlFgs^S41zrz&jQTSx~BUT|-S;!2EH#tDxL2Hq3Vhf!Gm7T8EqcfLA3u8>L0Wxk|P( z1;ePS)RU37hQM1dz_75Rd7EL@2q+uC+($lEUo0(1b{v*g8kc4tr9u~}DZXh!30_n4 ze4qzY&>D%knWAsZx&B{T6DRhz#5&TPRM*I9|2QLG?FvK%f&qirC&qF9lhuSklqqxO zXe)>!g^*aro-;bDt6lM**}mO*-ieB_8#K0{&*cPKsgjjhDb`>4-%RNNN{8Q}`QZ0u z?My`c%ks6Sch0}8pb1rGrTOGuu6@s`Jc7Smak<-1va0^FIO|1~Z;4=M+7;e!;mT*~ z75J;QCI2<@MD*M{=8Z$QzaH}W_2Nbzo(ZoaFreMS=GFCp!vg3Y znf>XFxi!rkI8izvs|>s)6=4-PY<;?pC$0B&<=mZ60GlHJcCg?jP_}1T=5>z3?jZH& zJBWCI0;-pmESvEiD7Q`$EG5gQ$Yx+4O5jLPXJBTng~$M2#Cgypq*wYGGs`RBVhtH| zwAXB`@KXGuo$Ul;4$_CSpy+ z%#tNnoa{8H=5lV)x;iylN?#S0eU5w>gyDG7X!Bl~s&qJ^KyZYnd!gTu&n z_t^qh*-%r`Ra>^x6S8y)TcCz5KxZ;3%H!xHu&k85(ys-v=n^BSL-Aw{kS6(_qkz0K zE6zkBX*0p(xu922Kayx7RbcO>Q{xpud8*JN3H+nu=96T_ghQg1OyudlQ#3aSAI*D| zvv_jH_4AalCFzeSMv1N;V71j=tmkp9`Q<7T1IyX3`zQ}YzPDR2F*R&6 zJBcYjA`i%>pe;$Lcmk~KCpd~Ey0M+nPaQnae1hDEP9?lTm?Pz@!RO$9a2*{lk_eRp zmj~V%;=EoY0f*QkCaR)_fdSggXMP+3(<^;|O#wBwa6c2eM`DI>1n^!Mi_I5<+4UpM z(555sc#`Ore%G=7S1$mNZ{8w_%mHr^P|4@uGmnn|U6ICY;U+vBLOZ;L75&6+y?!4R zJlNQXYC2334a48`d!cieeQ$K&pLGl3-fv(&NmTx6LeQ;|y=qJy362U~sgG&h008@` zZ@YEdlwxohMzJ;`!{7RmY9zF~;CKiu0fN?@2!X+mneY0X(db=#*pfK3Gx0 z>--+Ge!R4;*A53zXU&^l2!{65-mh!8|FZqStMJwa0R0izIM#5suRe-_ zc53r(tuh4W)Cv3g^)-bJ3OD*R#$$i^uTP?E?!9NStS9-*(Np3{+h41vTAl2IExh?2 zCkC!0$gwX;6P0Py>etvmGD5qmuZadFdO_xzeA*<;_+8OQO@6-SyUUBk+1b`!DQf-L z4>lEE8X*%-fTL)H-W}zC34@-#PlOGXZxs#oJc63Bg5_GhL(w>i+4~DcOowMlgZm_}iIJ{6p7ee2x@Eu6KTUKMulvo%gft+TFCzFGH8^TvV`1Ta9It_q8inaXBOJY~aW8 zJCgrx{M>J>Eds{Y>mUEUdO^J*p=82vZ1JXtQCZz~-r2vaVg&%TzcvKuew;oqOFEYw zn$1`JL7;NEM7qG)ByfT8Y{IacG2>y!V2=J1Q#u^yT3aYBls^pwowg#O9mGTrl`HtQXv)eo907Pj7`UkX`eE@^2}K~nc##r>7^q@cxul) z-S?l&it)6;rucZDVoi={GkQt3UA{-=CXdu5tYHK0a64$qq3K*<-Q%rUn}o&GBT4G|= zR))mx%#Mo1OH5DaiYo-|98Q?7A9^GvRyheg^7w#BnI_$odlhZa@hORL&~2XH&ITps z;Z!rd;ysZaUI@e!oswbeIHxe6aH}m4bl5k+GrR4MBbiKyP3mCu-tP;_hO9R|(h<{C zOYG59>!3Pgzn6ysWlsLL&F;h}E$jLa+Lb53_CA6jhm1d=yTU@Z$)VQ8Lm`tOmvZ~-ak8o6|X~CXNto;Y15RJDcZ1Bf)Ouq< ztq+Go)ecF?5)FksmnAMP4#rD&=DK+D{Z8P)TfIe?SOxtksj=2L1>2}1)wg2gPrw6hS?^#;4&^IK2$IN_!Lz3VAfdWk4)iA zS7N4K{sbV0UiQnDLi{8Dxaz%B2cI=+4xU%=d6&z%?Al7`GGOG8^EiRFa5%u**JfnqBdU;{e}@y}TX57FNB;C>)%44e5Ko;+E3 znM0B|Yrph|PMVg}biaoTHMYiTs45Ze#HR|Bq~?m_qzwE^$>5=4`mx`V86t)Y&?9`^ zoH=uXDaSt|nb&ZV~mWqx($R!X>>lanEh|hhA5VP%k~nh$-^vZN5@F zM(AAg0#c8q8Xp?PmNq|Dp7a^7+g_A;Esy}mAj$;?kK1V!(tEAd!r-@}-CI!aa;;=} z9Aqnp4nxq8k3tKTs=m%CSaSWsZiR}6ZCZm7N?8hy)*^aD?N73#OurT&r1c+LA=)+hI?d&Gu(h; z=0wY~q2kJ!qtq;|z)_l3R$7`?I8xh`4I97s`2GPn4vzQXJ)Zl%uJZ(}%$B|yaiZt_ zP@7b||H0~C?qdGV;7qR2?&%>Z5YU6#D1VX8Hz57)O#QJ^ycK?kTfT`?kL7m=$#Tb9hL=Ewfl<< z;AFW6D`|~|OTLf0dv>Ou&#cjnzP24K8fB^x`39gM@*E1C5?slYjeO>}sq@;ygF?%G zVy5U|S)ayRQo+;5RFA%Tsr}+QTe>H^H2CW2j`KG>PR;s+g(GJE`m33a_hdAHmKt7G ziLNvHRMq$I@|60Jly*CD$2yVN{AmfhX20gNY^$jf_1g8?h|nDg0}w3&>=LNH2IGe`QNVYze~8!X^-)<+~~%I%UcJiI;Hl;kCO2C%c2 z$&tdEl*5Ug9aR_ReJU$+4kvR}>OnQ_eiY{&&{|iwylFQDSp3~rcxfbp22+1rqVyLa zZCQU5y)-w(b^!%FJ4-#1>0Om*(ho{JJ(l^NT%G)g1N7xGRLqHl?IHVjMaU}v>2~s= z`c~v9Qz`|g+wB{)dp79w91y$}6dn%bMdVlFW1uG;D}5!Du>Qi&4MiQ1`mBTDc%z~; zBe5x{4j0akNcI8lccr4Gl4G9_>KOybJw(U|FaZBlUJQ%Zn+VQab(H3Uu27L!?0y6O zy#v1MfK)bB1%P-sc;vq~1~2xJs@3IH$H6u~_KP?a9vU~-{7KNEA;q|6hZo}u)D%w_ zndh;Eh0Yz>H>9JT0TrM%!^~k2_}{#pcw};;(4?nLy8e|Fe*mZj4fH_0B*q{b@8zwB;a2)2f-Ett{RvR zKXw;eT#=~aXDdwby`2onEmNSki~Lhvv!PgyRCTTP*@HH9KE#?kGEBFKf!b~cB% zD~WMZUQUb<5`)S*(us3j#sQv*qr6$?Zo@^spivGd(%9;5zx&eesiUR`+`e&8-e#h6 z6M#!RAwDfV=wAAN-1L==!;x^+Xn$2}X7biIRKh)XHU1b-kqm6h1Y*#@EVAeX6$WLU zI5+0;Zv$YprUu!o9`h9th!fr7ionsHZZ*(VvREJ&uz$~9?>!(45tdmER>cGL(8BM? zB73nQ1pz>ln#E@WW9jf!tf(LJgz_99fhxMhf(=fqDszEKRL~wQa9mC-kO*{p<8$|1 z&aaLJB`@EGG1Y)Uo0%`6M*#wcruOizwt~9#;qlxa9_aNwDw?b3bV?UQ%cBEqHBZ>( zyz%cqLp7O5j3FGkZYMbp{9{wSNeBE#PdPwEI0Ufi#l^r{PDX(&lgK9m)B6IHDZ%!3V7obe?JY;8zCzi@vD$GV8an`= z;{0&Dv0iF&5%=JA9MXXevM?t#enFL@rDOnzc=50+G=R~U*q=2iPPGcbCE|CUginN< zE;CZ1&Ba{x$(CRCGmxtD4B3k-X?=d7bR42i{ictWdLV96p$83!GUT^)}E zb1wj}=z@F-`Q+|br2o*#(`>K>8-MP!MFB!86bGzikq&4$kot=MT?cL3fUWy1rGEgd zxkzRq&ci{`8UPgZAN~vlP%tIfVT3UN(t@{Yt3^)jNA?n-qTVoRHq3|9EQHnnI7X`T~A5CH`F!?6bPBom5^eb8uNx ze@_5H4_z_rRPjBiggH^+vkJ=H>HNZ@vTP)N>!tWMf|G?YzdH`}H9miaR*`Q~VINzGXwrNU&@k16J`XWn z4K_|_Ml+iyuQoqWJKh-3ZLURgC}~-iadgWPcK;2x3pCUzK^xB**-=~DS*`nwfnqyn zG$a*AahL5o7=3qa#>({EBgF`)cL1A=g$dci0)C2 zGIN*m0>;8GG)-rC(m|SJ&>k{K0S!D(7M&u(p+t>8QELCbodBha_2MW*FQ5%ec#Djb zAZtmIgpTfkRGaP5n5@rfgT1DTdNP61c<|~B!h|_`2movU33{moEF+8EBoQ@CfPP#G zg$(H40&24BmB}DE5_AzQ7Dj9^vdQrnY>>N@^WWQ?W+UJXLEe`QgOxC^Q<1Otz&+U4 zEWUws*yz_77%EbC$_rL!Ea}e%r;x!5MRrQsa0N8{+3vtz`5RV5Xart=?$Wb2nvVF_1m=zOn1_#b6%TEO8-h6h}1Me{43GwQK?I#~;`)-omK2_!ht=4v~d8ciN zhE0IXBs&0UszSaza0Iej2CY%Z?FY7YC z+?9RFiA0_3qX>_^Fs~*w4L&`!|q6O__m?gPXhtR9heJF)%v2Lq)U=A4j#UPY-_v2~6uN9~+ z8tz8z>tOYX8N$J#bBmaMp<56yHq2t~e)3ts_mZ*t@rseJ{UWLeLjWwCcyQDI>Nz6R z823bF1Fd@zsdad6pZqn1_=7|)$n?E-U&PqcnlYVG9RnW7AaT+tG0)UWC~OpF#~xRF zfsUCCw+#W#cp@BhVW75r*Tk`K{5>zSg^1&1ejljm!(h-XH2lD`BZ_yU--qJM?pm?# zCMHgkty(okr!zjZW$K3He!O=QI8}|EDomWhm<^ZmSEfQNoJ$T&*UU=U)J_|z3RPW6 z>7^p?irm-43aDJj)|~sL%==wAM>W@TO58qFtR*<__mHRdJjMZ2devZK7OCtI|xL2RuzqgW>JNr0ib*d zVBDPO6bUvzqFG~fk%x!LkS+prDgD20weu(v?5vt5z-yLR8ns~${!R`S;fV$rLt#9f zRaGXKnc}UG=lz5S(%=ft5n^i&>CN(x;zI7B#j=SP`CM2X7rODDJ8HpscVLg~3Rk{+ z{r)~79kTDEpPZgKE5VHro^?%#tJ}jz3n^itzGRDY3!qTF4LcqhvV>$o1HfGioW4%Sy* z+w8xY1XPn}5)N&!6E}M38*lZ66z4WP>J#;?-uULdu`SID4ugjFROK$9!w+rB8Ro}S zY$hBUOsfBs90pCTA2i9@l5Ut(;y{JCTh!Y>3J%?M;312|Kwi}C-a%kVlF`bW?GxV? z!@xUdDilt<|3Kt7Ze0|cst<#*J{i?;+FM`kJ}h`gzWMIt`a4~~`}z7$`S|xkpB(!R zejlm7aqr7}5FFA!v25-S^2MQ^i=)>2;CBzFb?Ve^t191BS3W5>@*X$xByz4aFJrIfry~Y;pVnZbGKy|Xvl~XVX$@iHs z8dJd;j|{hiL+ZE-ovLF6h+?UXdCPlFV~Aq8{eC2GF@`kb~L!=rX$?6xRz+ zu)oEg45>~3)PJygpNa2C`&!xj-4jdFwJ0yEKEikH{j$)M&41IYO$fBl)lj_@(uS|L zm#=xqTkgK(&R{E3?AWasXthkJ1Mpk{)s<_XM(WfMu_Z4!phdC4)r6gT?s+ zY=$2u@k)uMJ7X6)HGW?4<+m(@EO;^++B~qCMF{r_Qs_v>I8DdljQWfY^YjB- zDZk;3Nh3?m)1tSy?`>!%R_{NJSp2Hq0PYE?I`&BHA8-FP6|82(G$EfRYUB0e<{Kou=~k=0GNstY;5L%)j4xq3d^vm2 zHY|OTfl|(9l%q6-ZEYS%A=c0OBY)8tnkm?0HLjXd1S`KS%4eD3f9xyzds5mXtZ)AX zx#7k{Y~A|(0s=S@)0)>r_CGL}G%?1yAJQ9K2>5Pmznd_kcl~8nm!Ua7>%`Ury!T5G+1qpHER7j6EVGgOxIU#H0`Gq(x8dsr1=94X;%XIJuAL zX@4PmNEKU>z4j&d(t#Y@X5EP&oY;ok4b^)v^SP>%DtSyt<*eK}ext2$_*dHPhP;aN zm!)7nPKBr44jI~)A#P7?Xngwhxb1@RligO8?O)UT1Q%@8 zw+e+6ViEhTU@-T-v*r*(9A>qYJED~s*ATO&tciumQE-dgLa8Q?uE<`M>2FTRDNbLU6WUotr zNb^L=n@lRdJ3=av%KkSogb^LaTJ-=5h5h=bu+f{|FES_9hjBm@j%K{B^++em8!rC0 z`Jlm51x*^4hU6mSX-5O(H08h%3lbLa)3{&y2l#)svRpG9YdeL*@~g@YN+`)ce8 z>rDcvP|djz?NNvZOm3_mtqHy`KmW)zjaF@?DQ&09E5No!h#`F2hg-PB;#cCHYrnuC z`PTa;Zuq#8+Iekl6Ia3<35q81!541MQHeqht(pKESC1O)rP)=mUOTnxpH!EP)i-fB z9so*y(`%{7^6$YgO#G=2B3jo1rh^#RpguaB>TPqXgsg!M4ZS^2=J%1#XI`w_zc>5*Eb;V}@OE}^ww-BG z&)7vtK%2Q9#51+Y+v?1Srq&u7By_^3{!-W0!JT+D2_?I#^vO)A77f~YnUq5+p*Sv-&W=y*gXRHX~qUAHTQgd-?Ze4yAo3&!c83GBS(vQo(qlPS7;nvxhrWL)UBG66v$l@VWCD7>30l1=E7 zky0#>UHeyL*_SLCrbq)Fi#jo~uzOdu+rHun19fsA>E&&aHsfmEboh@Zq`z^I@pUF0 zs)(=SYKwBy+wpvTp}~m(JOsTRwUF3+Avlc&l3;2a$(V%tUa=9ES!7%P6()U=3J1e~ zdTUc?N*@7MVs8CsR}_hbJ1jU<@}5G@g|}Kl=B#z<4(fV{Cqg)YMMk`cvCQXHKDkgE zN~ptcSWQGEwMIxO6Jtswc98OEZ2Pt=Y;aOese;@~l&I|X+q^UTP#;NPNt{IWnW)BD zepCkNz;`AVBmLD`a|g_*op&6EG-#gr@54Ud5wJE+-qM%Fx+)iyd(w?ua!p4BMFzYM zt@2}2oFvrG`9zc@Xf2Ei=-`wV@5Y307H%w%L!Wl1&!D`}319oZYUz<-Jg{-=-A;nZ z%{|(EG#T{!gQ@>nq62!LKXu0jDc6jHHRfL2BDn?!Ix=9EeF4c9XOm%Y@ICE6J-7YY zAdQ_5w_dH6DB_iV^O3ckb4mZ{4161031X;^9$7v+uJ@8&S(F0c-XB>->RqOeJ|Xrr zMN}cF`V$wa%k9^Zq%(KEfIqBR=YiFmhv^5*E0)S01`HRu_CBFp7*3$^^I5~Y zH_bhkh8qvG@-@q=mZ|@|D)`l{XM%5-Fq!9O#NLw`=eq=w`o4=Z7G8Lo?1vk{Q#2&_ zCU?EEX@_Y;ywhsSxGY)OmQ6LsK<}Qa>$phmblunOT6X0F!fSspcmWv4vU~8eeh>iR9A!h$jQ$ zsQ%uAK}2{Mnr{3AAxQ?g3LtQ^MFGViu_=dQC!s7w8j1@_IslYpV@(G@uFSi2eGcMI zY94BkI>cZQ50t4ml~0AIQ=E!(rc#GNLS(bjQKxdMS!QafI-Y7d46RHBLMWiZx55w- z<~AOxMG?@z3iDH;g07FVri~$mrnrpS<l<@#p%gQf!fHE0( zu!9Pvjwwj|ORo9O2X0d!d+=0DoR$v-AWNCn#}`{-Ti7so3QxsxXK;(tg}-PG1KQA9-~wRS*@bFJEPEbK zhv2R<3S8{MXDoSI|3(TmiB#0C94dU=^-DX>>0$MYE`2<}5HQXB;>W3Uz)2kW)R}+ z>x4p300ab4mP)Qsiw1-~fa1u@b{9#C~wHD9m;ETf|*-)Ey zx1>y{4-522(cPEFl&W*4UPFbQ(t1FAs3yvkzvX#GK*i8J3+n)^l(kiyDP<~7SAQ!w zJ>XFj<$P}R3TjS|DhV#s1Ya73)@?b{@}yxBasJ>=i8()z5_Z7{uIb|;$beH0V#g4yaswP@Id9kgLsQ+ zweYKyH~~f%%vaH*X)XRAE1JQy(;J7U2rx~jl~Zaa4TUH7?_A5H6vcBP?oNezBtWJw z&AjSD?_58*AB1T`1rD`?##$X=ESj;{H|BG2Ums;GW);3xL>!du{U_m zcYG^4eseK`1P z`em2^Df)H6@?R*4uN1nS8wTuo-FYi$N;K?GUD%ttpw04S&dbvG$HKnveYt%r?A~PX z!pB#9aLu&;#k`zN>yyD-V=bUMw7W+`23g zv-0fYi}?pZDi2A>ytTz#=NC#xZY?k(x9d{kP9{#l64^z^xkd5c{ajj3#`22N=B}og zDCh8sVx8cbixb92{oOU8!GfCC@VeI&)Sc~bRXUlAh94)dTa8T8S^<2+0HDpH9auPb z6riF>b?N~sCzzplR8e!9=wj4K%+g_H8bv`^7)MJ@+n_8{OG4FrV5KJ)quld~y8+R} ze;Z^)+WK--&B3!(6Yc+BQPX-sO* zR-#O7mU3+Bq1fYoG1;HCvK_W^2%ECuF{tU7tj*2be_K>oEd6dw^269-*mlaNtzwO> zSpBUs)405hxcHdu{2wv2jF@u$xa!N>nWk}ZcehW9y)7MzjrNOWZpJ0ozpW~In|AhX z#=q^_hw%|Z+ozP@)jfO5@_S1Ui>nxlrMQb^n%-i_ylcK4m+Stvp(u`}v6=YKEdIOF zTINaHiL1T!b{mZ+O%5H+ne%_^d@T|OJxul=&Uo%N2l1X_SXb0r|1qML!+@9o{f_SgB1FUXhnasL!o)sa zb1Egu0O11ogMHjW*s*6x$DZdMTdX*?RDbM6&#~p($5tL5d->|vt53&X|2xJNOIlS< zTGLNjKa{lLp7bUxX*1~~*s$o;mv_BqlZ;+X{I+b_f;ed~EntIB(g z=eO=o681yjxPkob$sbUi0eL%O$EtoM)6w9}J zHEI8>xG?wg@4RG8WwPAK&wmbmocALuK1x=4ovi#hS%sgBMWv{!d=-4IZA%iOlDu=7 z{Gq2o{2tE>^2Lou_5d9J@^4+djkojTy%HetN5*G4RH~s$su4=Kt-SfKMvBRiRMX?B zX8Eb+m8ljDJI|FFJsG?c>{R%Pl=m9R*8Eh7N4$8%XSdoE?S}X0=g+O%8vcj__N}O# zB7XTVIodyr>d3Qqd6aheb(;Iz`TJlVB3HOhDO9p?2eeG?m@$Vj9hwQs_Zp9HA5)r<}~E6jxGCHBd@=DW!LI3ssoq zmK3daP$i$jL}gZ~WL6twp0>_BGRl@+hn4byn}^ ztUi8LKPvm`Igr63c)%lj&_CO;9pV`G=lY54;fCxRy?=&}|Iq<}_Y&!R95?&U=RbNx zy7n+VjP+;a=lQvdmAOj|xi5Nim+$1RJo@h$AAs1-ea+A1qViT%^41LU z)~)k4Jo4Tg$=f`hx0Ro_U77c`A@5yp-upXwA0Fj>e4Y2{bKYlu9`6oSm`M;lo^r$o#)BoS+d@7nvrBOv}2jVQ+ap7aCL`@1> z)zc1+P}6XUYD`wUSD|c87tu;lpRU&MXmaaF**kMq|HxRGR_bLZzLWxPZMGwI-=q3N z`5;m4G|k6N4wZWjccy7Qz3kp#Q?8vZDEj;LMm$&oPQt}h639IHAGZFIXicJdRmPPU zLy50D?MFBT@BxTW1=@)Qv=djD>!~5z;27dX1y9_%F`IWLD^zSNbTf^jF9sS!KJ3oi zzxA-*xw)C*$x4IbocUx?XXN!a6!}rc%wL zC&yxE^Pz2%re3b)_jk{FBOmqT9yoF7R`$;5DbK$X7dQ6hIlkQaJGb@e^?0R0eqQvC zm!H=k_2ygi|NY~GHKlUF5&Cy|JLD&&DyjXQ{op(nkKRyYdyDt@OEw3mupF zaW6XB>Qa7pv^Q4=b#}BhUFhuWy85ECt9MMktNU7>HdIueJkj1V^7TbmuWQykN3js` z6|S0(DgDqtZ8Xw-?Y_-&;=m)LKaU2UyIj;8T#lHzGW3%Ehks@GRkcFWjr9u`^>4nf zU+%g2>FS@J(J!W5Q_`9nzq@Y#`MTU&tenf5LZQ>c6Xyy3&77N_G^l6q?5D%Kg`L>FRx*Bk(>|&rw#DuhmK7N~V7L2DIZj z<>lvxUVP5QU0sq-*Be?%eHwb*L*Mbsj~CfHw|>BL(!LOGXGn$(uZFK*Iq|x5|DovR zPzvem>S^z=%-$%SSHqhZyQVmbOxL6v+s&sRMz39JuD^Mz^1TxO#M|C+<&m_TQbScYJ<-Sa0AvuH8FwhtCHS_x*gT0^IRG zSY2*FMTW5c!UEWEdS$v$6c(zpXa%>y6+GSv;o8JtQfn^^uSoDVD6@S7k)7OAAKQO; zgQhs8kNJahkjqc!zgq83U)ZuT;;mR&SUItcDjtXpB^UI!4DW5ay zir7L+3IXDh7X>wKw{Z<*dgGk?&cQ;pz3a{#QW*d#m-XS@mVJQx+*zRW7gwdEN%p!~ z5U6(=-tQW~U8ma)tlZ89E8}URi8bn~+*sWlVuAdwVCqd~parWjOMwJv?=TgWgAW)R ztArYBI$DSXFOL7_#%K|M!4KMfE6qJi{L zb;sK2`SrijL?o%HFeh+@fTAGYo@yI>82mm?#0s%0-V+B^tHn;q4g*kwa|Wtc=YX0i zZ1i{>!}z|qSft3hAP`(ArD-v(`&aeWdp!_5>IdDAXCu34e$T8-^-cJ$fc7ZJ1}7Mn zg||dt3UQr|)Y+53UjGLQ{rG)iZyBo3K`09+!=gfS+anofk4x%_VmB@m(~GZnDkc*o zio`4O1NJM9^4mdZldB+Qr#%X@mtss2jfXw1vqh1&H;of$%fkiSJJ&f>Mq=_2uxyp{fsOtoLuu#7xVNYAdY+Kzk>||G=3&F~jh&RR$t3<5@ zdt4L+Vs-gTalBjeg)7Bl^7-77)XstzmrRHBuEZZd+8HU22qB1!F+Zgx1$pXI2qqtI zdF71QAoFSp=xu?YWTGk%qnf)WT`%KhG)eNjID4JB+`~CBQ@QfbJ~g=}rNC6@VOhu8 zua#>T2DO6~1W*UHU5hd-Hc*16X`;-V6C(dxZ$8>XH=a+9Y;axg*6IMLv@Z!+ouP>@ znLF}ry{`hG*@P>q2w<=UewqpU0YFmm2y;BHg1oD!sF{s$V}B3bazQRFQXc)ni8KrQ zs>u@jjCWZugS52^BplF58d!OJe(f_w(^9+ecA{&$nnD>DtWwq}wy6CMO4`1mf1f7m zFdr&vT`Z@!^$Ka#O%p$%au;s(0rv2<#5W3W1Wj%Q3QQhT@0hSUv#TJb?LC`iPX8I| z8$dKI@$$S~E7?&tg8UVDo{^z|^ho;e{m#~iXEX#JQ~|nHWGlLNSVvAOgb{I#3r-P) z*Aj^IpYMGo3S$X~jX4jUve)pk;h1g@Bf61*;5rWgj;g4IysBy}?9~fEr15ErJdPrd zfY}Bh2LO=bGseR}NCH-2RP>r>J?s#xrxAiQ=cwW6Xso|b0Kw!7+hJGUYJLIAtubVS zRYw6mg;Z7cxTzgM(6CgtQ{I~!WOAzEPZiL#-4-(?0-p!KK5)#Oz;Yz&pI=nitO(MM zCiEKsBjJT=7c3_54|Z81I2()YF)0!iC50EIQqR5g72Y_SoHP=6Mo8fnyNE8UHsVN3{P@uEb6Uc&smA?EJ~B`YS!K^@OKY_m@v zzYlU25@!de5X^H5@||gxIkrC^xFK|<)Hc|{>Sy8Y95Xk8KMz&h&lV=(5yfkoKi2IU z8yp1NwOe$_2{#c$%d0CiOLMU3+^RGiZ0>`P2xa3gfz{N{f)c@2-5e+z1w+suE2%_d zBU~}^(-v!PPg>&eYd_NETKfQKW!tFu31NteDr-%6oBFab*tF%M<)tRrH*wWMr3Z0% znH+HU;j`#rnvNUTD`s5T#a4v3$61rllEqUM=WX;BpBUN^HUd~yXQP9MZ1$1yZ8z91 zgVDh^LH3@J7l)~`EE~U=H??)(0>RgS6r2cQdTzkmg#gQU^lx7x&7;6BlK@OR*xaqz zVVA8gfQJvXI8Xq}yK2%=71AjLJ;i9hFmD;%4g6Q&acPc!1_VCL`Lws>^Y`UXz#7#2 zm<0l)?Lz&!N^pOM*OxC4V_&AtR(UOKq!{gs%kig_KX>G9Koci~+ijf0qPfxIINq2} z@p-RjVcuh4+=RHWU35ODF7_+XT&dv9Te>lES-;7SuD2+Vk;ry(PD`r^2arfmw(i3S z!dWNJrJL&G&mBfkIym7;*x)v?X0+)hJGvHEAEbWCz5WOt#LZ#QPY_uUN^?yjAz`Q`LaI`4SJ1 zc6({P%igV_0`*%dVHn{7cBZ>eRuf)aDsN^OJydCVmS096!PQ zAt@)ikz_;{<04Owft9ValD*!ljz!_iL(Wwnz2Od3e-*kg=)Bk6R&@3qoT|R>HUMe$ z+Ax67xCdZaA2Izws%sBmg?fZvV+Zf!n2`!(agoBh0JMwkAr0;dquIfYy(4NX!^M&w zbX;u>4Z8qAs?!Y5fK^FUJIi-wPH}Z!n$WLXNiKrpwn_0~Ti#6wf5DcXY8JBc5$(2d z`h=J1Z!guZFp?X$;BlsgsLii54c@iu;9Hz_+wI@Ib6BLxCPrmmrP?r}#JKmtfLM2Z zKKq~OxEMtH@Tj`$M9Yn)V=uI!>Nn|@IJ!hS6+WRSmwO~3NWdnhN@~{1@3LhcOPMkW zPzu%dG1u!V8_FeEAAIfyQ1z`Z6e{GH<=6`T=ME!)mdXV=^%GFd2B!)@h`q1g?#2 z4vi*1|4Af}qw}F&zHATFtou+8UIyE!Z`>g729o&n{z5vZc7ZNS;mE7ktzWQfo#W!# z3DSU9wax{b7YeoMl4{1UA2Dp@=BfRs&KRmIWY&yZ&Ebn$A$R1sW?X_a8K|sSFrBf! zng=$&AX?N}P^7I9>7r8X5c6jf&r6qZhQ2lqph+h|z)^(j={8_*0;UNdiW~b{L(^O% z+^i{(O4AUg;tv@0L%Rr46KA9XaNIhuxp|)~;Bnh2L+rWa*lKkvb1kPYpBEq6E%i(+ zN$@mMjT~5AW})(PjB&$>4+~kqoILN_9W+rZAB59O6X$tD5&lQ*mUqTRW6Cz08MiOw zpNBwnl})0-UIHD+x6jU__%L5dbI+$jUJ`FD$03)JEZPg+Rj{N*u3U$v>R?qX!tm1B z9O>sERd>#_rsnZJk@k`tai2i z+|srg1FX%%HwoULMc$)~r^W!_?O}i%D}}>JeVs6I+~w=vaDa#4gaLCYM8dyq+tRc zqOYNvju;&?bOQcPX5;KGF9iTp+zN4fEYF0AxSt1z)7T zYfUqq2VL{4MhAd`cL?grV9BW+hhb{a3A$%&E3pTF9LB3g6&SMyj9D2jsBu)SDB=TN zS7h86Gp_z&%fW}Lp997umJ1DYtmERcu0EI|z89(bmfZF6+`pDTw;Du-8${0F5u@zM zrG-C(Z>^nP7+RZ!9aD{ne{6V1Xd&zYzG0W{tac&=W{ulW`&P(=VsmUq~@jb9jK;@Lev zD^7Q%9Jdo5z+)0TomLF$UYsa893_0_`7FR9sI*X6^M;#K%SoVxtJDoQ#Nf5imC65x zod+&GWI|5o+nxRFUQ+;JT1%aCRsXy4c~&>Yalk?+c)BL$+}W?Yb-@jlpXch~Rl`3} z_28RoL+A#{-?ecmg0{_%x0#Lmf7hzVepSzEX;@*IWwokIH@aqBJ|Wv0oYl5I)vR*i za_R4kU!P53zztiC*kQT_-n^M1wC$iB~x z0HF4O&Ah%t8tK5W8aCJI@!;zTS_i8A>D<8j0e}S>+0HRs4C;8((#H5={kOm=$qr7X zU7>lK782NwcZ=_2r)Wxg?eTIPrK$%!Rr^+Rx)-9RWfkSexvF*#cAY-fOrN@V3^Czb zwS6;r>(9*oIe;%f!7WtZ1FV9+FpK_cP3279!prVvjVwcr~-9Xj>J9co+w*Y>Zx1H7PDQqeylv&a~PzG z43-g5NJJ8(q6ldA4aup4@CIAVU$PVFs|!!f>+8^-$xe2Xomdn>W&@vh9ikIUlMJ9K z7un+Pz}4Pdln&smeWtEoo4ERR%)$zE)yuiF_rJFnE9*~V4GPtBRd#K9@X^WPAl_P@ z%8nF!ALj2ZUr)Rr%~v-Fa5R(lJevb#N*{Z`ga&v*iO;usef@l?M>+D^z5wWewCo;D zWB}VY+IJ`Q0eGV7Yi!Lc#T~<7j!zch@t;>g-w*A)e}L4?PkzLd7BX8w06pGr7jF_u4vf>9YN) z)g610_^taPycVp{>Ju5N>d`Ylu7nI9FSsVBRzij%_f=Q;4oSUX#IQ6& zy5kR)d7LFLbx)Of&g_4yedqvIb>4Eh-`&YZ{Tp}hGEVGtn<#i3xK*mOG?sa)Tyjzv zccta9_a{5ZJ0*Vm|{zZ^40EK

Z##^mP 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

4ex#x0AdV`hZ^ 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 z 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

RHRb(pQJ;fVmCceOTp2844pJpCsPT*a)V$nSKuo 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

  • 3GPv#zWKPQartIc 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

    v)DVTGI77`<*(JcHE2Kd@Bt)J_05 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 Ne{