From 571485f1a61d98c255783d57de77ed8c5012bea5 Mon Sep 17 00:00:00 2001 From: MinusGix Date: Thu, 28 Mar 2024 16:12:40 -0500 Subject: [PATCH] Update floem for editor styling (#3122) --- Cargo.lock | 12 +- Cargo.toml | 2 +- lapce-app/Cargo.toml | 2 +- lapce-app/benches/visual_line.rs | 4 +- lapce-app/src/app.rs | 12 +- lapce-app/src/doc.rs | 108 ++---------- lapce-app/src/editor.rs | 14 +- lapce-app/src/editor/view.rs | 252 +++++++++++++++++++++------ lapce-app/src/panel/plugin_view.rs | 10 +- lapce-app/src/panel/terminal_view.rs | 6 +- lapce-app/src/text_input.rs | 7 +- 11 files changed, 247 insertions(+), 182 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 568d4e86..48f550ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1672,7 +1672,7 @@ checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" [[package]] name = "floem" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=eba11fbdea84bfac0b90da5f26e1045597e897a4#eba11fbdea84bfac0b90da5f26e1045597e897a4" +source = "git+https://github.com/lapce/floem?rev=fbd5f4db12db93b3fcbe047df6f6cc054e8ff634#fbd5f4db12db93b3fcbe047df6f6cc054e8ff634" dependencies = [ "bitflags 2.5.0", "copypasta", @@ -1734,7 +1734,7 @@ dependencies = [ [[package]] name = "floem-editor-core" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=eba11fbdea84bfac0b90da5f26e1045597e897a4#eba11fbdea84bfac0b90da5f26e1045597e897a4" +source = "git+https://github.com/lapce/floem?rev=fbd5f4db12db93b3fcbe047df6f6cc054e8ff634#fbd5f4db12db93b3fcbe047df6f6cc054e8ff634" dependencies = [ "bitflags 1.3.2", "itertools", @@ -1822,7 +1822,7 @@ dependencies = [ [[package]] name = "floem_reactive" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=eba11fbdea84bfac0b90da5f26e1045597e897a4#eba11fbdea84bfac0b90da5f26e1045597e897a4" +source = "git+https://github.com/lapce/floem?rev=fbd5f4db12db93b3fcbe047df6f6cc054e8ff634#fbd5f4db12db93b3fcbe047df6f6cc054e8ff634" dependencies = [ "smallvec", ] @@ -1830,7 +1830,7 @@ dependencies = [ [[package]] name = "floem_renderer" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=eba11fbdea84bfac0b90da5f26e1045597e897a4#eba11fbdea84bfac0b90da5f26e1045597e897a4" +source = "git+https://github.com/lapce/floem?rev=fbd5f4db12db93b3fcbe047df6f6cc054e8ff634#fbd5f4db12db93b3fcbe047df6f6cc054e8ff634" dependencies = [ "floem-cosmic-text", "floem-peniko", @@ -1841,7 +1841,7 @@ dependencies = [ [[package]] name = "floem_tiny_skia_renderer" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=eba11fbdea84bfac0b90da5f26e1045597e897a4#eba11fbdea84bfac0b90da5f26e1045597e897a4" +source = "git+https://github.com/lapce/floem?rev=fbd5f4db12db93b3fcbe047df6f6cc054e8ff634#fbd5f4db12db93b3fcbe047df6f6cc054e8ff634" dependencies = [ "anyhow", "bytemuck", @@ -1858,7 +1858,7 @@ dependencies = [ [[package]] name = "floem_vger_renderer" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=eba11fbdea84bfac0b90da5f26e1045597e897a4#eba11fbdea84bfac0b90da5f26e1045597e897a4" +source = "git+https://github.com/lapce/floem?rev=fbd5f4db12db93b3fcbe047df6f6cc054e8ff634#fbd5f4db12db93b3fcbe047df6f6cc054e8ff634" dependencies = [ "anyhow", "floem-peniko", diff --git a/Cargo.toml b/Cargo.toml index 9fa5e22e..5eb4cd62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ lapce-core = { path = "./lapce-core" } lapce-rpc = { path = "./lapce-rpc" } lapce-proxy = { path = "./lapce-proxy" } -floem-editor-core = { git = "https://github.com/lapce/floem", rev = "eba11fbdea84bfac0b90da5f26e1045597e897a4", features = ["serde"] } +floem-editor-core = { git = "https://github.com/lapce/floem", rev = "fbd5f4db12db93b3fcbe047df6f6cc054e8ff634", features = ["serde"] } # floem-editor-core = { path = "../workspaces/floem/editor-core/", features = ["serde"] } [patch.crates-io] diff --git a/lapce-app/Cargo.toml b/lapce-app/Cargo.toml index 06d5cae8..798551f7 100644 --- a/lapce-app/Cargo.toml +++ b/lapce-app/Cargo.toml @@ -66,7 +66,7 @@ floem-winit = { version = "0.29.4", features = ["rwh_05"] } [dependencies.floem] # path = "../../workspaces/floem" git = "https://github.com/lapce/floem" -rev = "eba11fbdea84bfac0b90da5f26e1045597e897a4" +rev = "fbd5f4db12db93b3fcbe047df6f6cc054e8ff634" default-features = true features = ["editor", "serde"] diff --git a/lapce-app/benches/visual_line.rs b/lapce-app/benches/visual_line.rs index e731d9f7..7a46f09b 100644 --- a/lapce-app/benches/visual_line.rs +++ b/lapce-app/benches/visual_line.rs @@ -8,7 +8,7 @@ layout::TextLayoutLine, phantom_text::PhantomTextLine, visual_line::{ - FontSizeCacheId, LineFontSizeProvider, Lines, ResolvedWrap, + ConfigId, FontSizeCacheId, LineFontSizeProvider, Lines, ResolvedWrap, TextLayoutProvider, VLine, }, }, @@ -167,7 +167,7 @@ fn make_lines_ph( lines.set_wrap(wrap); if init { - lines.init_all(0, 0, &text, true); + lines.init_all(0, ConfigId::new(0, 0), &text, true); } (text, lines) diff --git a/lapce-app/src/app.rs b/lapce-app/src/app.rs index 8f129547..a0dde766 100644 --- a/lapce-app/src/app.rs +++ b/lapce-app/src/app.rs @@ -33,8 +33,10 @@ view::{View, Widget}, views::{ clip, container, drag_resize_window_area, drag_window_area, dyn_stack, - empty, label, rich_text, scroll::scroll, stack, svg, tab, text, tooltip, - virtual_stack, Decorators, VirtualDirection, VirtualItemSize, VirtualVector, + empty, label, rich_text, + scroll::{scroll, HideBar, VerticalScrollAsHorizontal}, + stack, svg, tab, text, tooltip, virtual_stack, Decorators, VirtualDirection, + VirtualItemSize, VirtualVector, }, window::{ResizeDirection, WindowConfig, WindowId}, EventPropagation, @@ -941,10 +943,10 @@ fn editor_tab_header( .with_untracked(|editor_tab| editor_tab.children[active].1) .get_untracked() }) - .hide_bar(|| true) - .vertical_scroll_as_horizontal(|| true) .style(|s| { - s.position(Position::Absolute) + s.set(HideBar, true) + .set(VerticalScrollAsHorizontal, true) + .position(Position::Absolute) .height_full() .max_width_full() }) diff --git a/lapce-app/src/doc.rs b/lapce-app/src/doc.rs index 20bfb8c3..3f9010c1 100644 --- a/lapce-app/src/doc.rs +++ b/lapce-app/src/doc.rs @@ -18,17 +18,13 @@ reactive::{batch, ReadSignal, RwSignal, Scope}, views::editor::{ actions::CommonAction, - color::EditorColor, command::{Command, CommandExecuted}, id::EditorId, layout::{LineExtraStyle, TextLayoutLine}, phantom_text::{PhantomText, PhantomTextKind, PhantomTextLine}, - text::{ - Document, DocumentPhantom, PreeditData, RenderWhitespace, Styling, - SystemClipboard, WrapMethod, - }, + text::{Document, DocumentPhantom, PreeditData, Styling, SystemClipboard}, view::{ScreenLines, ScreenLinesBase}, - CursorInfo, Editor, + CursorInfo, Editor, EditorStyle, }, }; use itertools::Itertools; @@ -71,7 +67,7 @@ use crate::{ command::{CommandKind, LapceCommand}, - config::{color::LapceColor, editor::WrapStyle, LapceConfig}, + config::{color::LapceColor, LapceConfig}, editor::{compute_screen_lines, EditorData}, find::{Find, FindProgress, FindResult}, history::DocumentHistory, @@ -369,49 +365,6 @@ pub fn create_editor(self: &Rc, cx: Scope, id: EditorId) -> Editor { editor.cursor_info = cursor_info; editor.ime_allowed = common.window_common.ime_allowed; - // Updating editor fields based on config - let ed = editor.clone(); - cx.create_effect(move |_| { - let config = config.get(); - - batch(|| { - if ed.scroll_beyond_last_line.get_untracked() - != config.editor.scroll_beyond_last_line - { - ed.scroll_beyond_last_line - .set(config.editor.scroll_beyond_last_line); - } - - if ed.cursor_surrounding_lines.get_untracked() - != config.editor.cursor_surrounding_lines - { - ed.cursor_surrounding_lines - .set(config.editor.cursor_surrounding_lines); - } - - if ed.show_indent_guide.get_untracked() - != config.editor.show_indent_guide - { - ed.show_indent_guide.set(config.editor.show_indent_guide); - } - - if ed.modal_relative_line_numbers.get_untracked() - != config.editor.modal_mode_relative_line_numbers - { - ed.modal_relative_line_numbers - .set(config.editor.modal_mode_relative_line_numbers); - } - - if ed.smart_tab.get_untracked() != config.editor.smart_tab { - ed.smart_tab.set(config.editor.smart_tab); - } - - if ed.modal.get_untracked() != config.core.modal { - ed.modal.set(config.core.modal); - } - }); - }); - editor.recreate_view_effects(); editor @@ -1458,6 +1411,7 @@ fn compute_screen_lines( &editor_data.doc_signal().get(), editor.lines(), editor.text_prov(), + editor.config_id(), ) } @@ -1504,7 +1458,7 @@ impl DocumentPhantom for Doc { fn phantom_text( &self, _: EditorId, - _: &dyn Styling, + _: &EditorStyle, line: usize, ) -> PhantomTextLine { let config = &self.common.config.get_untracked(); @@ -1674,7 +1628,7 @@ fn phantom_text( PhantomTextLine { text } } - fn has_multiline_phantom(&self, _: EditorId, _: &dyn Styling) -> bool { + fn has_multiline_phantom(&self, _: EditorId, _: &EditorStyle) -> bool { // TODO: actually check true } @@ -1719,9 +1673,6 @@ fn do_edit( } } -/// Minimum width that we'll allow the view to be wrapped at. -const MIN_WRAPPED_WIDTH: f32 = 100.0; - #[derive(Clone)] pub struct DocStyling { config: ReadSignal>, @@ -1731,12 +1682,13 @@ impl DocStyling { fn apply_colorization( &self, edid: EditorId, + style: &EditorStyle, line: usize, attrs: &Attrs, attrs_list: &mut AttrsList, ) { let config = self.config.get_untracked(); - let phantom_text = self.doc.phantom_text(edid, self, line); + let phantom_text = self.doc.phantom_text(edid, style, line); if let Some(bracket_styles) = self.doc.parser.borrow().bracket_pos.get(&line) { for bracket_style in bracket_styles.iter() { @@ -1789,10 +1741,6 @@ fn stretch(&self, _: EditorId, _line: usize) -> floem::cosmic_text::Stretch { floem::cosmic_text::Stretch::Normal } - fn indent_style(&self) -> IndentStyle { - self.doc.buffer.with_untracked(|b| b.indent_style()) - } - fn indent_line(&self, _: EditorId, line: usize, line_content: &str) -> usize { if line_content.trim().is_empty() { let text = self.doc.rope_text(); @@ -1819,15 +1767,16 @@ fn atomic_soft_tabs(&self, _: EditorId, _line: usize) -> bool { fn apply_attr_styles( &self, edid: EditorId, + style: &EditorStyle, line: usize, default: Attrs, attrs_list: &mut AttrsList, ) { let config = self.doc.common.config.get_untracked(); - self.apply_colorization(edid, line, &default, attrs_list); + self.apply_colorization(edid, style, line, &default, attrs_list); - let phantom_text = self.doc.phantom_text(edid, self, line); + let phantom_text = self.doc.phantom_text(edid, style, line); for line_style in self.doc.line_style(line).iter() { if let Some(fg_color) = line_style.style.fg_color.as_ref() { if let Some(fg_color) = config.style_color(fg_color) { @@ -1839,30 +1788,10 @@ fn apply_attr_styles( } } - fn wrap(&self, _: EditorId) -> WrapMethod { - let wrap_style = self - .config - .with_untracked(|config| config.editor.wrap_style); - match wrap_style { - WrapStyle::None => WrapMethod::None, - WrapStyle::EditorWidth => WrapMethod::EditorWidth, - WrapStyle::WrapWidth => WrapMethod::WrapWidth { - width: self - .config - .with_untracked(|config| config.editor.wrap_width as f32) - .max(MIN_WRAPPED_WIDTH), - }, - } - } - - fn render_whitespace(&self, _: EditorId) -> RenderWhitespace { - self.config - .with_untracked(|config| config.editor.render_whitespace) - } - fn apply_layout_styles( &self, edid: EditorId, + style: &EditorStyle, line: usize, layout_line: &mut TextLayoutLine, ) { @@ -1872,7 +1801,7 @@ fn apply_layout_styles( layout_line.extra_style.clear(); let layout = &layout_line.text; - let phantom_text = doc.phantom_text(edid, self, line); + let phantom_text = doc.phantom_text(edid, style, line); let phantom_styles = phantom_text .offset_size_iter() @@ -1978,17 +1907,6 @@ fn apply_layout_styles( }); } - fn color(&self, _: EditorId, color: EditorColor) -> Color { - let name = match color { - EditorColor::Scrollbar => LapceColor::LAPCE_SCROLL_BAR, - EditorColor::DropdownShadow => LapceColor::LAPCE_DROPDOWN_SHADOW, - EditorColor::PreeditUnderline => LapceColor::EDITOR_FOREGROUND, - _ => color.into(), - }; - - self.config.with_untracked(|config| config.color(name)) - } - fn paint_caret(&self, edid: EditorId, _line: usize) -> bool { let Some(e_data) = self.doc.editor_data(edid) else { return true; diff --git a/lapce-app/src/editor.rs b/lapce-app/src/editor.rs index 6c4ebfc0..786ef093 100644 --- a/lapce-app/src/editor.rs +++ b/lapce-app/src/editor.rs @@ -22,7 +22,7 @@ view::{ DiffSection, DiffSectionKind, LineInfo, ScreenLines, ScreenLinesBase, }, - visual_line::{Lines, TextLayoutProvider, VLine, VLineInfo}, + visual_line::{ConfigId, Lines, TextLayoutProvider, VLine, VLineInfo}, Editor, }, }; @@ -378,11 +378,8 @@ pub fn rope_text(&self) -> RopeTextVal { fn run_edit_command(&self, cmd: &EditCommand) -> CommandExecuted { let doc = self.doc(); let text = self.editor.rope_text(); - let modal = self - .common - .config - .with_untracked(|config| config.core.modal) - && !doc.content.with_untracked(|content| content.is_local()); + let is_local = doc.content.with_untracked(|content| content.is_local()); + let modal = self.editor.es.with_untracked(|s| s.modal()) && !is_local; let smart_tab = self .common .config @@ -2833,6 +2830,7 @@ pub(crate) fn compute_screen_lines( doc: &Doc, lines: &Lines, text_prov: impl TextLayoutProvider + Clone, + config_id: ConfigId, ) -> ScreenLines { // TODO: this should probably be a get since we need to depend on line-height let config = config.get(); @@ -2885,7 +2883,7 @@ pub(crate) fn compute_screen_lines( .iter_rvlines_init( text_prov, cache_rev, - config.id, + config_id, min_info.rvline, false, ) @@ -3083,7 +3081,7 @@ pub(crate) fn compute_screen_lines( .iter_rvlines_init( &text_prov, cache_rev, - config.id, + config_id, start_rvline, false, ) diff --git a/lapce-app/src/editor/view.rs b/lapce-app/src/editor/view.rs index ddfeb149..1d3c56d5 100644 --- a/lapce-app/src/editor/view.rs +++ b/lapce-app/src/editor/view.rs @@ -2,7 +2,7 @@ use floem::{ action::{set_ime_allowed, set_ime_cursor_area}, - context::PaintCx, + context::{PaintCx, StyleCx}, event::{Event, EventListener}, id::Id, keyboard::ModifiersState, @@ -13,36 +13,43 @@ reactive::{ create_effect, create_memo, create_rw_signal, Memo, ReadSignal, RwSignal, }, - style::{CursorStyle, Style}, + style::{CursorStyle, Style, TextColor}, taffy::prelude::NodeId, view::{AnyWidget, View, ViewData, Widget}, views::{ clip, container, dyn_stack, editor::{ + text::WrapMethod, view::{ - cursor_caret, DiffSectionKind, EditorView as FloemEditorView, - LineRegion, ScreenLines, + cursor_caret, CaretColor, CurrentLineColor, DiffSectionKind, + EditorView as FloemEditorView, EditorViewClass, EditorViewStyle, + IndentGuideColor, IndentStyleProp, LineRegion, ScreenLines, + SelectionColor, VisibleWhitespaceColor, }, visual_line::{RVLine, VLine}, - Editor, + CursorSurroundingLines, Editor, Modal, ModalRelativeLine, PhantomColor, + PlaceholderColor, PreeditUnderlineColor, RenderWhitespaceProp, + ScrollBeyondLastLine, ShowIndentGuide, SmartTab, WrapProp, }, - empty, label, scroll, stack, svg, Decorators, + empty, label, + scroll::{scroll, HideBar}, + stack, svg, Decorators, }, EventPropagation, Renderer, }; use itertools::Itertools; use lapce_core::{ - buffer::{diff::DiffLines, rope_text::RopeText}, + buffer::{diff::DiffLines, rope_text::RopeText, Buffer}, cursor::{CursorAffinity, CursorMode}, }; use lapce_rpc::dap_types::{DapId, SourceBreakpoint}; use lapce_xi_rope::find::CaseMatching; -use super::{gutter::editor_gutter_view, EditorData}; +use super::{gutter::editor_gutter_view, DocSignal, EditorData}; use crate::{ app::clickable_icon, command::InternalCommand, - config::{color::LapceColor, icon::LapceIcons, LapceConfig}, + config::{color::LapceColor, editor::WrapStyle, icon::LapceIcons, LapceConfig}, debug::LapceBreakpoint, doc::DocContent, text_input::TextInputBuilder, @@ -56,6 +63,71 @@ struct StickyHeaderInfo { y_diff: f64, } +fn editor_wrap(config: &LapceConfig) -> WrapMethod { + /// Minimum width that we'll allow the view to be wrapped at. + const MIN_WRAPPED_WIDTH: f32 = 100.0; + + match config.editor.wrap_style { + WrapStyle::None => WrapMethod::None, + WrapStyle::EditorWidth => WrapMethod::EditorWidth, + WrapStyle::WrapWidth => WrapMethod::WrapWidth { + width: (config.editor.wrap_width as f32).max(MIN_WRAPPED_WIDTH), + }, + } +} + +pub fn editor_style( + config: ReadSignal>, + doc: DocSignal, + s: Style, +) -> Style { + let config = config.get(); + let doc = doc.get(); + // s.class(EditorViewClass, |s| { + + s.set( + IndentStyleProp, + doc.buffer.with_untracked(Buffer::indent_style), + ) + .set(CaretColor, config.color(LapceColor::EDITOR_CARET)) + .set(SelectionColor, config.color(LapceColor::EDITOR_SELECTION)) + .set( + CurrentLineColor, + config.color(LapceColor::EDITOR_CURRENT_LINE), + ) + .set( + VisibleWhitespaceColor, + config.color(LapceColor::EDITOR_VISIBLE_WHITESPACE), + ) + .set( + IndentGuideColor, + config.color(LapceColor::EDITOR_INDENT_GUIDE), + ) + .set(ScrollBeyondLastLine, config.editor.scroll_beyond_last_line) + // }) + .color(config.color(LapceColor::EDITOR_FOREGROUND)) + .set(TextColor, config.color(LapceColor::EDITOR_FOREGROUND)) + .set(PhantomColor, config.color(LapceColor::EDITOR_DIM)) + .set(PlaceholderColor, config.color(LapceColor::EDITOR_DIM)) + .set( + PreeditUnderlineColor, + config.color(LapceColor::EDITOR_FOREGROUND), + ) + .set(ShowIndentGuide, config.editor.show_indent_guide) + .set(Modal, config.core.modal) + .set( + ModalRelativeLine, + config.editor.modal_mode_relative_line_numbers, + ) + .set(SmartTab, config.editor.smart_tab) + .set(WrapProp, editor_wrap(&config)) + .set( + CursorSurroundingLines, + config.editor.cursor_surrounding_lines, + ) + .set(RenderWhitespaceProp, config.editor.render_whitespace) +} + pub struct EditorView { data: ViewData, editor: EditorData, @@ -64,6 +136,7 @@ pub struct EditorView { viewport: RwSignal, debug_breakline: Memo>, sticky_header_info: StickyHeaderInfo, + editor_view_style: EditorViewStyle, } pub fn editor_view( @@ -174,6 +247,7 @@ pub fn editor_view( } }); + let doc = e_data.doc_signal(); EditorView { data: ViewData::new(id), editor: e_data, @@ -186,6 +260,7 @@ pub fn editor_view( last_sticky_should_scroll: false, y_diff: 0.0, }, + editor_view_style: Default::default(), } .on_event(EventListener::ImePreedit, move |event| { if !is_active.get_untracked() { @@ -213,6 +288,8 @@ pub fn editor_view( } EventPropagation::Stop }) + .class(EditorViewClass) + .style(move |s| editor_style(config, doc, s)) } impl EditorView { @@ -329,6 +406,7 @@ fn paint_cursor( cx: &mut PaintCx, is_local: bool, screen_lines: &ScreenLines, + editor_style: &EditorViewStyle, ) { let e_data = self.editor.clone(); let ed = e_data.editor.clone(); @@ -342,7 +420,7 @@ fn paint_cursor( let is_active = self.is_active.get_untracked() && !find_focus.get_untracked(); - let current_line_color = config.color(LapceColor::EDITOR_CURRENT_LINE); + let current_line_color = editor_style.current_line(); let breakline = self.debug_breakline.get_untracked().and_then( |(breakline, breakline_path)| { @@ -380,29 +458,37 @@ fn paint_cursor( CursorMode::Visual { .. } => false, }; - // Highlight the current line - if !is_local && highlight_current_line { - for (_, end) in cursor.regions_iter() { - // TODO: unsure if this is correct for wrapping lines - let rvline = ed.rvline_of_offset(end, cursor.affinity); + if let Some(current_line_color) = current_line_color { + // Highlight the current line + if !is_local && highlight_current_line { + for (_, end) in cursor.regions_iter() { + // TODO: unsure if this is correct for wrapping lines + let rvline = ed.rvline_of_offset(end, cursor.affinity); - if let Some(info) = screen_lines - .info(rvline) - .filter(|_| Some(rvline.line) != breakline) - { - let rect = Rect::from_origin_size( - (viewport.x0, info.vline_y), - (viewport.width(), line_height), - ); + if let Some(info) = screen_lines + .info(rvline) + .filter(|_| Some(rvline.line) != breakline) + { + let rect = Rect::from_origin_size( + (viewport.x0, info.vline_y), + (viewport.width(), line_height), + ); - cx.fill(&rect, current_line_color, 0.0); + cx.fill(&rect, current_line_color, 0.0); + } } } } - FloemEditorView::paint_selection(cx, &ed, screen_lines); + FloemEditorView::paint_selection(cx, &ed, screen_lines, editor_style); - FloemEditorView::paint_cursor_caret(cx, &ed, is_active, screen_lines); + FloemEditorView::paint_cursor_caret( + cx, + &ed, + is_active, + screen_lines, + editor_style, + ); }); } @@ -629,7 +715,17 @@ fn paint_scroll_bar( return; } - FloemEditorView::paint_scroll_bar(cx, &self.editor.editor, viewport); + cx.fill( + &Rect::ZERO + .with_size(Size::new(1.0, viewport.height())) + .with_origin(Point::new( + viewport.x0 + viewport.width() - BAR_WIDTH, + viewport.y0, + )) + .inflate(0.0, 10.0), + config.color(LapceColor::LAPCE_SCROLL_BAR), + 0.0, + ); if !self.editor.kind.get_untracked().is_normal() { return; @@ -929,6 +1025,27 @@ fn view_data_mut(&mut self) -> &mut ViewData { &mut self.data } + fn style(&mut self, cx: &mut StyleCx<'_>) { + if self.editor_view_style.read(cx) { + cx.app_state_mut().request_paint(self.id()); + } + + let editor = &self.editor.editor; + if editor.es.try_update(|s| s.read(cx)).unwrap() { + editor.floem_style_id.update(|val| *val += 1); + cx.app_state_mut().request_paint(self.id()); + } + + self.for_each_child_mut(&mut |child| { + cx.style_view(child); + false + }); + } + + fn debug_name(&self) -> std::borrow::Cow<'static, str> { + "Editor View".into() + } + fn update( &mut self, cx: &mut floem::context::UpdateCx, @@ -950,10 +1067,14 @@ fn layout( } let e_data = &self.editor; + let editor = &e_data.editor; + + let parent_size = editor.parent_size.get_untracked(); + let screen_lines = e_data.screen_lines().get_untracked(); for (line, _) in screen_lines.iter_lines_y() { // fill in text layout cache so that max width is correct. - e_data.editor.text_layout(line); + editor.text_layout(line); } let inner_node = self.inner_node.unwrap(); @@ -961,10 +1082,22 @@ fn layout( let config = self.editor.common.config.get_untracked(); let line_height = config.editor.line_height() as f64; - let width = e_data.editor.max_line_width() + 20.0; - let height = line_height * e_data.editor.last_vline().get() as f64; + let width = editor.max_line_width().max(parent_size.width()); + let last_line_height = + line_height * (editor.last_vline().get() + 1) as f64; + let height = last_line_height.max(parent_size.height()); - let style = Style::new().width(width).height(height).to_taffy_style(); + let margin_bottom = if self.editor_view_style.scroll_beyond_last_line() { + parent_size.height().min(last_line_height) - line_height + } else { + 0.0 + }; + + let style = Style::new() + .width(width) + .height(height) + .margin_bottom(margin_bottom) + .to_taffy_style(); cx.set_style(inner_node, style); vec![inner_node] @@ -975,10 +1108,17 @@ fn compute_layout( &mut self, cx: &mut floem::context::ComputeLayoutCx, ) -> Option { + let editor = &self.editor.editor; let viewport = cx.current_viewport(); if self.viewport.with_untracked(|v| v != &viewport) { self.viewport.set(viewport); } + let parent_size = cx + .app_state_mut() + .get_layout_rect(self.id().parent().unwrap()); + if editor.parent_size.with_untracked(|ps| ps != &parent_size) { + editor.parent_size.set(parent_size); + } None } @@ -999,7 +1139,7 @@ fn paint(&mut self, cx: &mut PaintCx) { // I expect that most/all of the paint functions could restrict themselves to only what is // within the active screen lines without issue. let screen_lines = ed.screen_lines.get_untracked(); - self.paint_cursor(cx, is_local, &screen_lines); + self.paint_cursor(cx, is_local, &screen_lines, &self.editor_view_style); let screen_lines = ed.screen_lines.get_untracked(); self.paint_diff_sections(cx, viewport, &screen_lines, &config); let screen_lines = ed.screen_lines.get_untracked(); @@ -1007,7 +1147,13 @@ fn paint(&mut self, cx: &mut PaintCx) { let screen_lines = ed.screen_lines.get_untracked(); self.paint_bracket_highlights_scope_lines(cx, viewport, &screen_lines); let screen_lines = ed.screen_lines.get_untracked(); - FloemEditorView::paint_text(cx, ed, viewport, &screen_lines); + FloemEditorView::paint_text( + cx, + ed, + viewport, + &screen_lines, + &self.editor_view_style, + ); let screen_lines = ed.screen_lines.get_untracked(); self.paint_sticky_headers(cx, viewport, &screen_lines); self.paint_scroll_bar(cx, viewport, is_local, config); @@ -1153,11 +1299,9 @@ pub fn editor_container_view( let replace_focus = main_split.common.find.replace_focus; let debug_breakline = window_tab_data.terminal.breakline; - let editor_rect = create_rw_signal(Rect::ZERO); - stack(( editor_breadcrumbs(workspace, editor.get_untracked(), config), - container( + clip( stack(( editor_gutter(window_tab_data.clone(), editor, is_active), container(editor_content(editor, debug_breakline, is_active)) @@ -1189,9 +1333,6 @@ pub fn editor_container_view( is_active, ), )) - .on_resize(move |rect| { - editor_rect.set(rect); - }) .style(|s| s.absolute().size_pct(100.0, 100.0)), ) .style(|s| s.size_pct(100.0, 100.0)), @@ -1618,9 +1759,9 @@ fn editor_breadcrumbs( doc.track(); Some(Point::new(3000.0, 0.0)) }) - .hide_bar(|| true) .style(move |s| { - s.absolute() + s.set(HideBar, true) + .absolute() .size_pct(100.0, 100.0) .border_bottom(1.0) .border_color(config.get().color(LapceColor::LAPCE_BORDER)) @@ -1666,17 +1807,18 @@ fn editor_content( let editor_content_view = editor_view(e_data.get_untracked(), debug_breakline, is_active).style( move |s| { - let config = config.get(); - let padding_bottom = if config.editor.scroll_beyond_last_line { - viewport.get().height() as f32 - - config.editor.line_height() as f32 - } else { - 0.0 - }; - s.absolute() - .padding_bottom(padding_bottom) - .cursor(CursorStyle::Text) - .min_size_pct(100.0, 100.0) + // let config = config.get(); + s.absolute().cursor(CursorStyle::Text) + // let padding_bottom = if config.editor.scroll_beyond_last_line { + // viewport.get().height() as f32 + // - config.editor.line_height() as f32 + // } else { + // 0.0 + // }; + // s.absolute() + // .padding_bottom(padding_bottom) + // .cursor(CursorStyle::Text) + // .min_size_pct(100.0, 100.0) }, ); let id = editor_content_view.id(); @@ -1748,10 +1890,12 @@ fn editor_content( if jump_to_middle { rect.inflate(0.0, viewport.height() / 2.0) } else { + let cursor_surrounding_lines = + e_data.editor.es.with(|s| s.cursor_surrounding_lines()); let mut rect = rect; - rect.y0 -= (config.editor.cursor_surrounding_lines * line_height) as f64 + rect.y0 -= (cursor_surrounding_lines * line_height) as f64 + sticky_header_height.get_untracked(); - rect.y1 += (config.editor.cursor_surrounding_lines * line_height) as f64; + rect.y1 += (cursor_surrounding_lines * line_height) as f64; rect } }) diff --git a/lapce-app/src/panel/plugin_view.rs b/lapce-app/src/panel/plugin_view.rs index 984b1c34..903b29fd 100644 --- a/lapce-app/src/panel/plugin_view.rs +++ b/lapce-app/src/panel/plugin_view.rs @@ -7,8 +7,10 @@ style::CursorStyle, view::View, views::{ - container, dyn_container, img, label, scroll::scroll, stack, svg, - virtual_stack, Decorators, VirtualDirection, VirtualItemSize, VirtualVector, + container, dyn_container, img, label, + scroll::{scroll, HideBar}, + stack, svg, virtual_stack, Decorators, VirtualDirection, VirtualItemSize, + VirtualVector, }, }; use indexmap::IndexMap; @@ -334,13 +336,13 @@ fn available_view(plugin: PluginData) -> impl View { .to_rect() .with_origin(Point::new(cursor_x.get(), 0.0)) }) - .hide_bar(|| true) .on_event_cont(EventListener::PointerDown, move |_| { focus.set(Focus::Panel(PanelKind::Plugin)); }) .style(move |s| { let config = config.get(); - s.width_pct(100.0) + s.set(HideBar, true) + .width_pct(100.0) .cursor(CursorStyle::Text) .items_center() .background(config.color(LapceColor::EDITOR_BACKGROUND)) diff --git a/lapce-app/src/panel/terminal_view.rs b/lapce-app/src/panel/terminal_view.rs index 62d5f3a1..476ac85b 100644 --- a/lapce-app/src/panel/terminal_view.rs +++ b/lapce-app/src/panel/terminal_view.rs @@ -7,7 +7,7 @@ view::View, views::{ container, dyn_stack, empty, label, - scroll::{scroll, Thickness}, + scroll::{scroll, Thickness, VerticalScrollAsHorizontal}, stack, svg, tab, Decorators, }, EventPropagation, @@ -196,7 +196,6 @@ fn terminal_tab_header(window_tab_data: Rc) -> impl View { ) }, )) - .vertical_scroll_as_horizontal(|| true) .on_resize(move |rect| { if rect.size() != scroll_size.get_untracked() { scroll_size.set(rect.size()); @@ -205,7 +204,8 @@ fn terminal_tab_header(window_tab_data: Rc) -> impl View { .style(move |s| { let header_width = header_width.get(); let icon_width = icon_width.get(); - s.absolute() + s.set(VerticalScrollAsHorizontal, true) + .absolute() .max_width(header_width - icon_width) .set(Thickness, 3) }), diff --git a/lapce-app/src/text_input.rs b/lapce-app/src/text_input.rs index 7bde90fc..8efbd91e 100644 --- a/lapce-app/src/text_input.rs +++ b/lapce-app/src/text_input.rs @@ -35,7 +35,7 @@ use crate::{ config::{color::LapceColor, LapceConfig}, doc::Doc, - editor::{DocSignal, EditorData}, + editor::{view::editor_style, DocSignal, EditorData}, keypress::KeyPressFocus, main_split::Editors, window_tab::CommonData, @@ -235,8 +235,9 @@ fn text_input_full( hide_cursor: editor.cursor_info.hidden, style: Default::default(), } - .style(|s| { - s.cursor(CursorStyle::Text) + .style(move |s| { + editor_style(config, doc, s) + .cursor(CursorStyle::Text) .padding_horiz(10.0) .padding_vert(6.0) })