Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/default-keybind.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ go_to_previous = ["shift-n"]
confirm = ["enter"]
ref_list = ["tab"]
search = ["/"]
search_target_toggle = ["ctrl-t"]
ignore_case_toggle = ["ctrl-g"]
fuzzy_toggle = ["ctrl-x"]
refresh = ["shift-r"]
Expand Down
15 changes: 15 additions & 0 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@
"type": "object",
"description": "Default search settings",
"properties": {
"target": {
"type": "string",
"description": "The field to search by default.",
"enum": [
"all",
"subject",
"author",
"ref",
"hash"
],
"default": "all"
},
"ignore_case": {
"type": "boolean",
"description": "Whether to enable ignore case by default.",
Expand Down Expand Up @@ -661,6 +673,9 @@
"search": {
"$ref": "#/definitions/keybindArray"
},
"search_target_toggle": {
"$ref": "#/definitions/keybindArray"
},
"ignore_case_toggle": {
"$ref": "#/definitions/keybindArray"
},
Expand Down
14 changes: 14 additions & 0 deletions docs/src/configurations/config-file-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ initial_selection = "latest"
mailmap = false

[core.search]
target = "all"
ignore_case = false
fuzzy = false

Expand Down Expand Up @@ -194,6 +195,19 @@ The width mode for each graph row image.
- `fixed`: use the same full graph width for every row image
- This can be used when you want to set a background color for graphs in environments that cannot correctly handle transparent images, or in environments where rendering does not work well when there are images of various widths.

### `core.search.target`

The field to search when the application starts. The target can be toggled while the commit list is displayed.

- type: `string` (enum)
- default: `all`
- possible values:
- `all`: Search refs, commit subjects, author names, and short commit hashes
- `subject`: Search commit subjects
- `author`: Search author names
- `ref`: Search branch, remote branch, and tag names
- `hash`: Search short commit hashes

### `core.search.ignore_case`

Whether to enable ignore case when the application starts. The option can be toggled while the commit list is displayed.
Expand Down
1 change: 1 addition & 0 deletions docs/src/keybindings/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ The default key bindings can be overridden.
| <kbd>/</kbd> | Start search | `search` |
| <kbd>Esc</kbd> | Cancel search | `cancel` |
| <kbd>n/N</kbd> | Go to next/previous search match | `go_to_next` `go_to_previous` |
| <kbd>Ctrl-t</kbd> | Toggle search target | `search_target_toggle` |
| <kbd>Ctrl-g</kbd> | Toggle ignore case | `ignore_case_toggle` |
| <kbd>Ctrl-x</kbd> | Toggle fuzzy match | `fuzzy_toggle` |
| <kbd>R</kbd> | Refresh | `refresh` |
Expand Down
8 changes: 6 additions & 2 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::{
graph::{CellWidthType, Graph, GraphImageManager},
keybind::KeyBind,
protocol::ImageProtocol,
search::SearchOptions,
view::{RefreshViewContext, View},
widget::commit_list::{CommitInfo, CommitListState},
};
Expand Down Expand Up @@ -127,8 +128,11 @@ impl<'a> App<'a> {
graph_cell_width,
head,
ref_name_to_commit_index_map,
ctx.core_config.search.ignore_case,
ctx.core_config.search.fuzzy,
SearchOptions {
target: ctx.core_config.search.target,
ignore_case: ctx.core_config.search.ignore_case,
fuzzy: ctx.core_config.search.fuzzy,
},
);
if let InitialSelection::Head = initial_selection {
match repository.head() {
Expand Down
7 changes: 7 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{
color::{ColorTheme, OptionalColorTheme},
graph::GraphImageWidthMode,
keybind::KeyBind,
search::SearchTarget,
CommitOrderType, GraphStyle, GraphWidthType, ImageProtocolType, InitialSelection, Result,
};

Expand Down Expand Up @@ -142,6 +143,8 @@ pub struct CoreGitConfig {
#[optional(derives = [Deserialize])]
#[derive(Debug, Clone, PartialEq, Eq, SmartDefault)]
pub struct CoreSearchConfig {
#[default(SearchTarget::All)]
pub target: SearchTarget,
#[default = false]
pub ignore_case: bool,
#[default = false]
Expand Down Expand Up @@ -449,6 +452,7 @@ mod tests {
},
git: CoreGitConfig { mailmap: false },
search: CoreSearchConfig {
target: SearchTarget::All,
ignore_case: false,
fuzzy: false,
},
Expand Down Expand Up @@ -535,6 +539,7 @@ mod tests {
[core.git]
mailmap = true
[core.search]
target = "author"
ignore_case = true
fuzzy = true
[core.user_command]
Expand Down Expand Up @@ -579,6 +584,7 @@ mod tests {
},
git: CoreGitConfig { mailmap: true },
search: CoreSearchConfig {
target: SearchTarget::Author,
ignore_case: true,
fuzzy: true,
},
Expand Down Expand Up @@ -691,6 +697,7 @@ mod tests {
},
git: CoreGitConfig { mailmap: false },
search: CoreSearchConfig {
target: SearchTarget::All,
ignore_case: false,
fuzzy: false,
},
Expand Down
2 changes: 2 additions & 0 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ pub enum UserEvent {
RefList,
Search,
UserCommand(usize),
SearchTargetToggle,
IgnoreCaseToggle,
FuzzyToggle,
Refresh,
Expand Down Expand Up @@ -292,6 +293,7 @@ impl<'de> Deserialize<'de> for UserEvent {
"confirm" => Ok(UserEvent::Confirm),
"ref_list" | "ref_list_toggle" => Ok(UserEvent::RefList),
"search" => Ok(UserEvent::Search),
"search_target_toggle" => Ok(UserEvent::SearchTargetToggle),
"ignore_case_toggle" => Ok(UserEvent::IgnoreCaseToggle),
"fuzzy_toggle" => Ok(UserEvent::FuzzyToggle),
"refresh" => Ok(UserEvent::Refresh),
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod git;
mod graph;
mod keybind;
mod protocol;
mod search;
mod view;
mod widget;

Expand Down
86 changes: 86 additions & 0 deletions src/search.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use serde::Deserialize;

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SearchTarget {
#[default]
All,
Subject,
Author,
Ref,
Hash,
}

impl SearchTarget {
pub fn next(self) -> Self {
match self {
Self::All => Self::Subject,
Self::Subject => Self::Author,
Self::Author => Self::Ref,
Self::Ref => Self::Hash,
Self::Hash => Self::All,
}
}

fn as_str(self) -> &'static str {
match self {
Self::All => "all",
Self::Subject => "subject",
Self::Author => "author",
Self::Ref => "ref",
Self::Hash => "hash",
}
}
}

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct SearchOptions {
pub target: SearchTarget,
pub ignore_case: bool,
pub fuzzy: bool,
}

impl SearchOptions {
pub fn status_string(&self) -> String {
let case = if self.ignore_case {
"ignore-case"
} else {
"case-sensitive"
};
let matcher = if self.fuzzy { "fuzzy" } else { "substring" };
format!("[{}] [{case}] [{matcher}]", self.target.as_str())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_search_target_next_cycles_through_all_targets() {
let mut target = SearchTarget::All;
let expected = [
SearchTarget::Subject,
SearchTarget::Author,
SearchTarget::Ref,
SearchTarget::Hash,
SearchTarget::All,
];

for expected_target in expected {
target = target.next();
assert_eq!(target, expected_target);
}
}

#[test]
fn test_search_options_status_string() {
let options = SearchOptions {
target: SearchTarget::Author,
ignore_case: true,
fuzzy: true,
};

assert_eq!(options.status_string(), "[author] [ignore-case] [fuzzy]");
}
}
1 change: 1 addition & 0 deletions src/view/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ fn build_lines(
(vec![UserEvent::Cancel], "Cancel search".into()),
(vec![UserEvent::GoToNext], "Go to next search match".into()),
(vec![UserEvent::GoToPrevious], "Go to previous search match".into()),
(vec![UserEvent::SearchTargetToggle], "Toggle search target".into()),
(vec![UserEvent::IgnoreCaseToggle], "Toggle ignore case".into()),
(vec![UserEvent::FuzzyToggle], "Toggle fuzzy match".into()),
(vec![UserEvent::Refresh], "Refresh".into()),
Expand Down
8 changes: 8 additions & 0 deletions src/view/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ impl<'a> ListView<'a> {
self.as_mut_list_state().cancel_search();
self.clear_search_query();
}
UserEvent::SearchTargetToggle => {
self.as_mut_list_state().toggle_search_target();
self.update_search_status();
}
UserEvent::IgnoreCaseToggle => {
self.as_mut_list_state().toggle_ignore_case();
self.update_search_status();
Expand Down Expand Up @@ -133,6 +137,10 @@ impl<'a> ListView<'a> {
self.as_mut_list_state().start_search();
self.update_search_status();
}
UserEvent::SearchTargetToggle => {
self.as_mut_list_state().toggle_search_target();
self.update_search_options_message();
}
UserEvent::IgnoreCaseToggle => {
self.as_mut_list_state().toggle_ignore_case();
self.update_search_options_message();
Expand Down
3 changes: 2 additions & 1 deletion src/view/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ use crate::{
app::AppContext,
event::{Sender, UserEventWithCount},
git::{Commit, FileChange, Ref},
search::SearchOptions,
view::{
detail::DetailView, help::HelpView, list::ListView, refs::RefsView,
user_command::UserCommandView,
},
widget::commit_list::{CommitListState, SearchOptions, SearchRefreshContext},
widget::commit_list::{CommitListState, SearchRefreshContext},
};

#[derive(Debug, Default)]
Expand Down
Loading