(refactor) shorten component creation by grouping common items in an Environment

This commit is contained in:
Alexandru Macovei 2022-10-03 13:01:39 +03:00 committed by extrawurst
parent 5259fd90b3
commit 0383f9517b
44 changed files with 467 additions and 911 deletions

View File

@ -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(),
};

View File

@ -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),
}
}

View File

@ -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(),
}
}

View File

@ -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(),
}
}

View File

@ -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,
}
}

View File

@ -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(),
}
}

View File

@ -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(),
}
}

View File

@ -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(),
}
}

View File

@ -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(),
}
}

View File

@ -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,
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(),
}
}

View File

@ -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(),
}
}

View File

@ -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,

View File

@ -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(),
}
}
///

View File

@ -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(),
}
}

View File

@ -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<AsyncGitNotification>,
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(),
}
}

View File

@ -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<AsyncGitNotification>,
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(),
}
}

View File

@ -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,
}

View File

@ -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(),
}
}
///

View File

@ -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<AsyncGitNotification>,
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(),
}
}

View File

@ -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,

View File

@ -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(),
}
}

View File

@ -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(),
}
}

View File

@ -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<AsyncGitNotification>,
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(),
}
}

View File

@ -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<AsyncGitNotification>,
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(),
}
}

View File

@ -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<AsyncGitNotification>,
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(),
}
}

View File

@ -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(),
}
}

View File

@ -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(),
}
}
///

View File

@ -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(),
}
}

View File

@ -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<AsyncAppNotification>,
sender_git: Sender<AsyncGitNotification>,
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,
}
}

View File

@ -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<AsyncAppNotification>,
sender_git: Sender<AsyncGitNotification>,
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(),
}
}

View File

@ -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(),
}
}

View File

@ -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: Queue,
theme: SharedTheme,
key_config: SharedKeyConfig,
scroll_top: Cell<usize>,
@ -40,22 +41,16 @@ pub struct StatusTreeComponent {
impl StatusTreeComponent {
///
pub fn new(
title: &str,
focus: bool,
queue: Option<Queue>,
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");

View File

@ -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(),
}
}

View File

@ -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<AsyncAppNotification>,
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(),
}
}

View File

@ -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,
}
}

View File

@ -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<AsyncGitNotification>,
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(),
}
}

View File

@ -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,

View File

@ -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,

View File

@ -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<RefCell<Options>>;
impl Options {

View File

@ -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<AsyncAppNotification>,
sender_git: Sender<AsyncGitNotification>,
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(),
}
}

View File

@ -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<AsyncGitNotification>,
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(),
}
}

View File

@ -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<AsyncGitNotification>,
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(),
}
}

View File

@ -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(),
}
}

View File

@ -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<AsyncGitNotification>,
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(),
}
}