Fixed a slew of bugs involving switching modes.
This commit is contained in:
parent
a193f2c0ca
commit
f98b36833c
|
|
@ -181,7 +181,7 @@ class IcedViewportView: NSView {
|
|||
|
||||
if cmd && !shift {
|
||||
switch chars {
|
||||
case "a", "b", "c", "e", "f", "g", "i", "v", "x", "z", "p", "t",
|
||||
case "a", "b", "c", "e", "f", "g", "i", "r", "v", "x", "z", "p", "t",
|
||||
"=", "+", "-", "0":
|
||||
keyDown(with: event)
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ pub enum Message {
|
|||
/// blank line with one blank line of padding above and below).
|
||||
FixUp,
|
||||
Evaluate,
|
||||
/// Full-document ordered eval: every module evaluated in sequence.
|
||||
EvalAll,
|
||||
SmartEval,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
|
|
@ -436,6 +438,10 @@ pub struct EditorState {
|
|||
// ── Images ──
|
||||
pub computed_images: Vec<ComputedImage>,
|
||||
pub image_cache: HashMap<String, ImageCacheEntry>,
|
||||
|
||||
/// Previous global cursor line (block start_line + intra-block line).
|
||||
/// Used by `tick()` to detect cursor-line changes and trigger eval.
|
||||
prev_cursor_line: usize,
|
||||
}
|
||||
|
||||
/// Per-eval table name→id bookkeeping. `keys` is every alias a table is
|
||||
|
|
@ -551,6 +557,7 @@ impl EditorState {
|
|||
pending_clipboard: None,
|
||||
computed_images: Vec::new(),
|
||||
image_cache: HashMap::new(),
|
||||
prev_cursor_line: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1126,6 +1133,10 @@ impl EditorState {
|
|||
if let Some(sc) = loaded.sidecar {
|
||||
self.apply_sidecar(&sc);
|
||||
}
|
||||
// Trigger full eval when loading into Live or View mode.
|
||||
if self.render_mode == RenderMode::Live || self.render_mode == RenderMode::View {
|
||||
self.run_eval_all();
|
||||
}
|
||||
}
|
||||
|
||||
/// Save the document to raw file bytes: assign sidecar ids to any tables
|
||||
|
|
@ -1497,6 +1508,22 @@ impl EditorState {
|
|||
self.eval_dirty = false;
|
||||
self.run_eval();
|
||||
}
|
||||
// Cursor-line-change trigger: when the cursor moves to a different
|
||||
// line (arrow keys, click, etc.) without an edit, re-evaluate.
|
||||
{
|
||||
let block_start = self.layout.get(self.focused_block)
|
||||
.and_then(|id| self.registry.get(id))
|
||||
.map(|b| b.start_line())
|
||||
.unwrap_or(0);
|
||||
let intra = self.content().cursor().position.line;
|
||||
let global_line = block_start + intra;
|
||||
if global_line != self.prev_cursor_line {
|
||||
self.prev_cursor_line = global_line;
|
||||
if !self.eval_dirty {
|
||||
self.run_eval();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fire the long-press copy at the threshold — if the user is still
|
||||
// holding past LONG_PRESS_MS without having released, double-clicked,
|
||||
// or moved off, drop the result onto the clipboard.
|
||||
|
|
@ -2127,7 +2154,7 @@ impl EditorState {
|
|||
/// containing the raw markdown. The single-block view path renders it
|
||||
/// as a full-page text editor. Cmd+A then selects all text naturally.
|
||||
pub fn enter_editor_mode(&mut self) {
|
||||
if self.render_mode != RenderMode::Live { return; }
|
||||
if self.render_mode == RenderMode::Editor { return; }
|
||||
self.push_undo_snapshot();
|
||||
let full = self.full_text();
|
||||
self.clear_blocks();
|
||||
|
|
@ -2138,6 +2165,10 @@ impl EditorState {
|
|||
self.render_mode = RenderMode::Editor;
|
||||
self.all_blocks_selected = false;
|
||||
self.editing = None;
|
||||
self.eval_results.clear();
|
||||
self.computed_tables.clear();
|
||||
self.computed_trees.clear();
|
||||
self.computed_cells.clear();
|
||||
// Select all text in the single editor so the user can immediately
|
||||
// delete or type over it.
|
||||
self.content_mut().perform(Action::Move(Motion::DocumentStart));
|
||||
|
|
@ -2150,7 +2181,7 @@ impl EditorState {
|
|||
/// Switch back to live mode: reparse the single text block into
|
||||
/// structured blocks (headings, tables, HRs, etc.).
|
||||
pub fn exit_editor_mode(&mut self) {
|
||||
if self.render_mode == RenderMode::Live { return; }
|
||||
if self.render_mode != RenderMode::Editor { return; }
|
||||
let text = self.content().text();
|
||||
let lang = self.lang_str();
|
||||
self.replace_blocks(blocks::parse_blocks(&text, &lang));
|
||||
|
|
@ -2218,8 +2249,12 @@ impl EditorState {
|
|||
}
|
||||
}
|
||||
|
||||
// Find use declarations in the focused block and import those modules
|
||||
if let Some(block) = self.block_at(block_idx) {
|
||||
// Find use declarations in all text blocks of this module and import those modules
|
||||
let use_block_ids: Vec<crate::selection::BlockId> = my_module
|
||||
.map(|m| m.block_ids.clone())
|
||||
.unwrap_or_default();
|
||||
for &bid in &use_block_ids {
|
||||
if let Some(block) = self.registry.get(&bid) {
|
||||
if let Some(tb) = block.as_any().downcast_ref::<TextBlock>() {
|
||||
let text = tb.content.text();
|
||||
let use_decls = interp::extract_use_declarations(&text);
|
||||
|
|
@ -2246,6 +2281,7 @@ impl EditorState {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eval_interp
|
||||
}
|
||||
|
|
@ -2375,6 +2411,33 @@ impl EditorState {
|
|||
|
||||
}
|
||||
|
||||
/// Evaluate every module in document order. Each module gets a fresh
|
||||
/// interpreter seeded with root exports (and its own `use` imports).
|
||||
/// Used by Cmd+R, mode switches to Live/View, and file loads.
|
||||
fn run_eval_all(&mut self) {
|
||||
self.rebuild_modules();
|
||||
// Clear all computed layers up front.
|
||||
self.eval_results.clear();
|
||||
self.computed_tables.clear();
|
||||
self.computed_trees.clear();
|
||||
self.computed_cells.clear();
|
||||
|
||||
// Evaluate each module in order by temporarily pointing focused_block
|
||||
// at a text block within it, then calling run_eval() which already
|
||||
// handles cross-module imports (root exports + `use` declarations).
|
||||
let saved = self.focused_block;
|
||||
let modules: Vec<crate::module::Module> = self.modules.clone();
|
||||
for module in &modules {
|
||||
let anchor_idx = module.block_ids.iter()
|
||||
.find_map(|bid| self.layout.iter().position(|id| id == bid));
|
||||
if let Some(idx) = anchor_idx {
|
||||
self.focused_block = idx;
|
||||
self.run_eval();
|
||||
}
|
||||
}
|
||||
self.focused_block = saved;
|
||||
}
|
||||
|
||||
pub fn take_pending_focus(&mut self) -> Option<WidgetId> {
|
||||
self.pending_focus.take()
|
||||
}
|
||||
|
|
@ -2542,6 +2605,7 @@ impl EditorState {
|
|||
Message::ShowContextMenu { .. } | Message::HideContextMenu => true,
|
||||
Message::CopyLiteral(_) | Message::CopyFocusedTableSelection => true,
|
||||
Message::InlineResultPress { .. } | Message::InlineResultRelease => true,
|
||||
Message::EvalAll => true,
|
||||
Message::EditorAction(action) | Message::BlockAction(_, action) => {
|
||||
!action.is_edit()
|
||||
}
|
||||
|
|
@ -2769,6 +2833,9 @@ impl EditorState {
|
|||
Message::Evaluate => {
|
||||
self.run_eval();
|
||||
}
|
||||
Message::EvalAll => {
|
||||
self.run_eval_all();
|
||||
}
|
||||
Message::SmartEval => {
|
||||
let cursor = self.content().cursor();
|
||||
let text = self.content().text();
|
||||
|
|
@ -3273,9 +3340,24 @@ impl EditorState {
|
|||
}
|
||||
Message::SetRenderMode(mode) => {
|
||||
match mode {
|
||||
RenderMode::Live => self.exit_editor_mode(),
|
||||
RenderMode::Live => {
|
||||
if self.render_mode == RenderMode::Editor {
|
||||
self.exit_editor_mode();
|
||||
} else if self.render_mode == RenderMode::View {
|
||||
self.render_mode = RenderMode::Live;
|
||||
self.reparse();
|
||||
// Restore keyboard focus to the focused text block.
|
||||
if let Some(tb) = self.text_block_at(self.focused_block) {
|
||||
self.pending_focus = Some(block_editor_id(tb.id));
|
||||
}
|
||||
}
|
||||
self.run_eval_all();
|
||||
}
|
||||
RenderMode::Editor => self.enter_editor_mode(),
|
||||
RenderMode::View => self.enter_view_mode(),
|
||||
RenderMode::View => {
|
||||
self.enter_view_mode();
|
||||
self.run_eval_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::ClearAllBlocks => {
|
||||
|
|
|
|||
|
|
@ -362,6 +362,10 @@ pub fn render(handle: &mut ViewportHandle) {
|
|||
messages.push(Message::SmartEval);
|
||||
consumed.push(ev_idx);
|
||||
}
|
||||
"r" => {
|
||||
messages.push(Message::EvalAll);
|
||||
consumed.push(ev_idx);
|
||||
}
|
||||
"z" if modifiers.shift() => {
|
||||
messages.push(Message::Redo);
|
||||
consumed.push(ev_idx);
|
||||
|
|
|
|||
|
|
@ -304,9 +304,9 @@ pub extern "C" fn viewport_send_command(handle: *mut ViewportHandle, command: u3
|
|||
8 => h.state.update(editor::Message::ZoomOut),
|
||||
9 => h.state.update(editor::Message::ZoomReset),
|
||||
// 11 = live, 12 = editor, 13 = view
|
||||
11 => h.state.exit_editor_mode(),
|
||||
12 => h.state.enter_editor_mode(),
|
||||
13 => h.state.enter_view_mode(),
|
||||
11 => h.state.update(editor::Message::SetRenderMode(editor::RenderMode::Live)),
|
||||
12 => h.state.update(editor::Message::SetRenderMode(editor::RenderMode::Editor)),
|
||||
13 => h.state.update(editor::Message::SetRenderMode(editor::RenderMode::View)),
|
||||
_ => return,
|
||||
};
|
||||
h.needs_redraw = true;
|
||||
|
|
|
|||
Loading…
Reference in New Issue