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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! The editor a keypress opens on the cursor's row: where it writes, what it
//! opens with, and the edit that removes the row.
use super::*;
use crate::lookout::pane::UNSET;
impl Settings {
/// Where an editor opened on the cursor's row writes, and what it opens
/// with. `None` on a row that cycles, folds or is not a key.
pub(in crate::lookout::app) fn editor_at_cursor(&self) -> Option<(Target, String)> {
let shape = shep_toml_shape();
let fields = shape.fields.fields();
match self.cursor()? {
SettingsRow::Field(index) => {
let field = &fields[index];
if !field.editable || !is_typed(&field.kind) {
return None;
}
let path = shape.paths.get(&field.key)?.clone();
let kind = Shape::of(&field.kind)?;
Some((
Target::Value { path, shape: kind },
self.snapshot.seed(field),
))
}
SettingsRow::Entry { map, index } => {
let key = &fields[map].key;
let (name, value) = self.snapshot.entries(key).into_iter().nth(index)?;
Some((
Target::Value {
path: vec![key.clone(), name],
shape: Shape::Text,
},
value,
))
}
SettingsRow::AddEntry(map) => Some((
Target::NewEntry {
path: shape.paths.get(&fields[map].key)?.clone(),
},
String::new(),
)),
SettingsRow::DogField { dog, row } => {
let (name, key, seed, secret) = self.dog_field_editor(dog, row)?;
Some((
Target::DogValue {
name,
key,
row,
secret,
},
seed,
))
}
// A dog's env is typed into the key/value editor, not this one.
SettingsRow::Table(_)
| SettingsRow::Dog(_)
| SettingsRow::DogKey { .. }
| SettingsRow::DogGrant { .. }
| SettingsRow::DogEnv(_)
| SettingsRow::DogEnvKey { .. }
| SettingsRow::DogEnvNew(_)
| SettingsRow::AvailableDog(_)
| SettingsRow::BrowseDogs => None,
}
}
/// What an editor opened on one row of a dog's own tree writes, and what
/// it opens with. `None` for a row that folds, cycles, is locked, or is a
/// secret, which is seeded empty rather than with a value the screen is
/// not allowed to show. A key the section does not set is seeded empty too,
/// not with the `(unset)` its row shows. The last of the four is whether
/// the field is a secret, which the editor draws masked.
fn dog_field_editor(&self, dog: usize, row: usize) -> Option<(String, String, String, bool)> {
let name = self.snapshot.dogs.get(dog)?.name.clone();
let pane = self.dog_tree(dog)?.pane()?;
let PaneRow::Field(index) = pane.rows().get(row)?.to_owned() else {
return None;
};
let field = pane.fields().fields().get(index)?;
if !field.editable || !is_typed(&field.kind) || pane.lock(&field.key).is_some() {
return None;
}
// The seed is what [`ConfigPane::begin_typing`] would open with, key
// for key: a secret's value is never held here, and a key the section
// does not set shows [`UNSET`], which is a rendering and not a value.
// Seeding either as drawn would arm a write of the placeholder itself.
let shown = pane.value(&field.key);
let seed = if field.secret || shown == UNSET {
String::new()
} else {
shown
};
Some((name, field.key.clone(), seed, field.secret))
}
/// The edit that removes the cursor's row from `shep.toml`, or `None`
/// where there is nothing to remove: a section, a dog, or a key the file
/// never wrote.
pub(in crate::lookout::app) fn removal_at_cursor(&self) -> Option<SettingEdit> {
let shape = shep_toml_shape();
let fields = shape.fields.fields();
match self.cursor()? {
SettingsRow::Field(index) => {
let field = &fields[index];
self.snapshot.file_value(&field.key)?;
Some(SettingEdit::Unset {
path: shape.paths.get(&field.key)?.clone(),
})
}
SettingsRow::Entry { map, index } => {
let key = &fields[map].key;
let (name, _) = self.snapshot.entries(key).into_iter().nth(index)?;
Some(SettingEdit::Unset {
path: vec![key.clone(), name],
})
}
SettingsRow::Table(_)
| SettingsRow::AddEntry(_)
| SettingsRow::Dog(_)
| SettingsRow::DogKey { .. }
| SettingsRow::DogGrant { .. }
| SettingsRow::DogEnv(_)
| SettingsRow::DogEnvKey { .. }
| SettingsRow::DogEnvNew(_)
| SettingsRow::DogField { .. }
| SettingsRow::AvailableDog(_)
| SettingsRow::BrowseDogs => None,
}
}
}