diff --git a/src/app.rs b/src/app.rs index 2bdb2754ef..3278d0bfa0 100644 --- a/src/app.rs +++ b/src/app.rs @@ -113,14 +113,41 @@ pub struct App { file_to_open: Option, } +pub struct Environment { + pub queue: Queue, + pub theme: SharedTheme, + pub key_config: SharedKeyConfig, + pub repo: RepoPathRef, + pub options: SharedOptions, + pub sender_git: Sender, + pub sender_app: Sender, +} + +/// 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, - sender_app: &Sender, + sender_git: Sender, + sender_app: Sender, 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 632006fa6e..2a86aba5cd 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, - 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 b097ce6d89..d3cc147a12 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 3b573a9910..af8d68f0c7 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 ba32394a74..941b0b7a92 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 015e3ff37f..2f184a256c 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 6c1a86c7a5..e1bce3fd9c 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 35317670e5..2e14aecace 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, - 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 7f9cef3afe..9f2956b720 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 db5ea23c93..49937c586a 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, - 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, - git_diff: AsyncDiff::new(repo.borrow().clone(), sender), + git_diff: AsyncDiff::new( + env.repo.borrow().clone(), + &env.sender_git, + ), visible: false, - key_config, - queue: queue.clone(), - options, + key_config: env.key_config.clone(), + queue: env.queue.clone(), + options: env.options.clone(), } } diff --git a/src/components/create_branch.rs b/src/components/create_branch.rs index c81a45b66a..c1a30b81db 100644 --- a/src/components/create_branch.rs +++ b/src/components/create_branch.rs @@ -4,6 +4,7 @@ use super::{ EventState, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, NeedsUpdate, Queue}, strings, @@ -95,24 +96,18 @@ impl Component for CreateBranchComponent { impl CreateBranchComponent { /// - pub fn new( - repo: RepoPathRef, - queue: Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - queue, + queue: env.queue.clone(), input: TextInputComponent::new( - theme.clone(), - key_config.clone(), - &strings::create_branch_popup_title(&key_config), - &strings::create_branch_popup_msg(&key_config), + env, + &strings::create_branch_popup_title(&env.key_config), + &strings::create_branch_popup_msg(&env.key_config), true, ), - theme, - key_config, - repo, + theme: env.theme.clone(), + key_config: env.key_config.clone(), + repo: env.repo.clone(), } } diff --git a/src/components/cred.rs b/src/components/cred.rs index 7cecc85acd..f801a5508d 100644 --- a/src/components/cred.rs +++ b/src/components/cred.rs @@ -4,6 +4,7 @@ use ratatui::{backend::Backend, layout::Rect, Frame}; use asyncgit::sync::cred::BasicAuthCredential; +use crate::app::Environment; use crate::components::{EventState, InputType, TextInputComponent}; use crate::keys::key_match; use crate::{ @@ -13,7 +14,6 @@ use crate::{ }, keys::SharedKeyConfig, strings, - ui::style::SharedTheme, }; /// @@ -27,23 +27,19 @@ pub struct CredComponent { impl CredComponent { /// - pub fn new( - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { + let key_config = env.key_config.clone(); Self { visible: false, input_username: TextInputComponent::new( - theme.clone(), - key_config.clone(), + env, &strings::username_popup_title(&key_config), &strings::username_popup_msg(&key_config), false, ) .with_input_type(InputType::Singleline), input_password: TextInputComponent::new( - theme, - key_config.clone(), + env, &strings::password_popup_title(&key_config), &strings::password_popup_msg(&key_config), false, diff --git a/src/components/diff.rs b/src/components/diff.rs index 6a2d433af1..557ce9d890 100644 --- a/src/components/diff.rs +++ b/src/components/diff.rs @@ -4,6 +4,7 @@ use super::{ Direction, DrawableComponent, HorizontalScrollType, ScrollType, }; use crate::{ + app::Environment, components::{CommandInfo, Component, EventState}, keys::{key_match, SharedKeyConfig}, options::SharedOptions, @@ -123,17 +124,10 @@ pub struct DiffComponent { impl DiffComponent { /// - pub fn new( - repo: RepoPathRef, - queue: Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - is_immutable: bool, - options: SharedOptions, - ) -> Self { + pub fn new(env: &Environment, is_immutable: bool) -> Self { Self { focused: false, - queue, + queue: env.queue.clone(), current: Current::default(), pending: false, selected_hunk: None, @@ -143,11 +137,11 @@ impl DiffComponent { selection: Selection::Single(0), vertical_scroll: VerticalScroll::new(), horizontal_scroll: HorizontalScroll::new(), - theme, - key_config, + theme: env.theme.clone(), + key_config: env.key_config.clone(), is_immutable, - repo, - options, + repo: env.repo.clone(), + options: env.options.clone(), } } /// diff --git a/src/components/externaleditor.rs b/src/components/externaleditor.rs index 61d41e8557..b343a9b79b 100644 --- a/src/components/externaleditor.rs +++ b/src/components/externaleditor.rs @@ -1,4 +1,5 @@ use crate::{ + app::Environment, components::{ visibility_blocking, CommandBlocking, CommandInfo, Component, DrawableComponent, EventState, @@ -36,14 +37,11 @@ pub struct ExternalEditorComponent { impl ExternalEditorComponent { /// - pub fn new( - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { visible: false, - theme, - key_config, + theme: env.theme.clone(), + key_config: env.key_config.clone(), } } diff --git a/src/components/fetch.rs b/src/components/fetch.rs index 80edaf642f..d8a154ab1b 100644 --- a/src/components/fetch.rs +++ b/src/components/fetch.rs @@ -1,4 +1,5 @@ use crate::{ + app::Environment, components::{ cred::CredComponent, visibility_blocking, CommandBlocking, CommandInfo, Component, DrawableComponent, EventState, @@ -20,7 +21,7 @@ use asyncgit::{ }, AsyncFetchJob, AsyncGitNotification, ProgressPercent, }; -use crossbeam_channel::Sender; + use crossterm::event::Event; use ratatui::{ backend::Backend, @@ -45,26 +46,17 @@ pub struct FetchComponent { impl FetchComponent { /// - pub fn new( - repo: RepoPathRef, - queue: &Queue, - sender: &Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - queue: queue.clone(), + queue: env.queue.clone(), pending: false, visible: false, - async_fetch: AsyncSingleJob::new(sender.clone()), + async_fetch: AsyncSingleJob::new(env.sender_git.clone()), progress: None, - input_cred: CredComponent::new( - theme.clone(), - key_config.clone(), - ), - theme, - key_config, - repo, + input_cred: CredComponent::new(env), + theme: env.theme.clone(), + key_config: env.key_config.clone(), + repo: env.repo.clone(), } } diff --git a/src/components/file_revlog.rs b/src/components/file_revlog.rs index 6ce4eeace1..2366ebda15 100644 --- a/src/components/file_revlog.rs +++ b/src/components/file_revlog.rs @@ -1,5 +1,6 @@ use super::utils::logitems::ItemBatch; use super::{visibility_blocking, BlameFileOpen, InspectCommitOpen}; +use crate::app::Environment; use crate::keys::key_match; use crate::options::SharedOptions; use crate::queue::StackablePopupOpen; @@ -70,41 +71,27 @@ pub struct FileRevlogComponent { impl FileRevlogComponent { /// - pub fn new( - repo_path: &RepoPathRef, - queue: &Queue, - sender: &Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - options: SharedOptions, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - theme: theme.clone(), - queue: queue.clone(), - sender: sender.clone(), - diff: DiffComponent::new( - repo_path.clone(), - queue.clone(), - theme, - key_config.clone(), - true, - options.clone(), - ), + theme: env.theme.clone(), + queue: env.queue.clone(), + sender: env.sender_git.clone(), + diff: DiffComponent::new(env, true), git_log: None, git_diff: AsyncDiff::new( - repo_path.borrow().clone(), - sender, + env.repo.borrow().clone(), + &env.sender_git, ), visible: false, - repo_path: repo_path.clone(), + repo_path: env.repo.clone(), open_request: None, table_state: std::cell::Cell::new(TableState::default()), items: ItemBatch::default(), count_total: 0, - key_config, + key_config: env.key_config.clone(), current_width: std::cell::Cell::new(0), current_height: std::cell::Cell::new(0), - options, + options: env.options.clone(), } } diff --git a/src/components/fuzzy_find_popup.rs b/src/components/fuzzy_find_popup.rs index cb9bfd8ace..1bc9b05220 100644 --- a/src/components/fuzzy_find_popup.rs +++ b/src/components/fuzzy_find_popup.rs @@ -4,6 +4,7 @@ use super::{ TextInputComponent, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, Queue}, string_utils::trim_length_left, @@ -39,30 +40,21 @@ pub struct FuzzyFindPopup { impl FuzzyFindPopup { /// - pub fn new( - queue: &Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { - let mut find_text = TextInputComponent::new( - theme.clone(), - key_config.clone(), - "", - "start typing..", - false, - ); + pub fn new(env: &Environment) -> Self { + let mut find_text = + TextInputComponent::new(env, "", "start typing..", false); find_text.embed(); Self { - queue: queue.clone(), + queue: env.queue.clone(), visible: false, query: None, find_text, - theme, + theme: env.theme.clone(), contents: Vec::new(), filtered: Vec::new(), selected_index: None, - key_config, + key_config: env.key_config.clone(), selection: 0, target: None, } diff --git a/src/components/help.rs b/src/components/help.rs index 6fd6eee62c..314e1a9d06 100644 --- a/src/components/help.rs +++ b/src/components/help.rs @@ -3,6 +3,7 @@ use super::{ DrawableComponent, EventState, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, strings, ui, version::Version, @@ -167,16 +168,13 @@ impl Component for HelpComponent { } impl HelpComponent { - pub const fn new( - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { cmds: vec![], visible: false, selection: 0, - theme, - key_config, + theme: env.theme.clone(), + key_config: env.key_config.clone(), } } /// diff --git a/src/components/inspect_commit.rs b/src/components/inspect_commit.rs index 664e6c2d03..1d737e696a 100644 --- a/src/components/inspect_commit.rs +++ b/src/components/inspect_commit.rs @@ -5,18 +5,17 @@ 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::{ - sync::{CommitId, CommitTags, RepoPathRef}, + sync::{CommitId, CommitTags}, AsyncDiff, AsyncGitNotification, DiffParams, DiffType, }; -use crossbeam_channel::Sender; use crossterm::event::Event; use ratatui::{ backend::Backend, @@ -204,36 +203,19 @@ impl InspectCommitComponent { accessors!(self, [diff, details]); /// - pub fn new( - repo: &RepoPathRef, - queue: &Queue, - sender: &Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - options: SharedOptions, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - queue: queue.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(), - ), + queue: env.queue.clone(), + details: CommitDetailsComponent::new(env), + diff: DiffComponent::new(env, true), open_request: None, - git_diff: AsyncDiff::new(repo.borrow().clone(), sender), + git_diff: AsyncDiff::new( + env.repo.borrow().clone(), + &env.sender_git, + ), visible: false, - key_config, - options, + key_config: env.key_config.clone(), + options: env.options.clone(), } } diff --git a/src/components/log_search_popup.rs b/src/components/log_search_popup.rs index 3f90a0d07b..f8f29ec836 100644 --- a/src/components/log_search_popup.rs +++ b/src/components/log_search_popup.rs @@ -3,6 +3,7 @@ use super::{ DrawableComponent, EventState, TextInputComponent, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, Queue}, strings::{self, POPUP_COMMIT_SHA_INVALID}, @@ -55,33 +56,23 @@ pub struct LogSearchPopupComponent { impl LogSearchPopupComponent { /// - pub fn new( - repo: RepoPathRef, - queue: &Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { - let mut find_text = TextInputComponent::new( - theme.clone(), - key_config.clone(), - "", - "search text", - false, - ); + pub fn new(env: &Environment) -> Self { + let mut find_text = + TextInputComponent::new(env, "", "search text", false); find_text.embed(); find_text.enabled(true); Self { - repo, - queue: queue.clone(), + repo: env.repo.clone(), + queue: env.queue.clone(), visible: false, mode: PopupMode::Search, - key_config, + key_config: env.key_config.clone(), options: ( SearchFields::default(), SearchOptions::default(), ), - theme, + theme: env.theme.clone(), find_text, selection: Selection::EnterText, jump_commit_id: None, diff --git a/src/components/msg.rs b/src/components/msg.rs index 31cb5c3724..e78765052e 100644 --- a/src/components/msg.rs +++ b/src/components/msg.rs @@ -3,6 +3,7 @@ use super::{ DrawableComponent, EventState, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, strings, ui, }; @@ -121,16 +122,13 @@ impl Component for MsgComponent { } impl MsgComponent { - pub const fn new( - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { title: String::new(), msg: String::new(), visible: false, - theme, - key_config, + theme: env.theme.clone(), + key_config: env.key_config.clone(), } } diff --git a/src/components/options_popup.rs b/src/components/options_popup.rs index 73b4e5c23e..c654ad1a4f 100644 --- a/src/components/options_popup.rs +++ b/src/components/options_popup.rs @@ -3,6 +3,7 @@ use super::{ DrawableComponent, EventState, }; use crate::{ + app::Environment, components::utils::string_width_align, keys::{key_match, SharedKeyConfig}, options::SharedOptions, @@ -41,19 +42,14 @@ pub struct OptionsPopupComponent { impl OptionsPopupComponent { /// - pub fn new( - queue: &Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - options: SharedOptions, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { selection: AppOption::StatusShowUntracked, - queue: queue.clone(), + queue: env.queue.clone(), visible: false, - key_config, - options, - theme, + key_config: env.key_config.clone(), + options: env.options.clone(), + theme: env.theme.clone(), } } diff --git a/src/components/pull.rs b/src/components/pull.rs index 76c91414f0..e9f42e6874 100644 --- a/src/components/pull.rs +++ b/src/components/pull.rs @@ -1,5 +1,6 @@ use super::PushComponent; use crate::{ + app::Environment, components::{ cred::CredComponent, visibility_blocking, CommandBlocking, CommandInfo, Component, DrawableComponent, EventState, @@ -21,7 +22,7 @@ use asyncgit::{ }, AsyncGitNotification, AsyncPull, FetchRequest, RemoteProgress, }; -use crossbeam_channel::Sender; + use crossterm::event::Event; use ratatui::{ backend::Backend, @@ -47,27 +48,21 @@ pub struct PullComponent { impl PullComponent { /// - pub fn new( - repo: &RepoPathRef, - queue: &Queue, - sender: &Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - repo: repo.clone(), - queue: queue.clone(), + repo: env.repo.clone(), + queue: env.queue.clone(), pending: false, visible: false, branch: String::new(), - git_fetch: AsyncPull::new(repo.borrow().clone(), sender), - progress: None, - input_cred: CredComponent::new( - theme.clone(), - key_config.clone(), + git_fetch: AsyncPull::new( + env.repo.borrow().clone(), + &env.sender_git, ), - theme, - key_config, + progress: None, + input_cred: CredComponent::new(env), + theme: env.theme.clone(), + key_config: env.key_config.clone(), } } diff --git a/src/components/push.rs b/src/components/push.rs index e272cefe1b..33f445855f 100644 --- a/src/components/push.rs +++ b/src/components/push.rs @@ -1,4 +1,5 @@ use crate::{ + app::Environment, components::{ cred::CredComponent, visibility_blocking, CommandBlocking, CommandInfo, Component, DrawableComponent, EventState, @@ -20,7 +21,6 @@ use asyncgit::{ AsyncGitNotification, AsyncPush, PushRequest, PushType, RemoteProgress, RemoteProgressState, }; -use crossbeam_channel::Sender; use crossterm::event::Event; use ratatui::{ backend::Backend, @@ -66,29 +66,23 @@ pub struct PushComponent { impl PushComponent { /// - pub fn new( - repo: &RepoPathRef, - queue: &Queue, - sender: &Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - repo: repo.clone(), - queue: queue.clone(), + repo: env.repo.clone(), + queue: env.queue.clone(), modifier: PushComponentModifier::None, pending: false, visible: false, branch: String::new(), push_type: PushType::Branch, - git_push: AsyncPush::new(repo.borrow().clone(), sender), - progress: None, - input_cred: CredComponent::new( - theme.clone(), - key_config.clone(), + git_push: AsyncPush::new( + env.repo.borrow().clone(), + &env.sender_git, ), - theme, - key_config, + progress: None, + input_cred: CredComponent::new(env), + theme: env.theme.clone(), + key_config: env.key_config.clone(), } } diff --git a/src/components/push_tags.rs b/src/components/push_tags.rs index 89668c807e..d2a8f9962b 100644 --- a/src/components/push_tags.rs +++ b/src/components/push_tags.rs @@ -1,4 +1,5 @@ use crate::{ + app::Environment, components::{ cred::CredComponent, visibility_blocking, CommandBlocking, CommandInfo, Component, DrawableComponent, EventState, @@ -20,7 +21,6 @@ use asyncgit::{ }, AsyncGitNotification, AsyncPushTags, PushTagsRequest, }; -use crossbeam_channel::Sender; use crossterm::event::Event; use ratatui::{ backend::Backend, @@ -45,29 +45,20 @@ pub struct PushTagsComponent { impl PushTagsComponent { /// - pub fn new( - repo: &RepoPathRef, - queue: &Queue, - sender: &Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - repo: repo.clone(), - queue: queue.clone(), + repo: env.repo.clone(), + queue: env.queue.clone(), pending: false, visible: false, git_push: AsyncPushTags::new( - repo.borrow().clone(), - sender, + env.repo.borrow().clone(), + &env.sender_git, ), progress: None, - input_cred: CredComponent::new( - theme.clone(), - key_config.clone(), - ), - theme, - key_config, + input_cred: CredComponent::new(env), + theme: env.theme.clone(), + key_config: env.key_config.clone(), } } diff --git a/src/components/rename_branch.rs b/src/components/rename_branch.rs index a9963091f4..e43988884a 100644 --- a/src/components/rename_branch.rs +++ b/src/components/rename_branch.rs @@ -4,10 +4,10 @@ use super::{ EventState, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, NeedsUpdate, Queue}, strings, - ui::style::SharedTheme, }; use anyhow::Result; use asyncgit::sync::{self, RepoPathRef}; @@ -89,24 +89,18 @@ impl Component for RenameBranchComponent { impl RenameBranchComponent { /// - pub fn new( - repo: RepoPathRef, - queue: Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - repo, - queue, + repo: env.repo.clone(), + queue: env.queue.clone(), input: TextInputComponent::new( - theme, - key_config.clone(), - &strings::rename_branch_popup_title(&key_config), - &strings::rename_branch_popup_msg(&key_config), + env, + &strings::rename_branch_popup_title(&env.key_config), + &strings::rename_branch_popup_msg(&env.key_config), true, ), branch_ref: None, - key_config, + key_config: env.key_config.clone(), } } diff --git a/src/components/reset.rs b/src/components/reset.rs index aa8cd1dd78..51d4781a94 100644 --- a/src/components/reset.rs +++ b/src/components/reset.rs @@ -1,4 +1,5 @@ use crate::{ + app::Environment, components::{ popup_paragraph, visibility_blocking, CommandBlocking, CommandInfo, Component, DrawableComponent, EventState, @@ -103,17 +104,13 @@ impl Component for ConfirmComponent { impl ConfirmComponent { /// - pub fn new( - queue: Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { target: None, visible: false, - queue, - theme, - key_config, + queue: env.queue.clone(), + theme: env.theme.clone(), + key_config: env.key_config.clone(), } } /// diff --git a/src/components/reset_popup.rs b/src/components/reset_popup.rs index a3b4842827..f384a418b5 100644 --- a/src/components/reset_popup.rs +++ b/src/components/reset_popup.rs @@ -3,6 +3,7 @@ use super::{ DrawableComponent, EventState, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::Queue, strings, try_or_popup, @@ -11,7 +12,7 @@ use crate::{ use anyhow::Result; use asyncgit::{ cached, - sync::{CommitId, RepoPath, RepoPathRef, ResetType}, + sync::{CommitId, RepoPath, ResetType}, }; use crossterm::event::Event; use ratatui::{ @@ -52,21 +53,18 @@ pub struct ResetPopupComponent { impl ResetPopupComponent { /// - pub fn new( - queue: &Queue, - repo: &RepoPathRef, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - queue: queue.clone(), - repo: repo.borrow().clone(), + queue: env.queue.clone(), + repo: env.repo.borrow().clone(), commit: None, kind: ResetType::Soft, - git_branch_name: cached::BranchName::new(repo.clone()), + git_branch_name: cached::BranchName::new( + env.repo.clone(), + ), visible: false, - key_config, - theme, + key_config: env.key_config.clone(), + theme: env.theme.clone(), } } diff --git a/src/components/revision_files.rs b/src/components/revision_files.rs index ee28cb2487..ef1b0297ea 100644 --- a/src/components/revision_files.rs +++ b/src/components/revision_files.rs @@ -4,12 +4,13 @@ use super::{ EventState, FileRevOpen, FuzzyFinderTarget, SyntaxTextComponent, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, Queue, StackablePopupOpen}, strings::{self, order, symbol}, try_or_popup, ui::{self, common_nav, style::SharedTheme}, - AsyncAppNotification, AsyncNotification, + AsyncNotification, }; use anyhow::Result; use asyncgit::{ @@ -19,7 +20,6 @@ use asyncgit::{ }, AsyncGitNotification, AsyncTreeFilesJob, }; -use crossbeam_channel::Sender; use crossterm::event::Event; use filetreelist::{FileTree, FileTreeItem}; use ratatui::{ @@ -57,31 +57,21 @@ pub struct RevisionFilesComponent { impl RevisionFilesComponent { /// - pub fn new( - repo: RepoPathRef, - queue: &Queue, - sender: &Sender, - sender_git: Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - queue: queue.clone(), + queue: env.queue.clone(), tree: FileTree::default(), scroll: VerticalScroll::new(), - current_file: SyntaxTextComponent::new( - repo.clone(), - sender, - key_config.clone(), - theme.clone(), - ), - async_treefiles: AsyncSingleJob::new(sender_git), - theme, + current_file: SyntaxTextComponent::new(env), + theme: env.theme.clone(), files: None, + async_treefiles: AsyncSingleJob::new( + env.sender_git.clone(), + ), revision: None, focus: Focus::Tree, - key_config, - repo, + key_config: env.key_config.clone(), + repo: env.repo.clone(), visible: false, } } diff --git a/src/components/revision_files_popup.rs b/src/components/revision_files_popup.rs index 19b762d268..809c960acf 100644 --- a/src/components/revision_files_popup.rs +++ b/src/components/revision_files_popup.rs @@ -6,18 +6,14 @@ use super::{ EventState, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, Queue, StackablePopupOpen}, strings::{self}, - ui::style::SharedTheme, - AsyncAppNotification, AsyncNotification, + AsyncNotification, }; use anyhow::Result; -use asyncgit::{ - sync::{CommitId, RepoPathRef}, - AsyncGitNotification, -}; -use crossbeam_channel::Sender; +use asyncgit::sync::CommitId; use crossterm::event::Event; use ratatui::{ backend::Backend, layout::Rect, widgets::Clear, Frame, @@ -48,27 +44,13 @@ pub struct RevisionFilesPopup { impl RevisionFilesPopup { /// - pub fn new( - repo: RepoPathRef, - queue: &Queue, - sender: &Sender, - sender_git: Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - files: RevisionFilesComponent::new( - repo, - queue, - sender, - sender_git, - theme, - key_config.clone(), - ), + files: RevisionFilesComponent::new(env), visible: false, - key_config, + key_config: env.key_config.clone(), open_request: None, - queue: queue.clone(), + queue: env.queue.clone(), } } diff --git a/src/components/stashmsg.rs b/src/components/stashmsg.rs index d30f68fcea..86c34441ce 100644 --- a/src/components/stashmsg.rs +++ b/src/components/stashmsg.rs @@ -4,11 +4,11 @@ use super::{ EventState, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::{AppTabs, InternalEvent, Queue}, strings, tabs::StashingOptions, - ui::style::SharedTheme, }; use anyhow::Result; use asyncgit::sync::{self, RepoPathRef}; @@ -126,24 +126,18 @@ impl Component for StashMsgComponent { impl StashMsgComponent { /// - pub fn new( - repo: RepoPathRef, - queue: Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { options: StashingOptions::default(), - queue, + queue: env.queue.clone(), input: TextInputComponent::new( - theme, - key_config.clone(), - &strings::stash_popup_title(&key_config), - &strings::stash_popup_msg(&key_config), + env, + &strings::stash_popup_title(&env.key_config), + &strings::stash_popup_msg(&env.key_config), true, ), - key_config, - repo, + key_config: env.key_config.clone(), + repo: env.repo.clone(), } } diff --git a/src/components/status_tree.rs b/src/components/status_tree.rs index 3c3031257b..2cbd29b65f 100644 --- a/src/components/status_tree.rs +++ b/src/components/status_tree.rs @@ -6,6 +6,7 @@ use super::{ BlameFileOpen, CommandBlocking, DrawableComponent, FileRevOpen, }; use crate::{ + app::Environment, components::{CommandInfo, Component, EventState}, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, NeedsUpdate, Queue, StackablePopupOpen}, @@ -30,7 +31,7 @@ pub struct StatusTreeComponent { current_hash: u64, focused: bool, show_selection: bool, - queue: Option, + queue: Queue, theme: SharedTheme, key_config: SharedKeyConfig, scroll_top: Cell, @@ -40,22 +41,16 @@ pub struct StatusTreeComponent { impl StatusTreeComponent { /// - pub fn new( - title: &str, - focus: bool, - queue: Option, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment, title: &str, focus: bool) -> Self { Self { title: title.to_string(), tree: StatusTree::default(), current_hash: 0, focused: focus, show_selection: focus, - queue, - theme, - key_config, + queue: env.queue.clone(), + theme: env.theme.clone(), + key_config: env.key_config.clone(), scroll_top: Cell::new(0), pending: true, visible: false, @@ -137,9 +132,7 @@ impl StatusTreeComponent { let changed = self.tree.move_selection(dir); if changed { - if let Some(ref queue) = self.queue { - queue.push(InternalEvent::Update(NeedsUpdate::DIFF)); - } + self.queue.push(InternalEvent::Update(NeedsUpdate::DIFF)); } changed @@ -309,11 +302,9 @@ impl StatusTreeComponent { if crate::clipboard::copy_string(&item.info.full_path) .is_err() { - if let Some(queue) = &self.queue { - queue.push(InternalEvent::ShowErrorMsg( - strings::POPUP_FAIL_COPY.to_string(), - )); - } + self.queue.push(InternalEvent::ShowErrorMsg( + strings::POPUP_FAIL_COPY.to_string(), + )); } } } @@ -463,17 +454,15 @@ impl Component for StatusTreeComponent { return if key_match(e, self.key_config.keys.blame) { if let Some(status_item) = self.selection_file() { self.hide(); - if let Some(queue) = &self.queue { - queue.push(InternalEvent::OpenPopup( - StackablePopupOpen::BlameFile( - BlameFileOpen { - file_path: status_item.path, - commit_id: self.revision, - selection: None, - }, - ), - )); - } + self.queue.push(InternalEvent::OpenPopup( + StackablePopupOpen::BlameFile( + BlameFileOpen { + file_path: status_item.path, + commit_id: self.revision, + selection: None, + }, + ), + )); } Ok(EventState::Consumed) } else if key_match( @@ -482,27 +471,21 @@ impl Component for StatusTreeComponent { ) { if let Some(status_item) = self.selection_file() { self.hide(); - if let Some(queue) = &self.queue { - queue.push(InternalEvent::OpenPopup( - StackablePopupOpen::FileRevlog( - FileRevOpen::new( - status_item.path, - ), - ), - )); - } + self.queue.push(InternalEvent::OpenPopup( + StackablePopupOpen::FileRevlog( + FileRevOpen::new(status_item.path), + ), + )); } Ok(EventState::Consumed) } else if key_match(e, self.key_config.keys.edit_file) { if let Some(status_item) = self.selection_file() { - if let Some(queue) = &self.queue { - queue.push( - InternalEvent::OpenExternalEditor( - Some(status_item.path), - ), - ); - } + self.queue.push( + InternalEvent::OpenExternalEditor(Some( + status_item.path, + )), + ); } Ok(EventState::Consumed) } else if key_match(e, self.key_config.keys.copy) { @@ -607,11 +590,9 @@ mod tests { // set up file tree let mut ftc = StatusTreeComponent::new( + &Default::default(), "title", true, - None, - SharedTheme::default(), - SharedKeyConfig::default(), ); ftc.update(&items) .expect("Updating FileTreeComponent failed"); @@ -649,11 +630,9 @@ mod tests { // set up file tree let mut ftc = StatusTreeComponent::new( + &Default::default(), "title", true, - None, - SharedTheme::default(), - SharedKeyConfig::default(), ); ftc.update(&items) .expect("Updating FileTreeComponent failed"); diff --git a/src/components/submodules.rs b/src/components/submodules.rs index e8cdac85b4..f92d800a72 100644 --- a/src/components/submodules.rs +++ b/src/components/submodules.rs @@ -4,6 +4,7 @@ use super::{ EventState, ScrollType, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, NeedsUpdate, Queue}, strings, try_or_popup, @@ -245,23 +246,18 @@ impl Component for SubmodulesListComponent { } impl SubmodulesListComponent { - pub fn new( - repo: RepoPathRef, - queue: &Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { submodules: Vec::new(), submodule_parent: None, scroll: VerticalScroll::new(), - queue: queue.clone(), + queue: env.queue.clone(), selection: 0, visible: false, - theme, - key_config, + theme: env.theme.clone(), + key_config: env.key_config.clone(), current_height: Cell::new(0), - repo, + repo: env.repo.clone(), repo_path: String::new(), } } diff --git a/src/components/syntax_text.rs b/src/components/syntax_text.rs index d96705d7a8..c1d908bb0c 100644 --- a/src/components/syntax_text.rs +++ b/src/components/syntax_text.rs @@ -3,6 +3,7 @@ use super::{ EventState, }; use crate::{ + app::Environment, keys::SharedKeyConfig, string_utils::tabs_to_spaces, strings, @@ -18,7 +19,6 @@ use asyncgit::{ sync::{self, RepoPathRef, TreeFile}, ProgressPercent, }; -use crossbeam_channel::Sender; use crossterm::event::Event; use filetreelist::MoveSelection; use itertools::Either; @@ -44,21 +44,18 @@ pub struct SyntaxTextComponent { impl SyntaxTextComponent { /// - pub fn new( - repo: RepoPathRef, - sender: &Sender, - key_config: SharedKeyConfig, - theme: SharedTheme, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - async_highlighting: AsyncSingleJob::new(sender.clone()), + async_highlighting: AsyncSingleJob::new( + env.sender_app.clone(), + ), syntax_progress: None, current_file: None, paragraph_state: Cell::new(ParagraphState::default()), focused: false, - key_config, - theme, - repo, + key_config: env.key_config.clone(), + theme: env.theme.clone(), + repo: env.repo.clone(), } } diff --git a/src/components/tag_commit.rs b/src/components/tag_commit.rs index 3919141fda..79f506c464 100644 --- a/src/components/tag_commit.rs +++ b/src/components/tag_commit.rs @@ -4,10 +4,10 @@ use super::{ EventState, }; use crate::{ + app::Environment, keys::{key_match, SharedKeyConfig}, queue::{InternalEvent, NeedsUpdate, Queue}, strings, try_or_popup, - ui::style::SharedTheme, }; use anyhow::Result; use asyncgit::sync::{ @@ -126,24 +126,18 @@ impl Component for TagCommitComponent { impl TagCommitComponent { /// - pub fn new( - repo: RepoPathRef, - queue: Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - queue, + queue: env.queue.clone(), input: TextInputComponent::new( - theme, - key_config.clone(), + env, &strings::tag_popup_name_title(), &strings::tag_popup_name_msg(), true, ), commit_id: None, - key_config, - repo, + key_config: env.key_config.clone(), + repo: env.repo.clone(), mode: Mode::Name, } } diff --git a/src/components/taglist.rs b/src/components/taglist.rs index eba6a03213..18e83dab90 100644 --- a/src/components/taglist.rs +++ b/src/components/taglist.rs @@ -3,6 +3,7 @@ use super::{ Component, DrawableComponent, EventState, }; use crate::{ + app::Environment, components::ScrollType, keys::{key_match, SharedKeyConfig}, queue::{Action, InternalEvent, Queue}, @@ -23,7 +24,7 @@ use asyncgit::{ }, AsyncGitNotification, }; -use crossbeam_channel::Sender; + use crossterm::event::Event; use ratatui::{ backend::Backend, @@ -292,16 +293,10 @@ impl Component for TagListComponent { } impl TagListComponent { - pub fn new( - repo: RepoPathRef, - queue: &Queue, - sender: &Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - theme, - queue: queue.clone(), + theme: env.theme.clone(), + queue: env.queue.clone(), tags: None, visible: false, has_remotes: false, @@ -309,9 +304,11 @@ impl TagListComponent { current_height: std::cell::Cell::new(0), basic_credential: None, missing_remote_tags: None, - async_remote_tags: AsyncSingleJob::new(sender.clone()), - key_config, - repo, + async_remote_tags: AsyncSingleJob::new( + env.sender_git.clone(), + ), + key_config: env.key_config.clone(), + repo: env.repo.clone(), } } diff --git a/src/components/textinput.rs b/src/components/textinput.rs index 1c8bd73d65..b9c98a23c9 100644 --- a/src/components/textinput.rs +++ b/src/components/textinput.rs @@ -1,3 +1,4 @@ +use crate::app::Environment; use crate::keys::key_match; use crate::strings::symbol; use crate::ui::Size; @@ -51,8 +52,7 @@ pub struct TextInputComponent { impl TextInputComponent { /// pub fn new( - theme: SharedTheme, - key_config: SharedKeyConfig, + env: &Environment, title: &str, default_msg: &str, show_char_count: bool, @@ -60,8 +60,8 @@ impl TextInputComponent { Self { msg: String::new(), visible: false, - theme, - key_config, + theme: env.theme.clone(), + key_config: env.key_config.clone(), show_char_count, title: title.to_string(), default_msg: default_msg.to_string(), @@ -555,8 +555,7 @@ mod tests { #[test] fn test_smoke() { let mut comp = TextInputComponent::new( - SharedTheme::default(), - SharedKeyConfig::default(), + &Environment::default(), "", "", false, @@ -576,8 +575,7 @@ mod tests { #[test] fn text_cursor_initial_position() { let mut comp = TextInputComponent::new( - SharedTheme::default(), - SharedKeyConfig::default(), + &Environment::default(), "", "", false, @@ -602,8 +600,7 @@ mod tests { #[test] fn test_cursor_second_position() { let mut comp = TextInputComponent::new( - SharedTheme::default(), - SharedKeyConfig::default(), + &Environment::default(), "", "", false, @@ -639,8 +636,7 @@ mod tests { #[test] fn test_visualize_newline() { let mut comp = TextInputComponent::new( - SharedTheme::default(), - SharedKeyConfig::default(), + &Environment::default(), "", "", false, @@ -675,8 +671,7 @@ mod tests { #[test] fn test_invisible_newline() { let mut comp = TextInputComponent::new( - SharedTheme::default(), - SharedKeyConfig::default(), + &Environment::default(), "", "", false, @@ -706,8 +701,7 @@ mod tests { #[test] fn test_next_word_position() { let mut comp = TextInputComponent::new( - SharedTheme::default(), - SharedKeyConfig::default(), + &Environment::default(), "", "", false, @@ -731,8 +725,7 @@ mod tests { #[test] fn test_previous_word_position() { let mut comp = TextInputComponent::new( - SharedTheme::default(), - SharedKeyConfig::default(), + &Environment::default(), "", "", false, @@ -759,8 +752,7 @@ mod tests { #[test] fn test_next_word_multibyte() { let mut comp = TextInputComponent::new( - SharedTheme::default(), - SharedKeyConfig::default(), + &Environment::default(), "", "", false, diff --git a/src/main.rs b/src/main.rs index c0f41a2770..0fb613911e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -203,8 +203,8 @@ fn run_app( let mut app = App::new( RefCell::new(repo), - &tx_git, - &tx_app, + tx_git, + tx_app, input.clone(), theme, key_config, diff --git a/src/options.rs b/src/options.rs index 4c0424c710..bfa12f6e0c 100644 --- a/src/options.rs +++ b/src/options.rs @@ -32,6 +32,17 @@ pub struct Options { data: OptionsData, } +#[cfg(test)] +impl Default for Options { + fn default() -> Self { + use asyncgit::sync::RepoPath; + Self { + repo: RefCell::new(RepoPath::Path(Default::default())), + data: Default::default(), + } + } +} + pub type SharedOptions = Rc>; impl Options { diff --git a/src/tabs/files.rs b/src/tabs/files.rs index 9c4c330423..81da261803 100644 --- a/src/tabs/files.rs +++ b/src/tabs/files.rs @@ -1,21 +1,15 @@ use std::path::Path; use crate::{ + app::Environment, components::{ visibility_blocking, CommandBlocking, CommandInfo, Component, DrawableComponent, EventState, RevisionFilesComponent, }, - keys::SharedKeyConfig, - queue::Queue, - ui::style::SharedTheme, - AsyncAppNotification, AsyncNotification, + AsyncNotification, }; use anyhow::Result; -use asyncgit::{ - sync::{self, RepoPathRef}, - AsyncGitNotification, -}; -use crossbeam_channel::Sender; +use asyncgit::sync::{self, RepoPathRef}; pub struct FilesTab { repo: RepoPathRef, @@ -25,25 +19,11 @@ pub struct FilesTab { impl FilesTab { /// - pub fn new( - repo: RepoPathRef, - sender: &Sender, - sender_git: Sender, - queue: &Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { visible: false, - files: RevisionFilesComponent::new( - repo.clone(), - queue, - sender, - sender_git, - theme, - key_config, - ), - repo, + files: RevisionFilesComponent::new(env), + repo: env.repo.clone(), } } diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index c208b868f1..a9cff547f1 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -1,4 +1,5 @@ use crate::{ + app::Environment, components::{ visibility_blocking, CommandBlocking, CommandInfo, CommitDetailsComponent, CommitList, Component, @@ -70,43 +71,35 @@ pub struct Revlog { impl Revlog { /// - pub fn new( - repo: &RepoPathRef, - queue: &Queue, - sender: &Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - repo: repo.clone(), - queue: queue.clone(), - commit_details: CommitDetailsComponent::new( - repo, - queue, - sender, - theme.clone(), - key_config.clone(), - ), + repo: env.repo.clone(), + queue: env.queue.clone(), + commit_details: CommitDetailsComponent::new(env), list: CommitList::new( - repo.clone(), - &strings::log_title(&key_config), - theme.clone(), - queue.clone(), - key_config.clone(), + env, + &strings::log_title(&env.key_config), ), git_log: AsyncLog::new( - repo.borrow().clone(), - sender, + env.repo.borrow().clone(), + &env.sender_git, None, ), search: LogSearch::Off, - git_tags: AsyncTags::new(repo.borrow().clone(), sender), - git_local_branches: AsyncSingleJob::new(sender.clone()), - git_remote_branches: AsyncSingleJob::new(sender.clone()), + git_tags: AsyncTags::new( + env.repo.borrow().clone(), + &env.sender_git, + ), + git_local_branches: AsyncSingleJob::new( + env.sender_git.clone(), + ), + git_remote_branches: AsyncSingleJob::new( + env.sender_git.clone(), + ), visible: false, - key_config, - sender: sender.clone(), - theme, + key_config: env.key_config.clone(), + sender: env.sender_git.clone(), + theme: env.theme.clone(), } } diff --git a/src/tabs/stashing.rs b/src/tabs/stashing.rs index 93734ae387..fb6ed5f961 100644 --- a/src/tabs/stashing.rs +++ b/src/tabs/stashing.rs @@ -1,5 +1,6 @@ use crate::{ accessors, + app::Environment, components::{ command_pump, event_pump, visibility_blocking, CommandBlocking, CommandInfo, Component, DrawableComponent, @@ -15,7 +16,7 @@ use asyncgit::{ sync::{self, status::StatusType, RepoPathRef}, AsyncGitNotification, AsyncStatus, StatusParams, }; -use crossbeam_channel::Sender; + use crossterm::event::Event; use ratatui::{ layout::{Alignment, Constraint, Direction, Layout}, @@ -45,34 +46,26 @@ impl Stashing { accessors!(self, [index]); /// - pub fn new( - repo: &RepoPathRef, - sender: &Sender, - queue: &Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { - repo: repo.clone(), + repo: env.repo.clone(), index: StatusTreeComponent::new( - &strings::stashing_files_title(&key_config), + env, + &strings::stashing_files_title(&env.key_config), true, - Some(queue.clone()), - theme.clone(), - key_config.clone(), ), visible: false, options: StashingOptions { keep_index: false, stash_untracked: true, }, - theme, + theme: env.theme.clone(), git_status: AsyncStatus::new( - repo.borrow().clone(), - sender.clone(), + env.repo.borrow().clone(), + env.sender_git.clone(), ), - queue: queue.clone(), - key_config, + queue: env.queue.clone(), + key_config: env.key_config.clone(), } } diff --git a/src/tabs/stashlist.rs b/src/tabs/stashlist.rs index 08540d8e11..5a40cc497e 100644 --- a/src/tabs/stashlist.rs +++ b/src/tabs/stashlist.rs @@ -1,4 +1,5 @@ use crate::{ + app::Environment, components::{ visibility_blocking, CommandBlocking, CommandInfo, CommitList, Component, DrawableComponent, EventState, @@ -7,7 +8,6 @@ use crate::{ keys::{key_match, SharedKeyConfig}, queue::{Action, InternalEvent, Queue, StackablePopupOpen}, strings, - ui::style::SharedTheme, }; use anyhow::Result; use asyncgit::sync::{self, CommitId, RepoPath, RepoPathRef}; @@ -23,24 +23,16 @@ pub struct StashList { impl StashList { /// - pub fn new( - repo: RepoPathRef, - queue: &Queue, - theme: SharedTheme, - key_config: SharedKeyConfig, - ) -> Self { + pub fn new(env: &Environment) -> Self { Self { visible: false, list: CommitList::new( - repo.clone(), - &strings::stashlist_title(&key_config), - theme, - queue.clone(), - key_config.clone(), + env, + &strings::stashlist_title(&env.key_config), ), - queue: queue.clone(), - key_config, - repo, + queue: env.queue.clone(), + key_config: env.key_config.clone(), + repo: env.repo.clone(), } } diff --git a/src/tabs/status.rs b/src/tabs/status.rs index d7e323740f..4be13eb39e 100644 --- a/src/tabs/status.rs +++ b/src/tabs/status.rs @@ -1,5 +1,6 @@ use crate::{ accessors, + app::Environment, components::{ command_pump, event_pump, visibility_blocking, ChangesComponent, CommandBlocking, CommandInfo, Component, @@ -10,7 +11,7 @@ use crate::{ options::SharedOptions, queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem}, strings, try_or_popup, - ui::style::{SharedTheme, Theme}, + ui::style::Theme, }; use anyhow::Result; use asyncgit::{ @@ -23,7 +24,7 @@ use asyncgit::{ AsyncBranchesJob, AsyncDiff, AsyncGitNotification, AsyncStatus, DiffParams, DiffType, PushType, StatusItem, StatusParams, }; -use crossbeam_channel::Sender; + use crossterm::event::Event; use itertools::Itertools; use ratatui::{ @@ -153,66 +154,49 @@ impl Status { accessors!(self, [index, index_wd, diff]); /// - pub fn new( - repo: RepoPathRef, - queue: &Queue, - sender: &Sender, - theme: SharedTheme, - key_config: SharedKeyConfig, - options: SharedOptions, - ) -> Self { - let repo_clone = repo.borrow().clone(); + pub fn new(env: &Environment) -> Self { + let repo_clone = env.repo.borrow().clone(); Self { - queue: queue.clone(), + queue: env.queue.clone(), visible: true, has_remotes: false, git_state: RepoState::Clean, focus: Focus::WorkDir, diff_target: DiffTarget::WorkingDir, index_wd: ChangesComponent::new( - repo.clone(), - &strings::title_status(&key_config), + env, + &strings::title_status(&env.key_config), true, true, - queue.clone(), - theme.clone(), - key_config.clone(), - options.clone(), ), index: ChangesComponent::new( - repo.clone(), - &strings::title_index(&key_config), + env, + &strings::title_index(&env.key_config), false, false, - queue.clone(), - theme.clone(), - key_config.clone(), - options.clone(), ), - diff: DiffComponent::new( - repo.clone(), - queue.clone(), - theme, - key_config.clone(), - false, - options.clone(), + diff: DiffComponent::new(env, false), + git_diff: AsyncDiff::new( + repo_clone.clone(), + &env.sender_git, ), - git_diff: AsyncDiff::new(repo_clone.clone(), sender), git_status_workdir: AsyncStatus::new( repo_clone.clone(), - sender.clone(), + env.sender_git.clone(), ), git_status_stage: AsyncStatus::new( repo_clone, - sender.clone(), + env.sender_git.clone(), ), - git_branches: AsyncSingleJob::new(sender.clone()), + git_branches: AsyncSingleJob::new(env.sender_git.clone()), git_action_executed: false, git_branch_state: None, - git_branch_name: cached::BranchName::new(repo.clone()), - key_config, - options, - repo, + git_branch_name: cached::BranchName::new( + env.repo.clone(), + ), + key_config: env.key_config.clone(), + options: env.options.clone(), + repo: env.repo.clone(), } }