change to pepegsitter

This commit is contained in:
Borodinov Ilya 2024-05-19 21:06:39 +03:00
parent 1346d8ddbf
commit 0e48b78f1a
Signed by: noth
GPG key ID: 75503B2EF596D1BD
18 changed files with 217 additions and 185 deletions

80
Cargo.lock generated
View file

@ -1649,22 +1649,6 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "inkjet"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdd9fd670f1a42725a90e7a97f5e6a777fc56f9031c1ee0ebcea8f91a6bb9c2f"
dependencies = [
"anyhow",
"cc",
"once_cell",
"serde",
"thiserror",
"toml",
"tree-sitter",
"tree-sitter-highlight",
]
[[package]] [[package]]
name = "inout" name = "inout"
version = "0.1.3" version = "0.1.3"
@ -2203,12 +2187,13 @@ dependencies = [
"anyhow", "anyhow",
"careless", "careless",
"funnylog", "funnylog",
"inkjet",
"kdl", "kdl",
"log", "log",
"miette", "miette",
"ming", "ming",
"pepegsitter",
"serde", "serde",
"tree-sitter-highlight",
"widestring", "widestring",
] ]
@ -2560,6 +2545,17 @@ dependencies = [
"hmac", "hmac",
] ]
[[package]]
name = "pepegsitter"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "215b00db1f5bfe7f8f1a3edb0e1ac9c4a42ffc4e50afd929c1e6a6f36d620cca"
dependencies = [
"cc",
"tree-sitter",
"tree-sitter-highlight",
]
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.1" version = "2.3.1"
@ -2718,7 +2714,7 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
dependencies = [ dependencies = [
"toml_edit 0.21.1", "toml_edit",
] ]
[[package]] [[package]]
@ -3160,15 +3156,6 @@ dependencies = [
"syn 2.0.63", "syn 2.0.63",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "sha1" name = "sha1"
version = "0.10.6" version = "0.10.6"
@ -3676,26 +3663,11 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "toml"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit 0.22.12",
]
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.6.5" version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
@ -3705,20 +3677,7 @@ checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"toml_datetime", "toml_datetime",
"winnow 0.5.40", "winnow",
]
[[package]]
name = "toml_edit"
version = "0.22.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.6.8",
] ]
[[package]] [[package]]
@ -4351,15 +4310,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winnow"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "wio" name = "wio"
version = "0.2.2" version = "0.2.2"

View file

