WIP: start on editor element
This commit is contained in:
parent
580694dbda
commit
d3b02c4de4
5 changed files with 215 additions and 94 deletions
|
@ -37,8 +37,8 @@ use futures::FutureExt;
|
||||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, AnyElement, AppContext, BackgroundExecutor, Context, Div, Element, EventEmitter,
|
div, AnyElement, AppContext, BackgroundExecutor, Context, Div, Element, EventEmitter,
|
||||||
FocusHandle, Hsla, Model, Pixels, Render, Subscription, Task, TextStyle, View, ViewContext,
|
FocusHandle, Hsla, Model, Pixels, Render, Styled, Subscription, Task, TextStyle, View,
|
||||||
VisualContext, WeakView, WindowContext,
|
ViewContext, VisualContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||||
use hover_popover::{hide_hover, HoverState};
|
use hover_popover::{hide_hover, HoverState};
|
||||||
|
@ -68,6 +68,7 @@ use scroll::{
|
||||||
use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
|
use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
|
@ -8347,51 +8348,51 @@ impl Editor {
|
||||||
// .text()
|
// .text()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
|
pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
|
||||||
// let mut wrap_guides = smallvec::smallvec![];
|
let mut wrap_guides = smallvec::smallvec![];
|
||||||
|
|
||||||
// if self.show_wrap_guides == Some(false) {
|
if self.show_wrap_guides == Some(false) {
|
||||||
// return wrap_guides;
|
return wrap_guides;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// let settings = self.buffer.read(cx).settings_at(0, cx);
|
let settings = self.buffer.read(cx).settings_at(0, cx);
|
||||||
// if settings.show_wrap_guides {
|
if settings.show_wrap_guides {
|
||||||
// if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
|
if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
|
||||||
// wrap_guides.push((soft_wrap as usize, true));
|
wrap_guides.push((soft_wrap as usize, true));
|
||||||
// }
|
}
|
||||||
// wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
|
wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
|
||||||
// }
|
}
|
||||||
|
|
||||||
// wrap_guides
|
wrap_guides
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
|
pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
|
||||||
// let settings = self.buffer.read(cx).settings_at(0, cx);
|
let settings = self.buffer.read(cx).settings_at(0, cx);
|
||||||
// let mode = self
|
let mode = self
|
||||||
// .soft_wrap_mode_override
|
.soft_wrap_mode_override
|
||||||
// .unwrap_or_else(|| settings.soft_wrap);
|
.unwrap_or_else(|| settings.soft_wrap);
|
||||||
// match mode {
|
match mode {
|
||||||
// language_settings::SoftWrap::None => SoftWrap::None,
|
language_settings::SoftWrap::None => SoftWrap::None,
|
||||||
// language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
|
language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
|
||||||
// language_settings::SoftWrap::PreferredLineLength => {
|
language_settings::SoftWrap::PreferredLineLength => {
|
||||||
// SoftWrap::Column(settings.preferred_line_length)
|
SoftWrap::Column(settings.preferred_line_length)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub fn set_soft_wrap_mode(
|
pub fn set_soft_wrap_mode(
|
||||||
// &mut self,
|
&mut self,
|
||||||
// mode: language_settings::SoftWrap,
|
mode: language_settings::SoftWrap,
|
||||||
// cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
// ) {
|
) {
|
||||||
// self.soft_wrap_mode_override = Some(mode);
|
self.soft_wrap_mode_override = Some(mode);
|
||||||
// cx.notify();
|
cx.notify();
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut AppContext) -> bool {
|
pub fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut AppContext) -> bool {
|
||||||
// self.display_map
|
self.display_map
|
||||||
// .update(cx, |map, cx| map.set_wrap_width(width, cx))
|
.update(cx, |map, cx| map.set_wrap_width(width, cx))
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
|
// pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
|
||||||
// if self.soft_wrap_mode_override.is_some() {
|
// if self.soft_wrap_mode_override.is_some() {
|
||||||
|
@ -9321,11 +9322,14 @@ impl EventEmitter for Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for Editor {
|
impl Render for Editor {
|
||||||
type Element = Div<Self>;
|
type Element = EditorElement;
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||||
// todo!()
|
EditorElement::new(EditorStyle {
|
||||||
div()
|
text: cx.text_style(),
|
||||||
|
line_height_scalar: 1.,
|
||||||
|
theme_id: 0,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,18 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
display_map::{BlockStyle, DisplaySnapshot},
|
display_map::{BlockStyle, DisplaySnapshot},
|
||||||
EditorStyle,
|
EditorMode, EditorStyle, SoftWrap,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
black, px, relative, AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, TextRun,
|
black, point, px, relative, size, AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style,
|
||||||
TextSystem,
|
TextRun, TextSystem, ViewContext,
|
||||||
};
|
};
|
||||||
use language::{CursorShape, Selection};
|
use language::{CursorShape, Selection};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{ops::Range, sync::Arc};
|
use std::{cmp, ops::Range, sync::Arc};
|
||||||
use sum_tree::Bias;
|
use sum_tree::Bias;
|
||||||
|
use theme::ActiveTheme;
|
||||||
|
|
||||||
enum FoldMarkers {}
|
enum FoldMarkers {}
|
||||||
|
|
||||||
|
@ -1321,29 +1322,31 @@ impl EditorElement {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// fn column_pixels(&self, column: usize, cx: &ViewContext<Editor>) -> f32 {
|
fn column_pixels(&self, column: usize, cx: &ViewContext<Editor>) -> Pixels {
|
||||||
// let style = &self.style;
|
let style = &self.style;
|
||||||
|
let font_size = style.text.font_size * cx.rem_size();
|
||||||
|
let layout = cx
|
||||||
|
.text_system()
|
||||||
|
.layout_text(
|
||||||
|
" ".repeat(column).as_str(),
|
||||||
|
font_size,
|
||||||
|
&[TextRun {
|
||||||
|
len: column,
|
||||||
|
font: style.text.font(),
|
||||||
|
color: Hsla::default(),
|
||||||
|
underline: None,
|
||||||
|
}],
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// cx.text_layout_cache()
|
layout[0].width
|
||||||
// .layout_str(
|
}
|
||||||
// " ".repeat(column).as_str(),
|
|
||||||
// style.text.font_size,
|
|
||||||
// &[(
|
|
||||||
// column,
|
|
||||||
// RunStyle {
|
|
||||||
// font_id: style.text.font_id,
|
|
||||||
// color: Color::black(),
|
|
||||||
// underline: Default::default(),
|
|
||||||
// },
|
|
||||||
// )],
|
|
||||||
// )
|
|
||||||
// .width()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext<Editor>) -> f32 {
|
fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext<Editor>) -> Pixels {
|
||||||
// let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1;
|
let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1;
|
||||||
// self.column_pixels(digit_count, cx)
|
self.column_pixels(digit_count, cx)
|
||||||
// }
|
}
|
||||||
|
|
||||||
//Folds contained in a hunk are ignored apart from shrinking visual size
|
//Folds contained in a hunk are ignored apart from shrinking visual size
|
||||||
//If a fold contains any hunks then that fold line is marked as modified
|
//If a fold contains any hunks then that fold line is marked as modified
|
||||||
|
@ -2002,6 +2005,7 @@ impl Element<Editor> for EditorElement {
|
||||||
element_state: &mut Self::ElementState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut gpui::ViewContext<Editor>,
|
cx: &mut gpui::ViewContext<Editor>,
|
||||||
) -> gpui::LayoutId {
|
) -> gpui::LayoutId {
|
||||||
|
let rem_size = cx.rem_size();
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
style.size.width = relative(1.).into();
|
style.size.width = relative(1.).into();
|
||||||
style.size.height = relative(1.).into();
|
style.size.height = relative(1.).into();
|
||||||
|
@ -2011,18 +2015,125 @@ impl Element<Editor> for EditorElement {
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<gpui::Pixels>,
|
bounds: Bounds<gpui::Pixels>,
|
||||||
view_state: &mut Editor,
|
editor: &mut Editor,
|
||||||
element_state: &mut Self::ElementState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut gpui::ViewContext<Editor>,
|
cx: &mut gpui::ViewContext<Editor>,
|
||||||
) {
|
) {
|
||||||
let text_style = cx.text_style();
|
// let mut size = constraint.max;
|
||||||
|
// if size.x().is_infinite() {
|
||||||
|
// unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
|
||||||
|
// }
|
||||||
|
|
||||||
let layout_text = cx.text_system().layout_text(
|
let snapshot = editor.snapshot(cx);
|
||||||
"hello world",
|
let style = self.style.clone();
|
||||||
text_style.font_size * cx.rem_size(),
|
let font_id = cx.text_system().font_id(&style.text.font()).unwrap();
|
||||||
&[text_style.to_run("hello world".len())],
|
let font_size = style.text.font_size * cx.rem_size();
|
||||||
None,
|
let line_height = (font_size * style.line_height_scalar).round();
|
||||||
);
|
let em_width = cx
|
||||||
|
.text_system()
|
||||||
|
.typographic_bounds(font_id, font_size, 'm')
|
||||||
|
.unwrap()
|
||||||
|
.size
|
||||||
|
.width;
|
||||||
|
let em_advance = cx
|
||||||
|
.text_system()
|
||||||
|
.advance(font_id, font_size, 'm')
|
||||||
|
.unwrap()
|
||||||
|
.width;
|
||||||
|
|
||||||
|
let gutter_padding;
|
||||||
|
let gutter_width;
|
||||||
|
let gutter_margin;
|
||||||
|
if snapshot.show_gutter {
|
||||||
|
let descent = cx.text_system().descent(font_id, font_size).unwrap();
|
||||||
|
|
||||||
|
let gutter_padding_factor = 3.5;
|
||||||
|
gutter_padding = (em_width * gutter_padding_factor).round();
|
||||||
|
gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0;
|
||||||
|
gutter_margin = -descent;
|
||||||
|
} else {
|
||||||
|
gutter_padding = px(0.0);
|
||||||
|
gutter_width = px(0.0);
|
||||||
|
gutter_margin = px(0.0);
|
||||||
|
};
|
||||||
|
|
||||||
|
let text_width = bounds.size.width - gutter_width;
|
||||||
|
let overscroll = point(em_width, px(0.));
|
||||||
|
let snapshot = {
|
||||||
|
editor.set_visible_line_count((bounds.size.height / line_height).into(), cx);
|
||||||
|
|
||||||
|
let editor_width = text_width - gutter_margin - overscroll.x - em_width;
|
||||||
|
let wrap_width = match editor.soft_wrap_mode(cx) {
|
||||||
|
SoftWrap::None => (MAX_LINE_LEN / 2) as f32 * em_advance,
|
||||||
|
SoftWrap::EditorWidth => editor_width,
|
||||||
|
SoftWrap::Column(column) => editor_width.min(column as f32 * em_advance),
|
||||||
|
};
|
||||||
|
|
||||||
|
if editor.set_wrap_width(Some(wrap_width), cx) {
|
||||||
|
editor.snapshot(cx)
|
||||||
|
} else {
|
||||||
|
snapshot
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let wrap_guides = editor
|
||||||
|
.wrap_guides(cx)
|
||||||
|
.iter()
|
||||||
|
.map(|(guide, active)| (self.column_pixels(*guide, cx), *active))
|
||||||
|
.collect::<SmallVec<[_; 2]>>();
|
||||||
|
|
||||||
|
let scroll_height = Pixels::from(snapshot.max_point().row() + 1) * line_height;
|
||||||
|
// todo!("this should happen during layout")
|
||||||
|
if let EditorMode::AutoHeight { max_lines } = snapshot.mode {
|
||||||
|
todo!()
|
||||||
|
// size.set_y(
|
||||||
|
// scroll_height
|
||||||
|
// .min(constraint.max_along(Axis::Vertical))
|
||||||
|
// .max(constraint.min_along(Axis::Vertical))
|
||||||
|
// .max(line_height)
|
||||||
|
// .min(line_height * max_lines as f32),
|
||||||
|
// )
|
||||||
|
} else if let EditorMode::SingleLine = snapshot.mode {
|
||||||
|
todo!()
|
||||||
|
// size.set_y(line_height.max(constraint.min_along(Axis::Vertical)))
|
||||||
|
}
|
||||||
|
// todo!()
|
||||||
|
// else if size.y().is_infinite() {
|
||||||
|
// // size.set_y(scroll_height);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
let gutter_size = size(gutter_width, bounds.size.height);
|
||||||
|
let text_size = size(text_width, bounds.size.height);
|
||||||
|
|
||||||
|
let autoscroll_horizontally =
|
||||||
|
editor.autoscroll_vertically(bounds.size.height, line_height, cx);
|
||||||
|
let mut snapshot = editor.snapshot(cx);
|
||||||
|
|
||||||
|
let scroll_position = snapshot.scroll_position();
|
||||||
|
// The scroll position is a fractional point, the whole number of which represents
|
||||||
|
// the top of the window in terms of display rows.
|
||||||
|
let start_row = scroll_position.y as u32;
|
||||||
|
let height_in_lines = f32::from(bounds.size.height / line_height);
|
||||||
|
let max_row = snapshot.max_point().row();
|
||||||
|
|
||||||
|
// Add 1 to ensure selections bleed off screen
|
||||||
|
let end_row = 1 + cmp::min((scroll_position.y + height_in_lines).ceil() as u32, max_row);
|
||||||
|
|
||||||
|
dbg!(start_row..end_row);
|
||||||
|
// let text_style = cx.text_style();
|
||||||
|
// let layout_text = cx.text_system().layout_text(
|
||||||
|
// "hello world",
|
||||||
|
// text_style.font_size * cx.rem_size(),
|
||||||
|
// &[text_style.to_run("hello world".len())],
|
||||||
|
// None,
|
||||||
|
// );
|
||||||
|
// let line_height = text_style
|
||||||
|
// .line_height
|
||||||
|
// .to_pixels(text_style.font_size.into(), cx.rem_size());
|
||||||
|
|
||||||
|
// layout_text.unwrap()[0]
|
||||||
|
// .paint(bounds.origin, line_height, cx)
|
||||||
|
// .unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -303,20 +303,20 @@ impl Editor {
|
||||||
self.scroll_manager.visible_line_count
|
self.scroll_manager.visible_line_count
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext<Self>) {
|
pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext<Self>) {
|
||||||
// let opened_first_time = self.scroll_manager.visible_line_count.is_none();
|
let opened_first_time = self.scroll_manager.visible_line_count.is_none();
|
||||||
// self.scroll_manager.visible_line_count = Some(lines);
|
self.scroll_manager.visible_line_count = Some(lines);
|
||||||
// if opened_first_time {
|
if opened_first_time {
|
||||||
// cx.spawn(|editor, mut cx| async move {
|
cx.spawn(|editor, mut cx| async move {
|
||||||
// editor
|
editor
|
||||||
// .update(&mut cx, |editor, cx| {
|
.update(&mut cx, |editor, cx| {
|
||||||
// editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx)
|
editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx)
|
||||||
// })
|
})
|
||||||
// .ok()
|
.ok()
|
||||||
// })
|
})
|
||||||
// .detach()
|
.detach()
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
pub fn set_scroll_position(
|
pub fn set_scroll_position(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -48,11 +48,11 @@ impl AutoscrollStrategy {
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn autoscroll_vertically(
|
pub fn autoscroll_vertically(
|
||||||
&mut self,
|
&mut self,
|
||||||
viewport_height: f32,
|
viewport_height: Pixels,
|
||||||
line_height: f32,
|
line_height: Pixels,
|
||||||
cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let visible_lines = viewport_height / line_height;
|
let visible_lines = f32::from(viewport_height / line_height);
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
|
let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
|
||||||
let max_scroll_top = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
|
let max_scroll_top = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
|
||||||
|
|
|
@ -825,6 +825,12 @@ impl From<Pixels> for u32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<u32> for Pixels {
|
||||||
|
fn from(pixels: u32) -> Self {
|
||||||
|
Pixels(pixels as f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Pixels> for usize {
|
impl From<Pixels> for usize {
|
||||||
fn from(pixels: Pixels) -> Self {
|
fn from(pixels: Pixels) -> Self {
|
||||||
pixels.0 as usize
|
pixels.0 as usize
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue