diff options
| -rw-r--r-- | crates/atuin-client/src/database.rs | 13 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/search/engines.rs | 4 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/search/interactive.rs | 93 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/search/keybindings/actions.rs | 6 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/search/keybindings/conditions.rs | 15 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/search/keybindings/defaults.rs | 10 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/search/keybindings/keymap.rs | 1 | ||||
| -rw-r--r-- | docs/docs/configuration/advanced-key-binding.md | 3 | ||||
| -rw-r--r-- | docs/docs/configuration/config.md | 15 | ||||
| -rw-r--r-- | docs/docs/configuration/key-binding.md | 21 | ||||
| -rw-r--r-- | docs/docs/guide/advanced-usage.md | 49 | ||||
| -rw-r--r-- | docs/docs/guide/basic-usage.md | 2 | ||||
| -rw-r--r-- | docs/mkdocs.yml | 1 |
13 files changed, 206 insertions, 27 deletions
diff --git a/crates/atuin-client/src/database.rs b/crates/atuin-client/src/database.rs index 28d6c0f0..7aa095f7 100644 --- a/crates/atuin-client/src/database.rs +++ b/crates/atuin-client/src/database.rs @@ -32,6 +32,7 @@ use super::{ settings::{FilterMode, SearchMode, Settings}, }; +#[derive(Clone)] pub struct Context { pub session: String, pub cwd: String, @@ -72,6 +73,18 @@ pub async fn current_context() -> eyre::Result<Context> { }) } +impl Context { + pub fn from_history(entry: &History) -> Self { + Context { + session: entry.session.to_string(), + cwd: entry.cwd.to_string(), + hostname: entry.hostname.to_string(), + host_id: String::new(), + git_root: utils::in_git_repo(entry.cwd.as_str()), + } + } +} + fn get_session_start_time(session_id: &str) -> Option<i64> { if let Ok(uuid) = Uuid::parse_str(session_id) && let Some(timestamp) = uuid.get_timestamp() diff --git a/crates/atuin/src/command/client/search/engines.rs b/crates/atuin/src/command/client/search/engines.rs index 95d6658b..5c53817e 100644 --- a/crates/atuin/src/command/client/search/engines.rs +++ b/crates/atuin/src/command/client/search/engines.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; use atuin_client::{ database::{Context, Database}, - history::History, + history::{History, HistoryId}, settings::{FilterMode, SearchMode, Settings}, }; use eyre::Result; @@ -22,6 +22,7 @@ pub struct SearchState { pub input: Cursor, pub filter_mode: FilterMode, pub context: Context, + pub custom_context: Option<HistoryId>, } impl SearchState { @@ -44,6 +45,7 @@ impl SearchState { fn filter_mode_available(&self, mode: FilterMode, settings: &Settings) -> bool { match mode { + FilterMode::Global | FilterMode::SessionPreload => self.custom_context.is_none(), FilterMode::Workspace => settings.workspaces && self.context.git_root.is_some(), _ => true, } diff --git a/crates/atuin/src/command/client/search/interactive.rs b/crates/atuin/src/command/client/search/interactive.rs index b5186706..c6a6064a 100644 --- a/crates/atuin/src/command/client/search/interactive.rs +++ b/crates/atuin/src/command/client/search/interactive.rs @@ -16,10 +16,11 @@ use super::{ history_list::{HistoryList, ListState}, }; use atuin_client::{ - database::{Database, current_context}, + database::{Context, Database, current_context}, history::{History, HistoryId, HistoryStats, store::HistoryStore}, settings::{ - CursorStyle, ExitMode, KeymapMode, PreviewStrategy, SearchMode, Settings, UiColumn, + CursorStyle, ExitMode, FilterMode, KeymapMode, PreviewStrategy, SearchMode, Settings, + UiColumn, }, }; @@ -59,6 +60,7 @@ pub enum InputAction { ReturnQuery, Continue, Redraw, + SwitchContext(Option<usize>), } #[derive(Clone)] @@ -304,6 +306,7 @@ impl State { selected_index: self.results_state.selected(), results_len: self.results_len, original_input_empty: self.original_input_empty, + has_context: self.search.custom_context.is_some(), }; // Convert KeyEvent to SingleKey @@ -657,6 +660,10 @@ impl State { self.engine = engines::engine(self.search_mode); InputAction::Continue } + Action::SwitchContext => { + InputAction::SwitchContext(Some(self.results_state.selected())) + } + Action::ClearContext => InputAction::SwitchContext(None), Action::ToggleTab => { self.tab_index = (self.tab_index + 1) % TAB_TITLES.len(); InputAction::Continue @@ -916,6 +923,11 @@ impl State { Compactness::Ultracompact => { if self.switched_search_mode { format!("S{}>", self.search_mode.as_str().chars().next().unwrap()) + } else if self.search.custom_context.is_some() { + format!( + "C{}>", + self.search.filter_mode.as_str().chars().next().unwrap() + ) } else { format!( "{}> ", @@ -1166,6 +1178,8 @@ impl State { fn build_input(&self, style: StyleState, prefix_width: u16) -> Paragraph<'_> { let (pref, mode) = if self.switched_search_mode { (" SRCH:", self.search_mode.as_str()) + } else if self.search.custom_context.is_some() { + (" CTX:", self.search.filter_mode.as_str()) } else { ("", self.search.filter_mode.as_str()) }; @@ -1372,7 +1386,7 @@ pub async fn history( let update_needed = tokio::spawn(async move { settings2.needs_update().await }).fuse(); tokio::pin!(update_needed); - let context = current_context().await?; + let initial_context = current_context().await?; let history_count = db.history_count(false).await?; let search_mode = if settings.shell_up_key_binding { @@ -1382,6 +1396,10 @@ pub async fn history( } else { settings.search_mode }; + let default_filter_mode = settings + .filter_mode_shell_up_key_binding + .filter(|_| settings.shell_up_key_binding) + .unwrap_or_else(|| settings.default_filter_mode(initial_context.git_root.is_some())); let mut app = State { history_count, results_state: ListState::default(), @@ -1397,11 +1415,9 @@ pub async fn history( keymaps: KeymapSet::from_settings(settings), search: SearchState { input, - filter_mode: settings - .filter_mode_shell_up_key_binding - .filter(|_| settings.shell_up_key_binding) - .unwrap_or_else(|| settings.default_filter_mode(context.git_root.is_some())), - context, + filter_mode: default_filter_mode, + context: initial_context.clone(), + custom_context: None, }, engine: engines::engine(search_mode), results_len: 0, @@ -1448,6 +1464,7 @@ pub async fn history( let initial_input = app.search.input.as_str().to_owned(); let initial_filter_mode = app.search.filter_mode; let initial_search_mode = app.search_mode; + let initial_custom_context = app.search.custom_context.clone(); let event_ready = tokio::task::spawn_blocking(|| event::poll(Duration::from_millis(250))); @@ -1479,6 +1496,19 @@ pub async fn history( app.tab_index = 0; }, + InputAction::SwitchContext(index) => { + if let Some(index) = index && let Some(entry) = results.get(index) { + app.search.custom_context = Some(entry.id.clone()); + app.search.context = Context::from_history(entry); + app.search.filter_mode = FilterMode::Session; + app.search.input = Cursor::from(String::new()); + app.results_state = ListState::default(); + } else { + app.search.custom_context = None; + app.search.context = initial_context.clone(); + app.search.filter_mode = default_filter_mode; + } + }, InputAction::Redraw => { terminal.clear()?; terminal.draw(|f| app.draw(f, &results, stats.clone(), inspecting.as_ref(), settings, theme))?; @@ -1504,10 +1534,23 @@ pub async fn history( if initial_input != app.search.input.as_str() || initial_filter_mode != app.search.filter_mode || initial_search_mode != app.search_mode + || initial_custom_context != app.search.custom_context { results = app.query_results(&mut db, settings.smart_sort).await?; } + // In custom context mode, when no filter is applied, highlight the entry which was used + // to enter the context when changing modes. This helps to find your way around. + if app.search.custom_context.is_some() + && app.search.input.as_str().is_empty() + && (initial_custom_context != app.search.custom_context + || initial_filter_mode != app.search.filter_mode) + && let Some(history_id) = app.search.custom_context.clone() + && let Some(pos) = results.iter().position(|entry| entry.id == history_id) + { + app.results_state.select(pos); + } + let inspecting_id = app.inspecting_state.clone().current; // If inspecting ID is not the current inspecting History, update it. match inspecting_id { @@ -1600,7 +1643,10 @@ pub async fn history( // * out of bounds -> usually implies no selected entry so we return the input Ok(app.search.input.into_inner()) } - InputAction::Continue | InputAction::Redraw | InputAction::Delete(_) => { + InputAction::Continue + | InputAction::Redraw + | InputAction::Delete(_) + | InputAction::SwitchContext(_) => { unreachable!("should have been handled!") } } @@ -1827,6 +1873,7 @@ mod tests { host_id: String::new(), git_root: None, }, + custom_context: None, }, engine: engines::engine(SearchMode::Fuzzy), now: Box::new(OffsetDateTime::now_utc), @@ -1881,6 +1928,7 @@ mod tests { host_id: String::new(), git_root: None, }, + custom_context: None, }, engine: engines::engine(SearchMode::Fuzzy), now: Box::new(OffsetDateTime::now_utc), @@ -1999,6 +2047,7 @@ mod tests { host_id: String::new(), git_root: None, }, + custom_context: None, }, engine: engines::engine(SearchMode::Fuzzy), now: Box::new(OffsetDateTime::now_utc), @@ -2057,6 +2106,7 @@ mod tests { host_id: String::new(), git_root: None, }, + custom_context: None, }, engine: engines::engine(SearchMode::Fuzzy), now: Box::new(OffsetDateTime::now_utc), @@ -2111,6 +2161,7 @@ mod tests { host_id: String::new(), git_root: None, }, + custom_context: None, }, engine: engines::engine(SearchMode::Fuzzy), now: Box::new(OffsetDateTime::now_utc), @@ -2161,6 +2212,7 @@ mod tests { host_id: String::new(), git_root: None, }, + custom_context: None, }, engine: engines::engine(SearchMode::Fuzzy), now: Box::new(OffsetDateTime::now_utc), @@ -2220,6 +2272,7 @@ mod tests { host_id: String::new(), git_root: None, }, + custom_context: None, }, engine: engines::engine(SearchMode::Fuzzy), now: Box::new(OffsetDateTime::now_utc), @@ -2280,6 +2333,7 @@ mod tests { host_id: String::new(), git_root: None, }, + custom_context: None, }, engine: engines::engine(SearchMode::Fuzzy), now: Box::new(OffsetDateTime::now_utc), @@ -2490,6 +2544,26 @@ mod tests { } #[test] + fn execute_switch_context() { + use crate::command::client::search::keybindings::Action; + + let mut state = make_executor_state(100, 7); + let settings = Settings::utc(); + let result = state.execute_action(&Action::SwitchContext, &settings); + assert!(matches!(result, super::InputAction::SwitchContext(Some(7)))); + } + + #[test] + fn execute_clear_context() { + use crate::command::client::search::keybindings::Action; + + let mut state = make_executor_state(100, 7); + let settings = Settings::utc(); + let result = state.execute_action(&Action::ClearContext, &settings); + assert!(matches!(result, super::InputAction::SwitchContext(None))); + } + + #[test] fn execute_noop() { use crate::command::client::search::keybindings::Action; @@ -2638,6 +2712,7 @@ mod tests { host_id: String::new(), git_root: None, }, + custom_context: None, }, engine: engines::engine(SearchMode::Fuzzy), now: Box::new(OffsetDateTime::now_utc), diff --git a/crates/atuin/src/command/client/search/keybindings/actions.rs b/crates/atuin/src/command/client/search/keybindings/actions.rs index fae811d6..66e2709e 100644 --- a/crates/atuin/src/command/client/search/keybindings/actions.rs +++ b/crates/atuin/src/command/client/search/keybindings/actions.rs @@ -52,6 +52,8 @@ pub enum Action { Redraw, CycleFilterMode, CycleSearchMode, + SwitchContext, + ClearContext, ToggleTab, // Mode changes @@ -129,6 +131,8 @@ impl Action { "redraw" => Ok(Action::Redraw), "cycle-filter-mode" => Ok(Action::CycleFilterMode), "cycle-search-mode" => Ok(Action::CycleSearchMode), + "switch-context" => Ok(Action::SwitchContext), + "clear-context" => Ok(Action::ClearContext), "toggle-tab" => Ok(Action::ToggleTab), "vim-enter-normal" => Ok(Action::VimEnterNormal), @@ -193,6 +197,8 @@ impl Action { Action::Redraw => "redraw".to_string(), Action::CycleFilterMode => "cycle-filter-mode".to_string(), Action::CycleSearchMode => "cycle-search-mode".to_string(), + Action::SwitchContext => "switch-context".to_string(), + Action::ClearContext => "clear-context".to_string(), Action::ToggleTab => "toggle-tab".to_string(), Action::VimEnterNormal => "vim-enter-normal".to_string(), diff --git a/crates/atuin/src/command/client/search/keybindings/conditions.rs b/crates/atuin/src/command/client/search/keybindings/conditions.rs index bc485713..d460d7d4 100644 --- a/crates/atuin/src/command/client/search/keybindings/conditions.rs +++ b/crates/atuin/src/command/client/search/keybindings/conditions.rs @@ -13,6 +13,7 @@ pub enum ConditionAtom { ListAtStart, NoResults, HasResults, + HasContext, } /// Boolean expression tree over condition atoms. @@ -49,6 +50,8 @@ pub struct EvalContext { pub results_len: usize, /// Whether the original input (query passed to the TUI) was empty. pub original_input_empty: bool, + /// Whether we use a search context of a command from the history. + pub has_context: bool, } // --------------------------------------------------------------------------- @@ -69,6 +72,7 @@ impl ConditionAtom { ConditionAtom::ListAtStart => ctx.results_len == 0 || ctx.selected_index == 0, ConditionAtom::NoResults => ctx.results_len == 0, ConditionAtom::HasResults => ctx.results_len > 0, + ConditionAtom::HasContext => ctx.has_context, } } @@ -83,6 +87,7 @@ impl ConditionAtom { "list-at-start" => Ok(ConditionAtom::ListAtStart), "no-results" => Ok(ConditionAtom::NoResults), "has-results" => Ok(ConditionAtom::HasResults), + "has-context" => Ok(ConditionAtom::HasContext), _ => Err(format!("unknown condition: {s}")), } } @@ -98,6 +103,7 @@ impl ConditionAtom { ConditionAtom::ListAtStart => "list-at-start", ConditionAtom::NoResults => "no-results", ConditionAtom::HasResults => "has-results", + ConditionAtom::HasContext => "has-context", } } } @@ -394,6 +400,7 @@ mod tests { selected_index: selected, results_len: len, original_input_empty, + has_context: false, } } @@ -457,6 +464,14 @@ mod tests { } #[test] + fn atom_has_context() { + let mut context = ctx(0, 0, 0, 0, 0); + assert!(!ConditionAtom::HasContext.evaluate(&context)); + context.has_context = true; + assert!(ConditionAtom::HasContext.evaluate(&context)); + } + + #[test] fn atom_parse_round_trip() { let conditions = [ "cursor-at-start", diff --git a/crates/atuin/src/command/client/search/keybindings/defaults.rs b/crates/atuin/src/command/client/search/keybindings/defaults.rs index 64dca691..f19bf377 100644 --- a/crates/atuin/src/command/client/search/keybindings/defaults.rs +++ b/crates/atuin/src/command/client/search/keybindings/defaults.rs @@ -405,6 +405,13 @@ pub fn default_prefix_keymap() -> Keymap { km.bind(key("d"), Action::Delete); km.bind(key("a"), Action::CursorStart); + km.bind_conditional( + key("c"), + vec![ + KeyRule::when(ConditionAtom::HasContext, Action::ClearContext), + KeyRule::always(Action::SwitchContext), + ], + ); km } @@ -530,6 +537,7 @@ mod tests { selected_index: selected, results_len: len, original_input_empty: false, + has_context: false, } } @@ -1250,6 +1258,7 @@ mod tests { selected_index: 0, results_len: 10, original_input_empty: true, + has_context: false, }; assert_eq!( set.emacs.resolve(&key("esc"), &ctx_original_empty), @@ -1265,6 +1274,7 @@ mod tests { selected_index: 0, results_len: 10, original_input_empty: false, + has_context: false, }; assert_eq!( set.emacs.resolve(&key("esc"), &ctx_original_not_empty), diff --git a/crates/atuin/src/command/client/search/keybindings/keymap.rs b/crates/atuin/src/command/client/search/keybindings/keymap.rs index bbf034b2..8c7fcfa8 100644 --- a/crates/atuin/src/command/client/search/keybindings/keymap.rs +++ b/crates/atuin/src/command/client/search/keybindings/keymap.rs @@ -127,6 +127,7 @@ mod tests { selected_index: selected, results_len: len, original_input_empty: false, + has_context: false, } } diff --git a/docs/docs/configuration/advanced-key-binding.md b/docs/docs/configuration/advanced-key-binding.md index 1fe9c1e4..7f73b5d6 100644 --- a/docs/docs/configuration/advanced-key-binding.md +++ b/docs/docs/configuration/advanced-key-binding.md @@ -206,6 +206,8 @@ Note: `select-next` and `select-previous` respect the `invert` setting. When `in | `cycle-filter-mode` | Cycle through filter modes (global, host, session, directory) | | `cycle-search-mode` | Cycle through search modes (fuzzy, prefix, fulltext, skim) | | `toggle-tab` | Toggle between the search tab and inspector tab | +| `switch-context` | Switch to the [context](../guide/advanced-usage.md#context-switch) of the currently selected command | +| `clear-context` | Return to the initial [context](../guide/advanced-usage.md#context-switch) | The difference between `accept` and `return-selection`: `accept` runs the command immediately when the TUI closes, while `return-selection` places it on your command line for further editing before you press enter. The `enter_accept` setting controls which of these the default `enter` key uses. @@ -251,6 +253,7 @@ Conditions let a single key do different things depending on the current state. | `list-at-end` | The selection is at the last entry | | `no-results` | The search returned zero results | | `has-results` | The search returned at least one result | +| `has-context` | The context comes from a previously selected command (`switch-context`) | ### Boolean expressions diff --git a/docs/docs/configuration/config.md b/docs/docs/configuration/config.md index 49e29a79..31980ed1 100644 --- a/docs/docs/configuration/config.md +++ b/docs/docs/configuration/config.md @@ -139,13 +139,14 @@ Default: `global` The default filter to use when searching -| Mode | Description | -| ---------------- | ------------------------------------------------------------ | -| global (default) | Search history from all hosts, all sessions, all directories | -| host | Search history just from this host | -| session | Search history just from the current session | -| directory | Search history just from the current directory (global) | -| workspace | Search history just from the current git repository (>17.0) | +| Mode | Description | +|------------------|--------------------------------------------------------------------------------------| +| global (default) | Search from the full history | +| host | Search history from this host | +| session | Search history from the current session | +| directory | Search history from the current directory | +| workspace | Search history from the current git repository | +| session-preload | Search from the current session and the global history from before the session start | Filter modes can still be toggled via ctrl-r diff --git a/docs/docs/configuration/key-binding.md b/docs/docs/configuration/key-binding.md index f292999f..942a2400 100644 --- a/docs/docs/configuration/key-binding.md +++ b/docs/docs/configuration/key-binding.md @@ -202,31 +202,32 @@ $env.config = ( ## Atuin UI shortcuts | Shortcut | Action | -| ----------------------------------------- | ----------------------------------------------------------------------------- | -| enter | Execute selected item | +|-------------------------------------------|-------------------------------------------------------------------------------| +| enter | Execute selected item | | tab | Select item and edit | | ctrl + r | Cycle through filter modes | | ctrl + s | Cycle through search modes | | alt + 1 to alt + 9 | Select item by the number located near it | | ctrl + c / ctrl + d / ctrl + g / esc | Return original | | ctrl + y | Copy selected item to clipboard | -| ctrl + ← / alt + b | Move the cursor to the previous word | -| ctrl + → / alt + f | Move the cursor to the next word | -| ctrl + b / ← | Move the cursor to the left | -| ctrl + f / → | Move the cursor to the right | +| ctrl + ← / alt + b | Move the cursor to the previous word | +| ctrl + → / alt + f | Move the cursor to the next word | +| ctrl + b / ← | Move the cursor to the left | +| ctrl + f / → | Move the cursor to the right | | ctrl + a / home | Move the cursor to the start of the line | | ctrl + e / end | Move the cursor to the end of the line | | ctrl + backspace / ctrl + alt + backspace | Remove the previous word / remove the word just before the cursor | | ctrl + delete / ctrl + alt + delete | Remove the next word or the word just after the cursor | | ctrl + w | Remove the word before the cursor even if it spans across the word boundaries | | ctrl + u | Clear the current line | -| ctrl + n / ctrl + j / ↑ | Select the next item on the list | -| ctrl + p / ctrl + k / ↓ | Select the previous item on the list | +| ctrl + n / ctrl + j / ↑ | Select the next item on the list | +| ctrl + p / ctrl + k / ↓ | Select the previous item on the list | | ctrl + o | Open the [inspector](#inspector) | | page down | Scroll search results one page down | | page up | Scroll search results one page up | -| ↓ (with no entry selected) | Return original or return query depending on [settings](config.md#exit_mode) | -| ↓ | Select the next item on the list | +| ↓ (with no entry selected) | Return original or return query depending on [settings](config.md#exit_mode) | +| ↓ | Select the next item on the list | +| ctrl + a, c | Switch to the context of the currently selected command / return to default | ### Vim mode diff --git a/docs/docs/guide/advanced-usage.md b/docs/docs/guide/advanced-usage.md new file mode 100644 index 00000000..0d5a1359 --- /dev/null +++ b/docs/docs/guide/advanced-usage.md @@ -0,0 +1,49 @@ +# Advanced Usage + +Atuin offers you several options to help navigate through the results. + +## Filter mode + +The command history can be filtered in different ways, letting you narrow the search scope. + +You can cycle through the different modes by pressing **ctrl-r**. + +The available modes are: + +| Mode | Description | +|------------------|--------------------------------------------------------------------------------------| +| global (default) | Search from the full history | +| host | Search history from this host | +| session | Search history from the current session | +| directory | Search history from the current directory | +| workspace | Search history from the current git repository | +| session-preload | Search from the current session and the global history from before the session start | + +See the [`filter_mode` config reference](../configuration/config.md#filter_mode) for more details. + +## Search mode + +Atuin offers different modes to interpret your search query. + +You can cycle through the different modes by pressing **ctrl-s**. + +The available modes are: + +| Mode | Description | +|-----------------|----------------------------------------------------------------------------------------------------------------| +| fuzzy (default) | Search for commands in a fuzzy way, similar to the [fzf syntax](https://github.com/junegunn/fzf#search-syntax) | +| prefix | Commands that start with your query | +| fulltext | Commands that contain your query as a substring | +| skim | Search for commands using the [skim syntax](https://github.com/lotabout/skim#search-syntax) | + +See the [`search_mode` config reference](../configuration/config.md#search_mode) for more details. + +## Context switch + +Atuin uses the current context (host, session, directory) to filter the history when you use a filter mode other than *global*. + +You can switch this context to the one of the currently selected command by pressing **ctrl-a** then **c**. + +This will set the filter mode to *session* and clear the search query, which will show you all the commands executed in the same shell session. + +Pressing this key combination again will return to the initial context. You can customize this behavior by setting [custom key bindings](../configuration/advanced-key-binding.md) to the `switch-context` and `clear-context` commands. `switch-context` can be called several times to navigate through multiple command contexts, while `clear-context` will always return to the initial context. diff --git a/docs/docs/guide/basic-usage.md b/docs/docs/guide/basic-usage.md index 0b40a0aa..f6df1c94 100644 --- a/docs/docs/guide/basic-usage.md +++ b/docs/docs/guide/basic-usage.md @@ -26,6 +26,8 @@ While searching in the TUI, you can adjust the "filter mode" by repeatedly press 3. The current directory only 4. The current shell session only +See the [advanced usage](advanced-usage.md) page for more options. + ## Common config adjustment For a full set of config values, please see the [config reference page](../configuration/config.md). diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 1cbbf30d..4ca51c60 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -63,6 +63,7 @@ nav: - Setting up sync: guide/sync.md - Import existing history: guide/import.md - Basic usage: guide/basic-usage.md + - Advanced usage: guide/advanced-usage.md - Deleting history: guide/delete-history.md - Syncing dotfiles: guide/dotfiles.md - Theming: guide/theming.md |
