diff options
44 files changed, 467 insertions, 911 deletions
@@ -113,14 +113,41 @@ pub struct App { file_to_open: Option<String>, } +pub struct Environment { + pub queue: Queue, + pub theme: SharedTheme, + pub key_config: SharedKeyConfig, + pub repo: RepoPathRef, + pub options: SharedOptions, + pub sender_git: Sender<AsyncGitNotification>, + pub sender_app: Sender<AsyncAppNotification>, +} + +/// The need to construct a "whatever" environment only arises in testing right now +#[cfg(test)] +impl Default for Environment { + fn default() -> Self { + use crossbeam_channel::unbounded; + Self { + queue: Queue::new(), + theme: Default::default(), + key_config: Default::default(), + repo: RefCell::new(RepoPath::Path(Default::default())), + options: Default::default(), + sender_git: unbounded().0, + sender_app: unbounded().0, + } + } +} + // public interface impl App { /// #[allow(clippy::too_many_lines)] pub fn new( repo: RepoPathRef, - sender: &Sender<AsyncGitNotification>, - sender_app: &Sender<AsyncAppNotification>, + sender_git: Sender<AsyncGitNotification>, + sender_app: Sender<AsyncAppNotification>, input: Input, theme: Theme, key_config: KeyConfig, @@ -130,219 +157,66 @@ impl App { let repo_path_text = repo_work_dir(&repo.borrow()).unwrap_or_default(); - let queue = Queue::new(); - let theme = Rc::new(theme); - let key_config = Rc::new(key_config); - let options = Options::new(repo.clone()); + let env = Environment { + queue: Queue::new(), + theme: Rc::new(theme), + key_config: Rc::new(key_config), + options: Options::new(repo.clone()), + repo, + sender_git, + sender_app, + }; - let tab = options.borrow().current_tab(); + let tab = env.options.borrow().current_tab(); let mut app = Self { input, - reset: ConfirmComponent::new( - queue.clone(), - theme.clone(), - key_config.clone(), - ), - commit: CommitComponent::new( - repo.clone(), - queue.clone(), - theme.clone(), - key_config.clone(), - options.clone(), - ), + reset: ConfirmComponent::new(&env), + commit: CommitComponent::new(&env), blame_file_popup: BlameFileComponent::new( - &repo, - &queue, - sender, - &strings::blame_title(&key_config), - theme.clone(), - key_config.clone(), - ), - file_revlog_popup: FileRevlogComponent::new( - &repo, - &queue, - sender, - theme.clone(), - key_config.clone(), - options.clone(), - ), - revision_files_popup: RevisionFilesPopup::new( - repo.clone(), - &queue, - sender_app, - sender.clone(), - theme.clone(), - key_config.clone(), - ), - stashmsg_popup: StashMsgComponent::new( - repo.clone(), - queue.clone(), - theme.clone(), - key_config.clone(), - ), - inspect_commit_popup: InspectCommitComponent::new( - &repo, - &queue, - sender, - theme.clone(), - key_config.clone(), - options.clone(), - ), - compare_commits_popup: CompareCommitsComponent::new( - &repo, - &queue, - sender, - theme.clone(), - key_config.clone(), - options.clone(), - ), - external_editor_popup: ExternalEditorComponent::new( - theme.clone(), - key_config.clone(), - ), - push_popup: PushComponent::new( - &repo, - &queue, - sender, - theme.clone(), - key_config.clone(), - ), - push_tags_popup: PushTagsComponent::new( - &repo, - &queue, - sender, - theme.clone(), - key_config.clone(), - ), - reset_popup: ResetPopupComponent::new( - &queue, - &repo, - theme.clone(), - key_config.clone(), - ), - pull_popup: PullComponent::new( - &repo, - &queue, - sender, - theme.clone(), - key_config.clone(), - ), - fetch_popup: FetchComponent::new( - repo.clone(), - &queue, - sender, - theme.clone(), - key_config.clone(), - ), - tag_commit_popup: TagCommitComponent::new( - repo.clone(), - queue.clone(), - theme.clone(), - key_config.clone(), - ), - create_branch_popup: CreateBranchComponent::new( - repo.clone(), - queue.clone(), - theme.clone(), - key_config.clone(), - ), - rename_branch_popup: RenameBranchComponent::new( - repo.clone(), - queue.clone(), - theme.clone(), - key_config.clone(), - ), - select_branch_popup: BranchListComponent::new( - repo.clone(), - queue.clone(), - theme.clone(), - key_config.clone(), - ), - tags_popup: TagListComponent::new( - repo.clone(), - &queue, - sender, - theme.clone(), - key_config.clone(), - ), - options_popup: OptionsPopupComponent::new( - &queue, - theme.clone(), - key_config.clone(), - options.clone(), - ), - submodule_popup: SubmodulesListComponent::new( - repo.clone(), - &queue, - theme.clone(), - key_config.clone(), - ), - log_search_popup: LogSearchPopupComponent::new( - repo.clone(), - &queue, - theme.clone(), - key_config.clone(), - ), - fuzzy_find_popup: FuzzyFindPopup::new( - &queue, - theme.clone(), - key_config.clone(), + &env, + &strings::blame_title(&env.key_config), ), + file_revlog_popup: FileRevlogComponent::new(&env), + revision_files_popup: RevisionFilesPopup::new(&env), + stashmsg_popup: StashMsgComponent::new(&env), + inspect_commit_popup: InspectCommitComponent::new(&env), + compare_commits_popup: CompareCommitsComponent::new(&env), + external_editor_popup: ExternalEditorComponent::new(&env), + push_popup: PushComponent::new(&env), + push_tags_popup: PushTagsComponent::new(&env), + reset_popup: ResetPopupComponent::new(&env), + pull_popup: PullComponent::new(&env), + fetch_popup: FetchComponent::new(&env), + tag_commit_popup: TagCommitComponent::new(&env), + create_branch_popup: CreateBranchComponent::new(&env), + rename_branch_popup: RenameBranchComponent::new(&env), + select_branch_popup: BranchListComponent::new(&env), + tags_popup: TagListComponent::new(&env), + options_popup: OptionsPopupComponent::new(&env), + submodule_popup: SubmodulesListComponent::new(&env), + log_search_popup: LogSearchPopupComponent::new(&env), + fuzzy_find_popup: FuzzyFindPopup::new(&env), do_quit: QuitState::None, cmdbar: RefCell::new(CommandBar::new( - theme.clone(), - key_config.clone(), + env.theme.clone(), + env.key_config.clone(), )), - help: HelpComponent::new( - theme.clone(), - key_config.clone(), - ), - msg: MsgComponent::new(theme.clone(), key_config.clone()), - revlog: Revlog::new( - &repo, - &queue, - sender, - theme.clone(), - key_config.clone(), - ), - status_tab: Status::new( - repo.clone(), - &queue, - sender, - theme.clone(), - key_config.clone(), - options.clone(), - ), - stashing_tab: Stashing::new( - &repo, - sender, - &queue, - theme.clone(), - key_config.clone(), - ), - stashlist_tab: StashList::new( - repo.clone(), - &queue, - theme.clone(), - key_config.clone(), - ), - files_tab: FilesTab::new( - repo.clone(), - sender_app, - sender.clone(), - &queue, - theme.clone(), - key_config.clone(), - ), + help: HelpComponent::new(&env), + msg: MsgComponent::new(&env), + revlog: Revlog::new(&env), + status_tab: Status::new(&env), + stashing_tab: Stashing::new(&env), + stashlist_tab: StashList::new(&env), + files_tab: FilesTab::new(&env), tab: 0, - queue, - theme, - options, - key_config, + queue: env.queue, + theme: env.theme, + options: env.options, + key_config: env.key_config, requires_redraw: Cell::new(false), file_to_open: None, - repo, + repo: env.repo, repo_path_text, popup_stack: PopupStack::default(), }; diff --git a/src/components/blame_file.rs b/src/components/blame_file.rs index 632006fa..2a86aba5 100644 --- a/src/components/blame_file.rs +++ b/src/components/blame_file.rs @@ -4,6 +4,7 @@ use super::{ InspectCommitOpen, }; use crate::{ + app::Environment, components::{utils::string_width_align, ScrollType}, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, Queue, StackablePopupOpen}, @@ -13,10 +14,9 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ - sync::{BlameHunk, CommitId, FileBlame, RepoPathRef}, + sync::{BlameHunk, CommitId, FileBlame}, AsyncBlame, AsyncGitNotification, BlameParams, }; -use crossbeam_channel::Sender; use crossterm::event::Event; use ratatui::{ backend::Backend, @@ -272,28 +272,21 @@ impl Component for BlameFileComponent { impl BlameFileComponent { /// - pub fn new( - repo: &RepoPathRef, - queue: &Queue, - sender: &Sender<AsyncGitNotification>, - title: &str, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment, title: &str) -> Self { Self { title: String::from(title), - theme, + theme: env.theme.clone(), async_blame: AsyncBlame::new( - repo.borrow().clone(), - sender, + env.repo.borrow().clone(), + &env.sender_git, ), - queue: queue.clone(), + queue: env.queue.clone(), visible: false, params: None, file_blame: None, open_request: None, table_state: std::cell::Cell::new(TableState::default()), - key_config, + key_config: env.key_config.clone(), current_height: std::cell::Cell::new(0), } } diff --git a/src/components/branchlist.rs b/src/components/branchlist.rs index b097ce6d..d3cc147a 100644 --- a/src/components/branchlist.rs +++ b/src/components/branchlist.rs @@ -4,6 +4,7 @@ use super::{ EventState, FuzzyFinderTarget, InspectCommitOpen, }; use crate::{ + app::Environment, components::ScrollType, keys::{key_match, SharedKeyConfig}, queue::{ @@ -329,12 +330,7 @@ impl Component for BranchListComponent { } impl BranchListComponent { - pub fn new( - repo: RepoPathRef, - queue: Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { branches: Vec::new(), local: true, @@ -342,11 +338,11 @@ impl BranchListComponent { visible: false, selection: 0, scroll: VerticalScroll::new(), - queue, - theme, - key_config, + queue: env.queue.clone(), + theme: env.theme.clone(), + key_config: env.key_config.clone(), current_height: Cell::new(0), - repo, + repo: env.repo.clone(), } } diff --git a/src/components/changes.rs b/src/components/changes.rs index 3b573a99..af8d68f0 100644 --- a/src/components/changes.rs +++ b/src/components/changes.rs @@ -4,12 +4,12 @@ use super::{ CommandBlocking, DrawableComponent, }; use crate::{ + app::Environment, components::{CommandInfo, Component, EventState}, keys::{key_match, SharedKeyConfig}, options::SharedOptions, queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem}, strings, try_or_popup, - ui::style::SharedTheme, }; use anyhow::Result; use asyncgit::{ @@ -35,28 +35,18 @@ impl ChangesComponent { //TODO: fix #[allow(clippy::too_many_arguments)] pub fn new( - repo: RepoPathRef, + env: &Environment, title: &str, focus: bool, is_working_dir: bool, - queue: Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - options: SharedOptions, ) -> Self { Self { - files: StatusTreeComponent::new( - title, - focus, - Some(queue.clone()), - theme, - key_config.clone(), - ), + files: StatusTreeComponent::new(env, title, focus), is_working_dir, - queue, - key_config, - options, - repo, + queue: env.queue.clone(), + key_config: env.key_config.clone(), + options: env.options.clone(), + repo: env.repo.clone(), } } diff --git a/src/components/commit.rs b/src/components/commit.rs index bd762878..8a26ecd3 100644 --- a/src/components/commit.rs +++ b/src/components/commit.rs @@ -65,30 +65,25 @@ const FIRST_LINE_LIMIT: usize = 50; impl CommitComponent { /// - pub fn new( - repo: RepoPathRef, - queue: Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - options: SharedOptions, - ) -> Self { + pub fn new(env: &crate::app::Environment) -> Self { Self { - queue, + queue: env.queue.clone(), mode: Mode::Normal, input: TextInputComponent::new( - theme.clone(), - key_config.clone(), + env, "", - &strings::commit_msg(&key_config), + &strings::commit_msg(&env.key_config), true, ), - key_config, - git_branch_name: cached::BranchName::new(repo.clone()), + key_config: env.key_config.clone(), + git_branch_name: cached::BranchName::new( + env.repo.clone(), + ), commit_template: None, - theme, - repo, + theme: env.theme.clone(), + repo: env.repo.clone(), commit_msg_history_idx: 0, - options, + options: env.options.clone(), verify: true, } } diff --git a/src/components/commit_details/compare_details.rs b/src/components/commit_details/compare_details.rs index 015e3ff3..2f184a25 100644 --- a/src/components/commit_details/compare_details.rs +++ b/src/components/commit_details/compare_details.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use crate::{ + app::Environment, components::{ commit_details::style::{style_detail, Detail}, dialog_paragraph, @@ -30,16 +31,12 @@ pub struct CompareDetailsComponent { impl CompareDetailsComponent { /// - pub const fn new( - repo: RepoPathRef, - theme: SharedTheme, - focused: bool, - ) -> Self { + pub fn new(env: &Environment, focused: bool) -> Self { Self { data: None, - theme, + theme: env.theme.clone(), focused, - repo, + repo: env.repo.clone(), } } diff --git a/src/components/commit_details/details.rs b/src/components/commit_details/details.rs index 6c1a86c7..e1bce3fd 100644 --- a/src/components/commit_details/details.rs +++ b/src/components/commit_details/details.rs @@ -1,4 +1,5 @@ use crate::{ + app::Environment, components::{ commit_details::style::style_detail, dialog_paragraph, @@ -45,22 +46,17 @@ type WrappedCommitMessage<'a> = impl DetailsComponent { /// - pub const fn new( - repo: RepoPathRef, - theme: SharedTheme, - key_config: SharedKeyConfig, - focused: bool, - ) -> Self { + pub fn new(env: &Environment, focused: bool) -> Self { Self { - repo, + repo: env.repo.clone(), data: None, tags: Vec::new(), - theme, + theme: env.theme.clone(), focused, scroll_to_bottom_next_draw: Cell::new(false), current_width: Cell::new(0), scroll: VerticalScroll::new(), - key_config, + key_config: env.key_config.clone(), } } diff --git a/src/components/commit_details/mod.rs b/src/components/commit_details/mod.rs index 35317670..2e14aeca 100644 --- a/src/components/commit_details/mod.rs +++ b/src/components/commit_details/mod.rs @@ -8,18 +8,15 @@ use super::{ }; use crate::{ accessors, + app::Environment, keys::{key_match, SharedKeyConfig}, - queue::Queue, strings, - ui::style::SharedTheme, }; use anyhow::Result; use asyncgit::{ - sync::{CommitTags, RepoPathRef}, - AsyncCommitFiles, AsyncGitNotification, CommitFilesParams, + sync::CommitTags, AsyncCommitFiles, CommitFilesParams, }; use compare_details::CompareDetailsComponent; -use crossbeam_channel::Sender; use crossterm::event::Event; use details::DetailsComponent; use ratatui::{ @@ -42,39 +39,18 @@ impl CommitDetailsComponent { accessors!(self, [single_details, compare_details, file_tree]); /// - pub fn new( - repo: &RepoPathRef, - queue: &Queue, - sender: &Sender<AsyncGitNotification>, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - single_details: DetailsComponent::new( - repo.clone(), - theme.clone(), - key_config.clone(), - false, - ), - compare_details: CompareDetailsComponent::new( - repo.clone(), - theme.clone(), - false, - ), + single_details: DetailsComponent::new(env, false), + compare_details: CompareDetailsComponent::new(env, false), git_commit_files: AsyncCommitFiles::new( - repo.borrow().clone(), - sender, - ), - file_tree: StatusTreeComponent::new( - "", - false, - Some(queue.clone()), - theme, - key_config.clone(), + env.repo.borrow().clone(), + &env.sender_git, ), + file_tree: StatusTreeComponent::new(env, "", false), visible: false, commit: None, - key_config, + key_config: env.key_config.clone(), } } diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index 7f9cef3a..9f2956b7 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -1,5 +1,6 @@ use super::utils::logitems::{ItemBatch, LogEntry}; use crate::{ + app::Environment, components::{ utils::string_width_align, CommandBlocking, CommandInfo, Component, DrawableComponent, EventState, ScrollType, @@ -59,15 +60,9 @@ pub struct CommitList { impl CommitList { /// - pub fn new( - repo: RepoPathRef, - title: &str, - theme: SharedTheme, - queue: Queue, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment, title: &str) -> Self { Self { - repo, + repo: env.repo.clone(), items: ItemBatch::default(), marked: Vec::with_capacity(2), selection: 0, @@ -80,9 +75,9 @@ impl CommitList { remote_branches: BTreeMap::default(), current_size: Cell::new(None), scroll_top: Cell::new(0), - theme, - queue, - key_config, + theme: env.theme.clone(), + queue: env.queue.clone(), + key_config: env.key_config.clone(), title: title.into(), } } diff --git a/src/components/compare_commits.rs b/src/components/compare_commits.rs index db5ea23c..49937c58 100644 --- a/src/components/compare_commits.rs +++ b/src/components/compare_commits.rs @@ -5,11 +5,11 @@ use super::{ }; use crate::{ accessors, + app::Environment, keys::{key_match, SharedKeyConfig}, options::SharedOptions, queue::{InternalEvent, Queue, StackablePopupOpen}, strings, - ui::style::SharedTheme, }; use anyhow::Result; use asyncgit::{ @@ -17,7 +17,6 @@ use asyncgit::{ AsyncDiff, AsyncGitNotification, CommitFilesParams, DiffParams, DiffType, }; -use crossbeam_channel::Sender; use crossterm::event::Event; use ratatui::{ backend::Backend, @@ -168,37 +167,20 @@ impl CompareCommitsComponent { accessors!(self, [diff, details]); /// - pub fn new( - repo: &RepoPathRef, - queue: &Queue, - sender: &Sender<AsyncGitNotification>, - theme: SharedTheme, - key_config: SharedKeyConfig, - options: SharedOptions, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - repo: repo.clone(), - details: CommitDetailsComponent::new( - repo, - queue, - sender, - theme.clone(), - key_config.clone(), - ), - diff: DiffComponent::new( - repo.clone(), - queue.clone(), - theme, - key_config.clone(), - true, - options.clone(), - ), + repo: env.repo.clone(), + details: CommitDetailsComponent::new(env), + diff: DiffComponent::new(env, true), open_request: None, |