use super::*;
impl State {
#[must_use]
pub fn open_diff(&mut self, of: DiffOf, anchor: Option<String>) -> Vec<Cmd> {
let (screen, cmds) = self.diff_screen(of, anchor);
self.screens.push(screen);
cmds
}
#[must_use]
pub fn diff_screen(&mut self, of: DiffOf, anchor: Option<String>) -> (Screen, Vec<Cmd>) {
let mut cmds = match &of {
DiffOf::Pr(pr) => self.ensure(DataKey::Pr(pr.clone()), false),
DiffOf::Commit(..) | DiffOf::Range(..) => Vec::new(),
};
if !self.diffs.get(&of).is_some_and(|d| d.error.is_none()) {
cmds.extend(self.start_diff(&of));
}
let mut screen = DiffScreen::new(of, DiffPrefs::fit(self.size.0));
screen.anchor = anchor;
(Screen::Diff(Box::new(screen)), cmds)
}
pub(crate) fn pr_base(&self, pr: &PrRef) -> Option<crate::diff_job::PrBase> {
let d = self.pr(pr)?;
Some(crate::diff_job::PrBase {
branch: d.base_ref.clone(),
oid: (!d.state.is_open())
.then(|| Oid::parse(&d.base_oid).ok())
.flatten(),
})
}
#[must_use]
pub(super) fn start_diff(&mut self, of: &DiffOf) -> Vec<Cmd> {
let base = match of {
DiffOf::Pr(pr) => match self.pr_base(pr) {
Some(base) => base,
None => return Vec::new(),
},
DiffOf::Commit(..) | DiffOf::Range(..) => crate::diff_job::PrBase::default(),
};
let diff = DiffState::fresh();
let job = diff.job;
self.diffs.insert(of.clone(), diff);
let mut cmds = vec![Cmd::Git(Git::LoadDiff {
of: of.clone(),
job,
base,
range: None,
})];
if let DiffOf::Pr(pr) = of {
cmds.extend([
Cmd::Api(Api::FetchViewed(pr.clone())),
Cmd::LoadReview(pr.clone()),
Cmd::Api(Api::FetchThreads(pr.clone())),
Cmd::Api(Api::FetchPatches(pr.clone())),
]);
cmds.extend(self.ensure(DataKey::PrChecks(pr.clone()), false));
crate::workflows::checks_loaded(self, pr);
}
if let DiffOf::Commit(repo, oid) = of {
let key = DataKey::CommitComments(repo.clone(), oid.to_string());
cmds.extend(self.ensure(key, false));
}
cmds
}
}
impl State {
#[must_use]
pub fn settle_diff(&mut self) -> Vec<Cmd> {
let of = match self.screen() {
Screen::Diff(screen) => Some(screen.of.clone()),
Screen::Page(p) => browse::glanced(&p.route).cloned().map(DiffOf::Pr),
};
let mut cmds = match of {
Some(of)
if !self.diffs.contains_key(&of)
&& (of.pr()).is_none_or(|pr| self.pr_remote(pr).is_none_or(|r| !r.loading)) =>
{
self.start_diff(&of)
}
_ => Vec::new(),
};
cmds.extend(join::join(self));
let content = self.layout().content;
if let Some((screen, diff)) = self.diff_parts() {
cmds.extend(diff_screen::settle(screen, diff, content));
}
cmds
}
}
impl State {
#[must_use]
pub fn compose(&mut self, target: compose::Target, text: &str) -> Vec<Cmd> {
let compose = Compose::new(&self.theme, target, text);
self.overlay = Some(Overlay::Compose(Box::new(compose)));
crate::typing::fetch_mentionable(self)
}
pub fn diff(&self) -> Option<&DiffState> {
match self.screen() {
Screen::Diff(screen) => self.diffs.get(&screen.of),
Screen::Page(_) => None,
}
}
pub(crate) fn diff_parts(&mut self) -> Option<(&mut DiffScreen, &mut DiffState)> {
let State { screens, diffs, .. } = self;
let Screen::Diff(screen) = screens.last_mut() else {
return None;
};
let diff = diffs.get_mut(&screen.of)?;
Some((screen, diff))
}
}