-
Notifications
You must be signed in to change notification settings - Fork 138
feat: checkout branch/revision with picker #506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,8 +9,10 @@ use crate::{ | |
| }, | ||
| item_data::{ItemData, RefKind}, | ||
| menu::arg::Arg, | ||
| picker::{PickerData, PickerItem, PickerState}, | ||
| term::Term, | ||
| }; | ||
| use itertools::Itertools; | ||
| use std::{process::Command, rc::Rc}; | ||
|
|
||
| pub(crate) fn init_args() -> Vec<Arg> { | ||
|
|
@@ -21,17 +23,57 @@ pub(crate) struct Checkout; | |
| impl OpTrait for Checkout { | ||
| fn get_action(&self, _target: &ItemData) -> Option<Action> { | ||
| Some(Rc::new(move |app: &mut App, term: &mut Term| { | ||
| let rev = app.prompt( | ||
| term, | ||
| &PromptParams { | ||
| prompt: "Checkout", | ||
| create_default_value: Box::new(selected_rev), | ||
| ..Default::default() | ||
| }, | ||
| )?; | ||
| let selected_rev = selected_rev(app); | ||
| // Collect and sort all branches (local and remote) excluding the current branch & | ||
| // selected revision, if there's any. | ||
| let mut branches: Vec<PickerItem> = app | ||
| .state | ||
| .repo | ||
| .branches(None) | ||
| .map_err(Error::ListGitReferences)? | ||
| .filter_map(Result::ok) | ||
| .filter_map(|(branch, _)| { | ||
| if branch.is_head() { | ||
| return None; | ||
| } | ||
|
|
||
| let name = branch.name().ok()??; | ||
|
|
||
| // Filter out selected rev, as it will be added to the top | ||
| // below. | ||
| if let Some(ref rev) = selected_rev | ||
| && rev == name | ||
| { | ||
| return None; | ||
| } | ||
|
|
||
| // Remote is only used for sorting | ||
| Some((branch.get().is_remote(), name.to_string())) | ||
| }) | ||
| .sorted() | ||
| .map(|(_remote, branch_name)| { | ||
| PickerItem::new(branch_name.clone(), PickerData::Revision(branch_name)) | ||
| }) | ||
| .collect(); | ||
|
|
||
| // If this action was started from a selected revision, push it to the | ||
| // to the top, so it's selected by default and can be accepted by <enter> | ||
| // without any extra steps. | ||
| if let Some(rev) = selected_rev { | ||
| branches.insert(0, PickerItem::new(rev.clone(), PickerData::Revision(rev))); | ||
| } | ||
|
|
||
| checkout(app, term, &rev)?; | ||
| Ok(()) | ||
| // Allow custom input to support checking out other revisions not in the list | ||
| let picker = PickerState::new("Checkout", branches, true); | ||
| match app.picker(term, picker)? { | ||
| Some(data) => checkout(app, term, data.display()), | ||
| None => { | ||
| // TODO: necessary to make sure parent menu closes, shouldn't this be | ||
| // handled by .picker, like .prompt does? | ||
| app.close_menu(); | ||
|
Comment on lines
+71
to
+73
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, it should close down everything when aborted.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want I can make an extra commit to fix this as the first commit on this PR
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good! |
||
| Ok(()) | ||
| } | ||
| } | ||
| })) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| --- | ||
| source: src/tests/branch.rs | ||
| expression: ctx.redact_buffer() | ||
| --- | ||
| On branch main | | ||
| Your branch is up to date with 'origin/main'. | | ||
| | | ||
| Recent commits | | ||
| b66a0bf main merged origin/main add initial-file | | ||
| | | ||
| | | ||
| | | ||
| ────────────────────────────────────────────────────────────────────────────────| | ||
| 4/4 Checkout › █ | | ||
| ▌merged | | ||
| unmerged | | ||
| origin/HEAD | | ||
| origin/main | | ||
| | | ||
| | | ||
| | | ||
| | | ||
| | | ||
| | | ||
| styles_hash: a64f5b0f5c87b3e5 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| --- | ||
| source: src/tests/branch.rs | ||
| expression: ctx.redact_buffer() | ||
| --- | ||
| Branches | | ||
| * main | | ||
| merged | | ||
| unmerged | | ||
| | | ||
| Remote origin | | ||
| origin/HEAD | | ||
| origin/main | | ||
| ────────────────────────────────────────────────────────────────────────────────| | ||
| 4/4 Checkout › █ | | ||
| ▌merged | | ||
| unmerged | | ||
| origin/HEAD | | ||
| origin/main | | ||
| | | ||
| | | ||
| | | ||
| | | ||
| | | ||
| | | ||
| styles_hash: 2cac6f3d25b0271c |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's similar logic in
src/ops/merge.rsnow from the other usage of the Picker.To me, I think these two should probably behave exactly the same. So perhaps let's settle on one behaviour of listing revs, and re-use that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I saw that. If the other PR is merged, I can probably make use of that function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I merged it in yesterday finally! :)