diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d89c0e..d2d0971 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,8 +26,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - It now displays the source command (file and line) of the entry - When saving... - Unchanged files are no longer overwritten - - Commands are no longer reordered - - Done and cancel dates are simplified + - Imports are now sorted alphabetically + - Done and cancel dates are now simplified where possible - Always prints import-based path, not absolute path ### Fixed diff --git a/src/files/format.rs b/src/files/format.rs index 368f60f..6fb79b2 100644 --- a/src/files/format.rs +++ b/src/files/format.rs @@ -318,20 +318,56 @@ impl fmt::Display for Log { } impl File { + fn sort(commands: &mut Vec<&Command>) { + // Order of commands in a file: + // 1. Imports, sorted alphabetically + // 2. Time zone(s) + // 3. Log entries, sorted by date (ascending) + // 4. Tasks and notes, in original order + + // There should always be at most one time zone, so we don't care about + // their order. + + // In the individual steps we must use a stable sort so the order of 4. + // is not lost. + + // Order imports alphabetically + commands.sort_by_key(|c| match c { + Command::Include(path) => Some(&path.value), + _ => None, + }); + + // Order log entries by date + commands.sort_by_key(|c| match c { + Command::Log(Log { date, .. }) => Some(date.value), + _ => None, + }); + + // Order by type + commands.sort_by_key(|c| match c { + Command::Include(_) => 0, + Command::Timezone(_) => 1, + Command::Log(_) => 2, + Command::Task(_) | Command::Note(_) => 3, + }); + } + pub fn format(&self, removed: &HashSet) -> String { let mut result = String::new(); - let commands = self + let mut commands = self .commands .iter() .enumerate() .filter(|(i, _)| !removed.contains(i)) - .map(|(_, c)| c) + .map(|(_, c)| &c.value) .collect::>(); + Self::sort(&mut commands); + for i in 0..commands.len() { - let curr = &commands[i].value; - let next = commands.get(i + 1).map(|c| &c.value); + let curr = &commands[i]; + let next = commands.get(i + 1); result.push_str(&format!("{}", curr));