1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! What each feature adds to the screens, in one table: the actions it
//! owns, the others it takes on its own pages, what it does with them,
//! the menu's rows it offers, and what it brings up to date as data
//! arrives or a page opens.
//!
//! An action is done by the feature that takes it on the screen as it is
//! (editing a release, closing a milestone), else by the one that owns it,
//! which does it or says where it works. No two features own one action,
//! and on no screen do two take one (tests check both), so the table's
//! order is only the order the menu offers their rows in.
use crate::keymap::Action;
use crate::nav::Doable;
use crate::state::{Cmd, State};
/// What a feature adds.
pub struct Feature {
/// Its own actions: wherever they're pressed, it does them, or says
/// where they work.
pub owns: &'static [Action],
/// Whether it takes `action` on the screen as it is: another's on its
/// own pages.
pub takes: fn(&State, Action) -> bool,
/// Does an action it owns or takes.
pub act: fn(&mut State, Action) -> Vec<Cmd>,
/// The menu's rows it adds on the screen.
pub offers: fn(&State, &mut Vec<Doable>),
/// After GitHub's data arrives or a page opens: brings what it keeps
/// up to date with it.
pub follow: fn(&mut State) -> Vec<Cmd>,
}
impl Feature {
/// A feature that adds nothing, to fill in what one leaves out.
pub const NONE: Feature = Feature {
owns: &[],
takes: |_, _| false,
act: |_, _| Vec::new(),
offers: |_, _| {},
follow: |_| Vec::new(),
};
}
/// Every feature, in the order the menu offers their rows.
pub const FEATURES: &[Feature] = &[
crate::home::FEATURE,
crate::forms::FEATURE,
crate::projects::FEATURE,
crate::discuss::FEATURE,
crate::create::FEATURE,
crate::clone::FEATURE,
crate::release::FEATURE,
crate::gist::FEATURE,
crate::wiki::form::FEATURE,
crate::site::FEATURE,
crate::act::FEATURE,
crate::review::FEATURE,
crate::edit::FEATURE,
crate::manage::FEATURE,
crate::settings::FEATURE,
crate::watch::FEATURE,
crate::housekeeping::FEATURE,
crate::workflows::FEATURE,
crate::offline::FEATURE,
];
/// The feature that does `action` here: the one that takes it on this
/// screen, else the one that owns it.
pub fn of(state: &State, action: Action) -> Option<&'static Feature> {
(FEATURES.iter().find(|f| (f.takes)(state, action)))
.or_else(|| FEATURES.iter().find(|f| f.owns.contains(&action)))
}
/// The menu's rows the features add.
pub fn offers(state: &State, out: &mut Vec<Doable>) {
for f in FEATURES {
(f.offers)(state, out);
}
}
/// After GitHub's data arrives or a page opens: brings every feature up
/// to date with it.
#[must_use]
pub fn follow(state: &mut State) -> Vec<Cmd> {
FEATURES.iter().flat_map(|f| (f.follow)(state)).collect()
}