@ -10,10 +10,11 @@ anyhow.workspace = true
widestring = "1.1.0" widestring = "1.1.0"
log.workspace = true log.workspace = true
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
inkjet = { version = "0.10.5", features = ["language-rust", "language-toml", "language-zig"], default-features = false }
careless = { git = "https://codeberg.org/minky/careless", version = "0.1.0" } careless = { git = "https://codeberg.org/minky/careless", version = "0.1.0" }
kdl = { version = "4.6.0", default-features = false } kdl = { version = "4.6.0", default-features = false }
miette = { workspace = true, features = ["fancy"] } miette = { workspace = true, features = ["fancy"] }
pepegsitter = { version = "0.2.2", features = ["tree-sitter-highlight"] }
tree-sitter-highlight = "0.20.1"
[workspace] [workspace]
members = [ members = [

View file

@ -11,17 +11,21 @@ use std::{
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use futures::{channel::oneshot, future::{LocalBoxFuture, FutureExt}, Future}; use futures::{
channel::oneshot,
future::{FutureExt, LocalBoxFuture},
Future,
};
use slotmap::SlotMap; use slotmap::SlotMap;
use time::UtcOffset; use time::UtcOffset;
pub use async_context::*; pub use async_context::*;
use collections::{FxHashMap, FxHashSet, VecDeque}; use collections::{FxHashMap, FxHashSet, VecDeque};
pub use entity_map::*; pub use entity_map::*;
use util::http::{self, HttpClient};
pub use model_context::*; pub use model_context::*;
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub use test_context::*; pub use test_context::*;
use util::http::{self, HttpClient};
use util::ResultExt; use util::ResultExt;
use crate::{ use crate::{

View file

@ -13,8 +13,8 @@ use image::{ImageBuffer, ImageError};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use media::core_video::CVImageBuffer; use media::core_video::CVImageBuffer;
use util::http;
use thiserror::Error; use thiserror::Error;
use util::http;
use util::ResultExt; use util::ResultExt;
/// A source of image content. /// A source of image content.

View file

@ -14,8 +14,8 @@ use crate::{
use collections::VecDeque; use collections::VecDeque;
use refineable::Refineable as _; use refineable::Refineable as _;
use std::{cell::RefCell, ops::Range, rc::Rc}; use std::{cell::RefCell, ops::Range, rc::Rc};
use util::sum_tree::{self, Bias, SumTree};
use taffy::style::Overflow; use taffy::style::Overflow;
use util::sum_tree::{self, Bias, SumTree};
/// Construct a new list element /// Construct a new list element
pub fn list(state: ListState) -> List { pub fn list(state: ListState) -> List {

View file

@ -1,7 +1,8 @@
use crate::{AppContext, PlatformDispatcher}; use crate::{AppContext, PlatformDispatcher};
use futures::FutureExt;
use std::{ use std::{
future::Future,
fmt::Debug, fmt::Debug,
future::Future,
marker::PhantomData, marker::PhantomData,
mem, mem,
num::NonZeroUsize, num::NonZeroUsize,
@ -14,7 +15,6 @@ use std::{
task::{Context, Poll}, task::{Context, Poll},
time::Duration, time::Duration,
}; };
use futures::FutureExt;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use util::TryFutureExt; use util::TryFutureExt;
use waker_fn::waker_fn; use waker_fn::waker_fn;

View file

@ -111,11 +111,11 @@ impl<T: Clone + Debug + Default> Point<T> {
} }
/// Splats a `value` across both `x` and `y` /// Splats a `value` across both `x` and `y`
pub const fn all(value: T) -> Self where T: Copy { pub const fn all(value: T) -> Self
Self { where
x: value, T: Copy,
y: value {
} Self { x: value, y: value }
} }
/// Transforms the point to a `Point<U>` by applying the given function to both coordinates. /// Transforms the point to a `Point<U>` by applying the given function to both coordinates.

View file

@ -125,18 +125,17 @@ pub use element::*;
pub use elements::*; pub use elements::*;
pub use executor::*; pub use executor::*;
pub use geometry::*; pub use geometry::*;
pub use ming_macros::{register_action, test, IntoElement, Render};
pub use input::*; pub use input::*;
pub use interactive::*; pub use interactive::*;
use key_dispatch::*; use key_dispatch::*;
pub use keymap::*; pub use keymap::*;
pub use ming_macros::{register_action, test, IntoElement, Render};
pub use platform::*; pub use platform::*;
pub use refineable::*; pub use refineable::*;
pub use scene::*; pub use scene::*;
use seal::Sealed; use seal::Sealed;
pub use shared_string::*; pub use shared_string::*;
pub use shared_uri::*; pub use shared_uri::*;
pub use tokio::time::Sleep as Timer;
pub use style::*; pub use style::*;
pub use styled::*; pub use styled::*;
pub use subscription::*; pub use subscription::*;
@ -145,6 +144,7 @@ pub use taffy::{AvailableSpace, LayoutId};
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub use test::*; pub use test::*;
pub use text_system::*; pub use text_system::*;
pub use tokio::time::Sleep as Timer;
pub use util::arc_cow::ArcCow; pub use util::arc_cow::ArcCow;
pub use view::*; pub use view::*;
pub use window::*; pub use window::*;

View file

@ -58,10 +58,10 @@ pub(crate) use cosmic_text::*;
pub(crate) use linux::*; pub(crate) use linux::*;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub(crate) use mac::*; pub(crate) use mac::*;
pub use util::semver::SemanticVersion;
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub(crate) use test::*; pub(crate) use test::*;
use time::UtcOffset; use time::UtcOffset;
pub use util::semver::SemanticVersion;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub(crate) use windows::*; pub(crate) use windows::*;

View file

@ -17,9 +17,9 @@ use copypasta::{ClipboardContext, ClipboardProvider};
use futures::channel::oneshot::{self, Receiver}; use futures::channel::oneshot::{self, Receiver};
use itertools::Itertools; use itertools::Itertools;
use parking_lot::RwLock; use parking_lot::RwLock;
use util::semver::SemanticVersion;
use smallvec::SmallVec; use smallvec::SmallVec;
use time::UtcOffset; use time::UtcOffset;
use util::semver::SemanticVersion;
use windows::{ use windows::{
core::*, core::*,
Wdk::System::SystemServices::*, Wdk::System::SystemServices::*,

View file

@ -652,8 +652,9 @@ impl<'de> serde::Deserialize<'de> for FontWeight {
where where
E: serde::de::Error, E: serde::de::Error,
{ {
v.parse() v.parse().map_err(|()| {
.map_err(|()| E::custom("expected a font weight value (e.g. 'normal' or 'bold')")) E::custom("expected a font weight value (e.g. 'normal' or 'bold')")
})
} }
} }

View file

@ -17,7 +17,10 @@ pub trait FluentBuilder {
} }
/// Imperatively modify self with the given closure. /// Imperatively modify self with the given closure.
fn apply(mut self, f: impl FnOnce(&mut Self)) -> Self where Self: Sized { fn apply(mut self, f: impl FnOnce(&mut Self)) -> Self
where
Self: Sized,
{
f(&mut self); f(&mut self);
self self

View file

@ -3,17 +3,18 @@ use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote, ToTokens}; use quote::{format_ident, quote, ToTokens};
use std::mem; use std::mem;
use syn::{ use syn::{
parse2, parse_quote, punctuated::Punctuated, spanned::Spanned as _, Expr, parse2, parse_quote, punctuated::Punctuated, spanned::Spanned as _, Expr, FnArg, ItemFn, Lit,
FnArg, ItemFn, Lit, Meta, PatLit as ExprLit, Token, Type, Meta, PatLit as ExprLit, Token, Type,
}; };
pub fn test(args: TS, function: TS) -> TS { pub fn test(args: TS, function: TS) -> TS {
test_impl(args.into(), function.into()).map_or_else(|e| e.into_compile_error().into(), |ts| ts.into()) test_impl(args.into(), function.into())
.map_or_else(|e| e.into_compile_error().into(), |ts| ts.into())
} }
fn test_impl(args: TokenStream, function: TokenStream) -> syn::Result<TokenStream> { fn test_impl(args: TokenStream, function: TokenStream) -> syn::Result<TokenStream> {
let Meta::List(args) = parse2(args)? else { let Meta::List(args) = parse2(args)? else {
return Err(syn::Error::new(Span::call_site(), "invalid attr")) return Err(syn::Error::new(Span::call_site(), "invalid attr"));
}; };
let mut max_retries = 0; let mut max_retries = 0;
let mut num_iterations = 1; let mut num_iterations = 1;

View file

@ -1,9 +1,9 @@
pub mod arc_cow; pub mod arc_cow;
pub mod http;
pub mod fs; pub mod fs;
pub mod http;
pub mod paths; pub mod paths;
pub mod serde;
pub mod semver; pub mod semver;
pub mod serde;
pub mod sum_tree; pub mod sum_tree;
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub mod test; pub mod test;

View file

@ -1,9 +1,10 @@
use careless::prelude::*; use careless::prelude::*;
use inkjet::tree_sitter_highlight::{Error, HighlightEvent, Highlighter}; use funnylog::warn;
use std::{ops::Range, path::PathBuf}; use std::{ops::Range, path::PathBuf};
use tree_sitter_highlight::{Error, HighlightConfiguration, HighlightEvent, Highlighter};
use widestring::Utf16String; use widestring::Utf16String;
use crate::editor::Theme; use crate::editor::{Highlight, Theme};
use crate::vim::Mode; use crate::vim::Mode;
use super::*; use super::*;
@ -15,7 +16,7 @@ pub struct Buffer {
pub selected: Option<Range<usize>>, pub selected: Option<Range<usize>>,
pub name: SharedString, pub name: SharedString,
pub modified: bool, pub modified: bool,
pub mode: Mode pub mode: Mode,
} }
impl Buffer { impl Buffer {
@ -28,7 +29,7 @@ impl Buffer {
marked: None, marked: None,
selected: None, selected: None,
modified: false, modified: false,
mode: Mode::default() mode: Mode::default(),
}) })
} }
@ -40,33 +41,35 @@ impl Buffer {
selected: None, selected: None,
name: SharedString::from_static("<scratch>"), name: SharedString::from_static("<scratch>"),
modified: false, modified: false,
mode: Mode::default() mode: Mode::default(),
} }
} }
pub fn styled(&self, default_style: &TextStyle, theme: &Theme) -> Vec<StyledText> { pub fn styled(&self, default_style: &TextStyle, theme: &Theme) -> Vec<StyledText> {
let text = self.text.to_string(); let text = self.text.to_string();
if let Some(language) = self if let Some(mut language) = self
.path .path
.as_ref() .as_ref()
.and_then(|path| path.extension()) .and_then(|path| path.extension())
.and_then(|extension| { .and_then(|extension| {
inkjet::Language::from_token(extension.to_str()?).map(|lang| lang.config()) Language::from_token(extension.to_str()?).map(|lang| lang.config())
}) })
{ {
let (indices, highlights): (Vec<&str>, Vec<&Highlight>) =
theme.highlights.iter().map(|(name, hl)| (name.as_str(), hl)).unzip();
language.configure(&indices);
let mut hl = Highlighter::new(); let mut hl = Highlighter::new();
let mut lines = vec![]; let mut lines = vec![];
for line in text.lines() { for line in text.lines() {
// damnation // damnation
match hl match hl
.highlight(language, line.as_bytes(), None, |lang| { .highlight(&language, line.as_bytes(), None, |lang| None)
inkjet::Language::from_token(lang).map(|lang| lang.config())
})
.and_then(|hls| { .and_then(|hls| {
Ok(StyledText::new(Arc::from(line)).with_runs( Ok(StyledText::new(Arc::from(line)).with_runs(
MingHighlighter::new(hls, default_style, theme).try_to_collect()?, MingHighlighter::new(hls, default_style, &highlights)
.try_to_collect()?,
)) ))
}) { }) {
Ok(styled) => lines.push(styled), Ok(styled) => lines.push(styled),
@ -92,17 +95,17 @@ impl Buffer {
pub struct MingHighlighter<'a, I> { pub struct MingHighlighter<'a, I> {
iter: I, iter: I,
default_style: &'a TextStyle, default_style: &'a TextStyle,
theme: &'a Theme, highlights: &'a [&'a Highlight],
current_hl_idx: Option<usize>, current_hl_idx: Option<usize>,
current_span: Option<Range<usize>>, current_span: Option<Range<usize>>,
} }
impl<'a, I> MingHighlighter<'a, I> { impl<'a, I> MingHighlighter<'a, I> {
pub fn new(iter: I, default_style: &'a TextStyle, theme: &'a Theme) -> Self { pub fn new(iter: I, default_style: &'a TextStyle, highlights: &'a [&'a Highlight]) -> Self {
Self { Self {
iter, iter,
default_style, default_style,
theme, highlights,
current_hl_idx: None, current_hl_idx: None,
current_span: None, current_span: None,
} }
@ -122,9 +125,8 @@ impl<I: Iterator<Item = Result<HighlightEvent, Error>>> Iterator for MingHighlig
self.current_span = Some(start..end); self.current_span = Some(start..end);
self.default_style.to_run(end - start).apply(|run| { self.default_style.to_run(end - start).apply(|run| {
if let Some(hl) = self if let Some(hl) =
.current_hl_idx self.current_hl_idx.and_then(|idx| self.highlights.get(idx))
.and_then(|idx| self.theme.highlight_indices.get(idx))
{ {
hl.apply_to_run(run) hl.apply_to_run(run)
} }
@ -143,3 +145,24 @@ impl<I: Iterator<Item = Result<HighlightEvent, Error>>> Iterator for MingHighlig
) )
} }
} }
pub enum Language {
Rust,
Toml,
}
impl Language {
pub fn from_token(token: &str) -> Option<Self> {
Some(match token {
"rs" | "rust" => Self::Rust,
"toml" => Self::Toml,
_ => return None,
})
}
pub fn config(&self) -> HighlightConfiguration {
match self {
Self::Rust => pepegsitter::rust::highlight(),
Self::Toml => pepegsitter::toml::highlight(),
}
}
}

View file

@ -78,7 +78,7 @@ pub struct Theme {
pub name: String, pub name: String,
pub background_color: Rgba, pub background_color: Rgba,
pub text_color: Rgba, pub text_color: Rgba,
pub highlight_indices: Vec<Highlight>, pub highlights: Vec<(String, Highlight)>,
} }
fn rgba_from_kdl(value: &KdlValue) -> miette::Result<Rgba> { fn rgba_from_kdl(value: &KdlValue) -> miette::Result<Rgba> {
@ -103,18 +103,12 @@ impl Theme {
} }
pub fn from_kdl_document(document: KdlDocument) -> miette::Result<Self> { pub fn from_kdl_document(document: KdlDocument) -> miette::Result<Self> {
let highlight_indices = match document.get("highlights").and_then(|node| node.children()) { let highlights = match document.get("highlights").and_then(|node| node.children()) {
Some(doc) => { Some(doc) => doc
let mut indices = vec![]; .nodes()
.iter()
for name in inkjet::constants::HIGHLIGHT_NAMES { .map(|node| Highlight::from_kdl_node(node).map(|hl| (node.name().to_string(), hl)))
let Some(node) = doc.get(*name) else { continue }; .try_to_collect()?,
indices.push(Highlight::from_kdl_node(node)?);
}
indices
}
None => Default::default(), None => Default::default(),
}; };
@ -133,7 +127,7 @@ impl Theme {
.get_arg("text_color") .get_arg("text_color")
.context("no background_color attr") .context("no background_color attr")
.and_then(rgba_from_kdl)?, .and_then(rgba_from_kdl)?,
highlight_indices, highlights,
}) })
} }
} }
@ -198,7 +192,6 @@ impl Editor {
let buf = self.buf.read(cx); let buf = self.buf.read(cx);
div() div()
.debug()
.flex() .flex()
.flex_row() .flex_row()
.justify_between() .justify_between()
@ -233,16 +226,15 @@ impl Editor {
impl Render for Editor { impl Render for Editor {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
cx.focus(&self.focus_handle); cx.focus(&self.focus_handle);
let styled = {
// -1 read...
let style = &self.settings.read(cx).style;
div() div()
.font_family(style.font_family.clone()) .map(|div| {
.text_color(style.theme.text_color) let style = &self.settings.read(cx).style;
};
styled.key_context("Editor") div.font_family(style.font_family.clone())
.text_color(style.theme.text_color)
})
.key_context("Editor")
.on_action(cx.listener(|me, event: &action::CursorDown, cx| { .on_action(cx.listener(|me, event: &action::CursorDown, cx| {
me.cursor.y = me.cursor.y.saturating_add(1).min( me.cursor.y = me.cursor.y.saturating_add(1).min(
me.buf me.buf

View file

@ -1,4 +1,4 @@
use std::fmt::write; use std::{any::TypeId, fmt::write};
use super::*; use super::*;
@ -122,6 +122,7 @@ impl Element for EditorElement {
) { ) {
let focus_handle = self.editor.focus_handle(cx); let focus_handle = self.editor.focus_handle(cx);
let key_context = self.editor.read(cx).key_context(cx); let key_context = self.editor.read(cx).key_context(cx);
cx.set_focus_handle(&focus_handle); cx.set_focus_handle(&focus_handle);
cx.set_key_context(key_context); cx.set_key_context(key_context);
cx.handle_input( cx.handle_input(
@ -129,68 +130,124 @@ impl Element for EditorElement {
ElementInputHandler::new(bounds, self.editor.clone()), ElementInputHandler::new(bounds, self.editor.clone()),
); );
let view = self.editor.clone(); let styled_bounds: Arc<[Bounds<Pixels>]> = Arc::from(
let font_size = self.style.font_size.to_pixels(px(4.)); request_layout
let hb = prepaint.hb.clone(); .styled
.iter()
.map(|(_, _, b)| *b)
.collect::<Vec<Bounds<Pixels>>>(),
);
let styled_bounds = request_layout cx.on_action(TypeId::of::<action::CursorUp>(), {
.styled let view = self.editor.clone();
.iter() let styled_bounds = styled_bounds.clone();
.map(|(_, _, b)| *b)
.collect::<Vec<_>>();
cx.on_mouse_event(move |scroll: &ScrollWheelEvent, dispatch, cx| { move |_event, _dispatch, cx| {
if !dispatch.bubble() || !hb.is_hovered(cx) { view.update(cx, |editor, cx| {
return; if editor.cursor.y == 0 {
} return;
view.update(cx, |editor, cx| {
let prev_editor_scroll = editor.scroll;
let change = match scroll.delta {
ScrollDelta::Lines(pnt) => {
let mut lines = pnt.y.abs();
let mut do_scroll = px(0.);
for bounds in styled_bounds.iter() {
if lines <= 1. {
do_scroll += px(bounds.size.height.0 * lines);
break;
}
do_scroll += bounds.size.height;
lines -= 1.;
}
point(px(0.), do_scroll * pnt.y.signum())
} }
ScrollDelta::Pixels(pix) => pix,
};
editor.scroll = (editor.scroll + change).clamp( editor.cursor.y = editor.cursor.y.saturating_sub(1);
&point(bounds.size.width, bounds.size.height).negate(),
&Point::default(),
);
let prev_ruler = editor.ruler; let line_bounds = styled_bounds
let next_ruler = (editor.scroll.y.0 / bounds.size.height.0 * 100.).abs().floor() as u8; .iter()
.take(editor.cursor.y)
.fold(px(0.), |px, bounds| px + bounds.size.height);
if prev_ruler != next_ruler { if line_bounds > bounds.size.height {
editor.ruler = next_ruler; editor.scroll.y = -line_bounds;
cx.notify(); }
} });
log::trace!(
"[{prev_editor_scroll:#?} -> {:#?}] [{prev_ruler}% -> {next_ruler}%] {scroll:#?}",
editor.scroll
);
cx.stop_propagation(); cx.stop_propagation();
}
});
if !change.is_zero() { cx.on_action(TypeId::of::<action::CursorDown>(), {
cx.refresh(); let view = self.editor.clone();
let styled_bounds = styled_bounds.clone();
move |_event, _dispatch, cx| {
view.update(cx, |editor, cx| {
if editor.cursor.y == editor.buf.read(cx).text.chars().filter(|char| *char == '\n').count() {
return;
}
editor.cursor.y += 1;
let line_bounds = styled_bounds
.iter()
.take(editor.cursor.y)
.fold(px(0.), |px, bounds| px + bounds.size.height);
if line_bounds > bounds.size.height {
editor.scroll.y = -line_bounds;
}
});
cx.stop_propagation();
}
});
cx.on_mouse_event({
let view = self.editor.clone();
let hb = prepaint.hb.clone();
let styled_bounds = styled_bounds.clone();
move |scroll: &ScrollWheelEvent, dispatch, cx| {
if !dispatch.bubble() || !hb.is_hovered(cx) {
return;
} }
});
view.update(cx, |editor, cx| {
let prev_editor_scroll = editor.scroll;
let change = match scroll.delta {
ScrollDelta::Lines(pnt) => {
let mut lines = pnt.y.abs();
let mut do_scroll = px(0.);
for bounds in styled_bounds.iter() {
if lines <= 1. {
do_scroll += px(bounds.size.height.0 * lines);
break;
}
do_scroll += bounds.size.height;
lines -= 1.;
}
point(px(0.), do_scroll * pnt.y.signum())
}
ScrollDelta::Pixels(pix) => pix,
};
editor.scroll = (editor.scroll + change).clamp(
&point(bounds.size.width, bounds.size.height).negate(),
&Point::default(),
);
let prev_ruler = editor.ruler;
let next_ruler = (editor.scroll.y.0 / bounds.size.height.0 * 100.).abs().floor() as u8;
if prev_ruler != next_ruler {
editor.ruler = next_ruler;
cx.notify();
}
log::trace!(
"[{prev_editor_scroll:#?} -> {:#?}] [{prev_ruler}% -> {next_ruler}%] {scroll:#?}",
editor.scroll
);
cx.stop_propagation();
if !change.is_zero() {
cx.refresh();
}
});
}
}); });
cx.with_text_style( cx.with_text_style(

View file

@ -3,5 +3,5 @@ pub enum Mode {
#[default] #[default]
Normal, Normal,
Insert, Insert,
Visual Visual,
} }