2 fix block rendering: computed heights, scrollable column, set_text guard
This commit is contained in:
parent
80fd148280
commit
a390a2cc4a
|
|
@ -334,6 +334,12 @@ impl EditorState {
|
|||
}
|
||||
|
||||
pub fn set_text(&mut self, text: &str) {
|
||||
if text.is_empty() && !self.blocks.is_empty() {
|
||||
// Swift sends empty text for untitled docs — keep initial content if present
|
||||
if self.blocks.len() > 1 || !self.blocks[0].content.text().is_empty() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if self.blocks.is_empty() {
|
||||
self.blocks = crate::blocks::parse_blocks(text);
|
||||
} else {
|
||||
|
|
@ -1001,74 +1007,160 @@ impl EditorState {
|
|||
fn view_blocks(&self) -> Element<'_, Message, Theme, iced_wgpu::Renderer> {
|
||||
use crate::blocks::BlockKind;
|
||||
|
||||
let single_text_block = self.blocks.len() == 1
|
||||
&& self.blocks[0].kind == BlockKind::Text;
|
||||
|
||||
let title_bar_h = 38.0_f32;
|
||||
|
||||
let mut block_elements: Vec<Element<'_, Message, Theme, iced_wgpu::Renderer>> = Vec::new();
|
||||
|
||||
if !single_text_block && !self.blocks.is_empty() {
|
||||
if self.blocks[0].kind != BlockKind::Text {
|
||||
block_elements.push(
|
||||
iced_widget::container(iced_widget::text(""))
|
||||
.height(Length::Fixed(title_bar_h))
|
||||
.width(Length::Fill)
|
||||
.into()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (bi, block) in self.blocks.iter().enumerate() {
|
||||
match block.kind {
|
||||
BlockKind::Text => {
|
||||
let top_pad = if bi == 0 { 38.0_f32 } else { 4.0 };
|
||||
let block_idx = bi;
|
||||
let line_h = self.font_size * 1.3;
|
||||
|
||||
let editor = iced_widget::text_editor(&block.content)
|
||||
.on_action(move |action| Message::BlockAction(block_idx, action))
|
||||
.font(Font::MONOSPACE)
|
||||
.size(self.font_size)
|
||||
.height(Length::Fill)
|
||||
.padding(Padding { top: top_pad, right: 8.0, bottom: 8.0, left: 8.0 })
|
||||
.wrapping(Wrapping::Word)
|
||||
.key_binding(macos_key_binding)
|
||||
.style(|_theme, _status| {
|
||||
let p = palette::current();
|
||||
Style {
|
||||
background: Background::Color(p.base),
|
||||
border: Border::default(),
|
||||
placeholder: p.overlay0,
|
||||
value: p.text,
|
||||
selection: Color { a: 0.4, ..p.blue },
|
||||
}
|
||||
});
|
||||
|
||||
let settings = SyntaxSettings {
|
||||
lang: self.lang.clone().unwrap_or_default(),
|
||||
source: block.content.text(),
|
||||
};
|
||||
let editor_el: Element<'_, Message, Theme, iced_wgpu::Renderer> = editor
|
||||
.highlight_with::<SyntaxHighlighter>(
|
||||
settings,
|
||||
|highlight, _theme| Format {
|
||||
color: Some(syntax::highlight_color(highlight.kind)),
|
||||
font: syntax::highlight_font(highlight.kind),
|
||||
},
|
||||
)
|
||||
.into();
|
||||
|
||||
let text = block.content.text();
|
||||
let result_mask: Vec<bool> = text.lines().map(|l| is_result_line(l)).collect();
|
||||
let source_line_count = result_mask.iter().filter(|r| !**r).count();
|
||||
let decors = compute_line_decors(&text);
|
||||
let gutter = Gutter {
|
||||
line_count: block.content.line_count(),
|
||||
source_line_count,
|
||||
font_size: self.font_size,
|
||||
scroll_offset: self.scroll_offset,
|
||||
cursor_line: block.content.cursor().position.line,
|
||||
top_pad,
|
||||
result_mask,
|
||||
line_decors: decors,
|
||||
};
|
||||
let gw = gutter.gutter_width();
|
||||
|
||||
let gutter_canvas: Element<'_, Message, Theme, iced_wgpu::Renderer> =
|
||||
canvas::Canvas::new(gutter)
|
||||
.width(Length::Fixed(gw))
|
||||
if single_text_block {
|
||||
let editor = iced_widget::text_editor(&block.content)
|
||||
.on_action(move |action| Message::BlockAction(block_idx, action))
|
||||
.font(Font::MONOSPACE)
|
||||
.size(self.font_size)
|
||||
.height(Length::Fill)
|
||||
.padding(Padding { top: title_bar_h, right: 8.0, bottom: 8.0, left: 8.0 })
|
||||
.wrapping(Wrapping::Word)
|
||||
.key_binding(macos_key_binding)
|
||||
.style(|_theme, _status| {
|
||||
let p = palette::current();
|
||||
Style {
|
||||
background: Background::Color(p.base),
|
||||
border: Border::default(),
|
||||
placeholder: p.overlay0,
|
||||
value: p.text,
|
||||
selection: Color { a: 0.4, ..p.blue },
|
||||
}
|
||||
});
|
||||
|
||||
let settings = SyntaxSettings {
|
||||
lang: self.lang.clone().unwrap_or_default(),
|
||||
source: block.content.text(),
|
||||
};
|
||||
let editor_el: Element<'_, Message, Theme, iced_wgpu::Renderer> = editor
|
||||
.highlight_with::<SyntaxHighlighter>(
|
||||
settings,
|
||||
|highlight, _theme| Format {
|
||||
color: Some(syntax::highlight_color(highlight.kind)),
|
||||
font: syntax::highlight_font(highlight.kind),
|
||||
},
|
||||
)
|
||||
.into();
|
||||
|
||||
block_elements.push(
|
||||
iced_widget::row![gutter_canvas, editor_el]
|
||||
.height(Length::Fill)
|
||||
let text = block.content.text();
|
||||
let result_mask: Vec<bool> = text.lines().map(|l| is_result_line(l)).collect();
|
||||
let source_line_count = result_mask.iter().filter(|r| !**r).count();
|
||||
let decors = compute_line_decors(&text);
|
||||
let gutter = Gutter {
|
||||
line_count: block.content.line_count(),
|
||||
source_line_count,
|
||||
font_size: self.font_size,
|
||||
scroll_offset: self.scroll_offset,
|
||||
cursor_line: block.content.cursor().position.line,
|
||||
top_pad: title_bar_h,
|
||||
result_mask,
|
||||
line_decors: decors,
|
||||
};
|
||||
let gw = gutter.gutter_width();
|
||||
|
||||
let gutter_canvas: Element<'_, Message, Theme, iced_wgpu::Renderer> =
|
||||
canvas::Canvas::new(gutter)
|
||||
.width(Length::Fixed(gw))
|
||||
.height(Length::Fill)
|
||||
.into();
|
||||
|
||||
block_elements.push(
|
||||
iced_widget::row![gutter_canvas, editor_el]
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
);
|
||||
} else {
|
||||
let top_pad = if bi == 0 { title_bar_h } else { 0.0 };
|
||||
let actual_lines = block.content.line_count().max(1);
|
||||
let editor_h = (actual_lines as f32) * line_h + top_pad + 8.0;
|
||||
|
||||
let editor = iced_widget::text_editor(&block.content)
|
||||
.on_action(move |action| Message::BlockAction(block_idx, action))
|
||||
.font(Font::MONOSPACE)
|
||||
.size(self.font_size)
|
||||
.height(Length::Fixed(editor_h))
|
||||
.padding(Padding { top: top_pad, right: 8.0, bottom: 4.0, left: 8.0 })
|
||||
.wrapping(Wrapping::Word)
|
||||
.key_binding(macos_key_binding)
|
||||
.style(|_theme, _status| {
|
||||
let p = palette::current();
|
||||
Style {
|
||||
background: Background::Color(p.base),
|
||||
border: Border::default(),
|
||||
placeholder: p.overlay0,
|
||||
value: p.text,
|
||||
selection: Color { a: 0.4, ..p.blue },
|
||||
}
|
||||
});
|
||||
|
||||
let settings = SyntaxSettings {
|
||||
lang: self.lang.clone().unwrap_or_default(),
|
||||
source: block.content.text(),
|
||||
};
|
||||
let editor_el: Element<'_, Message, Theme, iced_wgpu::Renderer> = editor
|
||||
.highlight_with::<SyntaxHighlighter>(
|
||||
settings,
|
||||
|highlight, _theme| Format {
|
||||
color: Some(syntax::highlight_color(highlight.kind)),
|
||||
font: syntax::highlight_font(highlight.kind),
|
||||
},
|
||||
)
|
||||
.into();
|
||||
|
||||
let text = block.content.text();
|
||||
let result_mask: Vec<bool> = text.lines().map(|l| is_result_line(l)).collect();
|
||||
let source_line_count = result_mask.iter().filter(|r| !**r).count();
|
||||
let decors = compute_line_decors(&text);
|
||||
let gutter = Gutter {
|
||||
line_count: block.content.line_count(),
|
||||
source_line_count,
|
||||
font_size: self.font_size,
|
||||
scroll_offset: self.scroll_offset,
|
||||
cursor_line: block.content.cursor().position.line,
|
||||
top_pad,
|
||||
result_mask,
|
||||
line_decors: decors,
|
||||
};
|
||||
let gw = gutter.gutter_width();
|
||||
|
||||
let gutter_canvas: Element<'_, Message, Theme, iced_wgpu::Renderer> =
|
||||
canvas::Canvas::new(gutter)
|
||||
.width(Length::Fixed(gw))
|
||||
.height(Length::Fixed(editor_h))
|
||||
.into();
|
||||
|
||||
block_elements.push(
|
||||
iced_widget::container(
|
||||
iced_widget::row![gutter_canvas, editor_el]
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fixed(editor_h))
|
||||
.into()
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
BlockKind::Heading => {
|
||||
let level = match block.heading_level {
|
||||
|
|
@ -1093,7 +1185,18 @@ impl EditorState {
|
|||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
BlockKind::EvalResult => {
|
||||
block_elements.push(
|
||||
crate::eval_block::view::<Message>(&block.eval_text)
|
||||
);
|
||||
}
|
||||
BlockKind::Tree => {
|
||||
if let Some(ref data) = block.tree_data {
|
||||
block_elements.push(
|
||||
crate::tree_block::view::<Message>(data)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1102,10 +1205,11 @@ impl EditorState {
|
|||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
} else if block_elements.len() == 1 {
|
||||
} else if single_text_block {
|
||||
block_elements.remove(0)
|
||||
} else {
|
||||
iced_widget::column(block_elements)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue