WIP: project the evaluated value; yank copies it
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
@@ -282,6 +282,7 @@ fn cell_display(
|
||||
numeric: matches!(value, Some(CellValue::Number(_))),
|
||||
error: matches!(value, Some(CellValue::Error(_))),
|
||||
id: cell_id(app, layout, row, col),
|
||||
value: value.clone(),
|
||||
};
|
||||
}
|
||||
let key = layout.cell_key(row, col);
|
||||
@@ -293,6 +294,7 @@ fn cell_display(
|
||||
// The *unformatted* value the TUI seeds its edit buffer from. Projecting it
|
||||
// beats a client un-formatting `text` (gotcha 47).
|
||||
edit_text: key.map(|key| app.display_value_in(layout, &key)),
|
||||
value: value.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use improvise_core::model::cell::CellValue;
|
||||
use improvise_core::model::record::{AggregateHash, RecordHash};
|
||||
use improvise_core::view::Axis;
|
||||
use improvise_core::view::layout::PageAxis;
|
||||
@@ -64,9 +65,9 @@ pub enum CreateKind {
|
||||
Category,
|
||||
}
|
||||
|
||||
/// One cell as the client draws it. Deliberately not a `CellValue` — the
|
||||
/// One cell as the client draws it. Drawn from `text`, never from `value` — the
|
||||
/// formatting has already happened, and re-deriving it is how ends drift.
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct CellDisplay {
|
||||
pub text: String,
|
||||
/// Right-align numerics, left-align text — decided by the server, which
|
||||
@@ -80,6 +81,9 @@ pub struct CellDisplay {
|
||||
/// What an editor should start with — the value as the user last
|
||||
/// **typed** it, not as it is drawn. The difference corrupts data (§3).
|
||||
pub edit_text: Option<String>,
|
||||
/// The value the host evaluated here, unrounded and untyped-by-text: what
|
||||
/// `yank` copies. Neither `text` nor `edit_text` can be re-parsed into it (§3).
|
||||
pub value: Option<CellValue>,
|
||||
}
|
||||
|
||||
impl CellDisplay {
|
||||
@@ -98,6 +102,7 @@ impl CellDisplay {
|
||||
numeric: true,
|
||||
error: false,
|
||||
id: None,
|
||||
value: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +115,7 @@ impl CellDisplay {
|
||||
error: true,
|
||||
id: None,
|
||||
edit_text: None,
|
||||
value: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,7 +422,7 @@ fn shows(items: &[&Vec<String>], idx: usize, first_rendered: usize, level: usize
|
||||
|
||||
/// The grid widget's copy of the visible cells (improvise-n10), indexed by
|
||||
/// position within the **viewport** and never by `CellKey`.
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct GridCache {
|
||||
/// The row axis's frame: levels, label tuples and groups. **Not** a list
|
||||
/// of strings — see [`AxisFrame`].
|
||||
@@ -563,7 +569,7 @@ enum LabelAxis {
|
||||
|
||||
/// What can change about the grid: cell values, the frames that name them,
|
||||
/// the widths, the totals, the page bar and the extent.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GridUpdate {
|
||||
/// Display values for cells, by viewport position.
|
||||
Cells(Vec<((usize, usize), CellDisplay)>),
|
||||
|
||||
@@ -530,12 +530,10 @@ fn composed(
|
||||
state,
|
||||
ModelCommand::ClearCell(record_cell_at_cursor(state)?),
|
||||
)?]),
|
||||
// `YankCell::execute`: the value, then the status. `edit_text` is
|
||||
// what the host evaluated, which is what the TUI yanks.
|
||||
// `YankCell::execute`: the value, then the status. The projected
|
||||
// value, never text re-parsed: improvise-dsxq.
|
||||
"yank" => Some(vec![
|
||||
Command::SetYanked(typed(
|
||||
cell_at_cursor(state)?.edit_text.as_deref().unwrap_or(""),
|
||||
)),
|
||||
Command::SetYanked(cell_at_cursor(state)?.value.clone()),
|
||||
Command::SetStatus("Yanked".to_string()),
|
||||
]),
|
||||
"paste" => Some(match state.view.yanked.clone() {
|
||||
@@ -3139,6 +3137,7 @@ mod tests {
|
||||
#[test]
|
||||
fn yy_yanks_the_cell_under_the_cursor_and_p_pastes_what_it_yanked() {
|
||||
let mut state = client_on(record_cell());
|
||||
state.grid.cells[0][0].value = Some(CellValue::Number(1200.0));
|
||||
arm(&mut state, ev(KeyCode::Char('y')));
|
||||
let KeyOutcome::Local(yank) = resolve(&state, ev(KeyCode::Char('y'))) else {
|
||||
panic!("`yy` is bound to yank");
|
||||
|
||||
Reference in New Issue
Block a user