Panics · P23 Chat: a branch past its total shows none; parameters peg into range; matches outside a passage stay out
This commit is contained in:
1 parent
30fea9ecec
commit
0b8b74b968
4 files changed
+83
-17
No files matched your search
+25
-6
@@ -308,7 +308,7 @@ impl RenderOnce for MessageEditor {
|
|||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct BranchNavigator {
|
pub struct BranchNavigator {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
current: usize,
|
current: Option<usize>,
|
||||||
total: usize,
|
total: usize,
|
||||||
on_change: Pick,
|
on_change: Pick,
|
||||||
}
|
}
|
||||||
@@ -320,10 +320,12 @@ impl BranchNavigator {
|
|||||||
total: usize,
|
total: usize,
|
||||||
on_change: impl Fn(usize, &mut Window, &mut App) + 'static,
|
on_change: impl Fn(usize, &mut Window, &mut App) + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
assert!(current < total, "version {current} of {total}");
|
if current >= total {
|
||||||
|
log::error!("branch navigator: version {current} of {total}; none shown");
|
||||||
|
}
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
current,
|
current: (current < total).then_some(current),
|
||||||
total,
|
total,
|
||||||
on_change: Rc::new(on_change),
|
on_change: Rc::new(on_change),
|
||||||
}
|
}
|
||||||
@@ -355,7 +357,7 @@ impl RenderOnce for BranchNavigator {
|
|||||||
"back",
|
"back",
|
||||||
IconName::ChevronLeft,
|
IconName::ChevronLeft,
|
||||||
"Previous version",
|
"Previous version",
|
||||||
current.checked_sub(1),
|
current.and_then(|current| current.checked_sub(1)),
|
||||||
))
|
))
|
||||||
.child(
|
.child(
|
||||||
tabular(
|
tabular(
|
||||||
@@ -363,13 +365,30 @@ impl RenderOnce for BranchNavigator {
|
|||||||
.text_size(theme.text_size(TextSize::Xs))
|
.text_size(theme.text_size(TextSize::Xs))
|
||||||
.text_color(theme.colors.fg_muted),
|
.text_color(theme.colors.fg_muted),
|
||||||
)
|
)
|
||||||
.child(format!("{} / {total}", current + 1)),
|
.child(match current {
|
||||||
|
Some(current) => format!("{} / {total}", current + 1),
|
||||||
|
None => format!("– / {total}"),
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
.child(step(
|
.child(step(
|
||||||
"forward",
|
"forward",
|
||||||
IconName::ChevronRight,
|
IconName::ChevronRight,
|
||||||
"Next version",
|
"Next version",
|
||||||
(current + 1 < total).then_some(current + 1),
|
current.and_then(|current| (current + 1 < total).then_some(current + 1)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::BranchNavigator;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_version_past_the_branches_shows_none() {
|
||||||
|
let navigator =
|
||||||
|
|current, total| BranchNavigator::new("branch", current, total, |_, _, _| {});
|
||||||
|
assert_eq!(navigator(1, 3).current, Some(1));
|
||||||
|
assert_eq!(navigator(3, 3).current, None);
|
||||||
|
assert_eq!(navigator(0, 0).current, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
-4
@@ -58,15 +58,25 @@ impl ParameterPanel {
|
|||||||
parameters: impl IntoIterator<Item = Parameter>,
|
parameters: impl IntoIterator<Item = Parameter>,
|
||||||
on_change: impl Fn(&SharedString, f64, &mut Window, &mut App) + 'static,
|
on_change: impl Fn(&SharedString, f64, &mut Window, &mut App) + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let parameters: Vec<Parameter> = parameters.into_iter().collect();
|
let mut parameters: Vec<Parameter> = parameters.into_iter().collect();
|
||||||
for parameter in ¶meters {
|
for parameter in &mut parameters {
|
||||||
assert!(
|
assert!(
|
||||||
parameter.min < parameter.max
|
parameter.min < parameter.max
|
||||||
&& parameter.step > 0.0
|
&& parameter.step > 0.0
|
||||||
&& (parameter.min..=parameter.max).contains(¶meter.value),
|
&& parameter.value.is_finite(),
|
||||||
"parameter {} has a bad range",
|
"parameter {} has a bad range",
|
||||||
parameter.key
|
parameter.key
|
||||||
);
|
);
|
||||||
|
if !(parameter.min..=parameter.max).contains(¶meter.value) {
|
||||||
|
log::error!(
|
||||||
|
"parameters: {} at {} lies outside {}..={}; pegged",
|
||||||
|
parameter.key,
|
||||||
|
parameter.value,
|
||||||
|
parameter.min,
|
||||||
|
parameter.max
|
||||||
|
);
|
||||||
|
parameter.value = parameter.value.clamp(parameter.min, parameter.max);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
@@ -309,7 +319,7 @@ impl RenderOnce for SystemPromptEditor {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Parameter, cost, places};
|
use super::{Parameter, ParameterPanel, cost, places};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cost_counts_tokens_at_their_prices() {
|
fn cost_counts_tokens_at_their_prices() {
|
||||||
@@ -351,4 +361,21 @@ mod tests {
|
|||||||
"float noise adds no places"
|
"float noise adds no places"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_value_outside_its_range_pegs() {
|
||||||
|
let knob = |value| Parameter {
|
||||||
|
key: "temperature".into(),
|
||||||
|
label: "Temperature".into(),
|
||||||
|
value,
|
||||||
|
min: 0.0,
|
||||||
|
max: 2.0,
|
||||||
|
step: 0.1,
|
||||||
|
hint: None,
|
||||||
|
};
|
||||||
|
let panel =
|
||||||
|
ParameterPanel::new("knobs", [knob(3.5), knob(-1.0), knob(0.7)], |_, _, _, _| {});
|
||||||
|
let values: Vec<f64> = panel.parameters.iter().map(|knob| knob.value).collect();
|
||||||
|
assert_eq!(values, [2.0, 0.0, 0.7]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+26
-7
@@ -232,13 +232,19 @@ impl DocumentChunkPreview {
|
|||||||
text: impl Into<SharedString>,
|
text: impl Into<SharedString>,
|
||||||
matched: Vec<Range<usize>>,
|
matched: Vec<Range<usize>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let text = text.into();
|
let text: SharedString = text.into();
|
||||||
assert!(
|
let matched: Vec<Range<usize>> = matched
|
||||||
matched.iter().all(|range| range.end <= text.len()
|
.into_iter()
|
||||||
&& text.is_char_boundary(range.start)
|
.filter(|range| {
|
||||||
&& text.is_char_boundary(range.end)),
|
let inside = text.get(range.clone()).is_some();
|
||||||
"a match lies outside the passage"
|
if !inside {
|
||||||
);
|
log::error!(
|
||||||
|
"document chunk: match {range:?} lies outside the passage; left out"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
inside
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
assert!(
|
assert!(
|
||||||
matched.windows(2).all(|pair| pair[0].end <= pair[1].start),
|
matched.windows(2).all(|pair| pair[0].end <= pair[1].start),
|
||||||
"matches come in order without overlapping"
|
"matches come in order without overlapping"
|
||||||
@@ -315,3 +321,16 @@ impl RenderOnce for DocumentChunkPreview {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::DocumentChunkPreview;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_match_outside_the_passage_is_left_out() {
|
||||||
|
let ranges = vec![1..2, 2..3, 3..9];
|
||||||
|
let preview = DocumentChunkPreview::new("guide.md", "p. 2", "éabc", ranges);
|
||||||
|
let kept = 2..3;
|
||||||
|
assert_eq!(preview.matched, [kept]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,3 +88,4 @@ One line per item: what changed, what stayed and why, review rounds.
|
|||||||
- P20: a hex selection off the bytes and a stack frame past the stack select none; a flame focus keeps what the profile holds; the timeline's wheel reports only finite, positive ranges from finite factors; a dump's last byte must have an address; flame paints log. Kept: disassembly patterns, `zoomed`'s contract. Review: 3 rounds.
|
- P20: a hex selection off the bytes and a stack frame past the stack select none; a flame focus keeps what the profile holds; the timeline's wheel reports only finite, positive ranges from finite factors; a dump's last byte must have an address; flame paints log. Kept: disassembly patterns, `zoomed`'s contract. Review: 3 rounds.
|
||||||
- P21: block editor listeners painted for a block, field, cell or kind since gone log and change nothing, a dropped picture drag leaves undo alone; a visual block press or edit over text the owner replaced is dropped; nested images parse; a version or find hit past its list selects none. Review: 4 rounds.
|
- P21: block editor listeners painted for a block, field, cell or kind since gone log and change nothing, a dropped picture drag leaves undo alone; a visual block press or edit over text the owner replaced is dropped; nested images parse; a version or find hit past its list selects none. Review: 4 rounds.
|
||||||
- P22: annotations and suggestions outside their text log and stay out, picks and decisions keeping the owner's index; `accept` returns `Option`; a gone pick, active thread or followed peer logs; yours at no count comes off; a masked field clamps a stale offset, so remote cursors and selections draw. Kept: a thread's comments, presence max, one list's order, empty marks, constant role and mode tables. Review: 3 rounds.
|
- P22: annotations and suggestions outside their text log and stay out, picks and decisions keeping the owner's index; `accept` returns `Option`; a gone pick, active thread or followed peer logs; yours at no count comes off; a masked field clamps a stale offset, so remote cursors and selections draw. Kept: a thread's comments, presence max, one list's order, empty marks, constant role and mode tables. Review: 3 rounds.
|
||||||
|
- P23: a branch version past its total logs and shows a dash, its arrows off; a parameter outside its range logs and pegs; a passage's matches outside it log and stay out. Kept: one-value contracts (progress, scores, shapes, peaks, levels, limits, prices, capacity, format, hour), the composer's trigger rows and stream reveal by construction; `places` skips zero, so `decimals` meets no zero step. Review: 2 rounds.
|
||||||
Reference in new issue
Block a user