treesitter revamp :)

This commit is contained in:
Borodinov Ilya 2024-05-15 22:14:17 +03:00
parent 4382205e84
commit 638a9a112b
Signed by: noth
GPG key ID: 75503B2EF596D1BD
14 changed files with 467 additions and 207 deletions

226
Cargo.lock generated
View file

@ -306,27 +306,12 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bit-set"
version = "0.5.3"
@ -432,6 +417,15 @@ dependencies = [
"piper",
]
[[package]]
name = "brownstone"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5839ee4f953e811bfdcf223f509cb2c6a3e1447959b0bff459405575bc17f22"
dependencies = [
"arrayvec",
]
[[package]]
name = "bstr"
version = "1.9.1"
@ -1641,6 +1635,12 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
[[package]]
name = "indent_write"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3"
[[package]]
name = "indexmap"
version = "2.2.6"
@ -1740,6 +1740,12 @@ dependencies = [
"libc",
]
[[package]]
name = "joinery"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5"
[[package]]
name = "jpeg-decoder"
version = "0.1.22"
@ -1758,6 +1764,34 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kaydle"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2de193d14f7d6f3288f5ee1c38b0d7869e95c322fc5e54d1c385765172db53"
dependencies = [
"kaydle-primitives",
"lazy_format",
"nom",
"nom-supreme",
"serde",
"serde-mobile",
"thiserror",
]
[[package]]
name = "kaydle-primitives"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f31f657f34304c4853f1e3a3f3c9a556d0462d7004460791728713d61d88272"
dependencies = [
"arrayvec",
"memchr",
"nom",
"nom-supreme",
"serde",
]
[[package]]
name = "khronos-egl"
version = "5.0.0"
@ -1784,6 +1818,12 @@ version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b"
[[package]]
name = "lazy_format"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05662be9cd63006934464f935195ae936460edb75de7b9a07e0509795afbdc3"
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -1849,18 +1889,6 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "line-wrap"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linkme"
version = "0.3.26"
@ -2052,6 +2080,12 @@ dependencies = [
"syn 2.0.63",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.3.7"
@ -2133,9 +2167,12 @@ version = "0.1.0"
dependencies = [
"anyhow",
"funnylog",
"kaydle",
"log",
"ming",
"syntect",
"serde",
"tree-sitter-highlight",
"tree-sitter-rust",
"widestring",
]
@ -2152,6 +2189,29 @@ dependencies = [
"memoffset",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nom-supreme"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bd3ae6c901f1959588759ff51c95d24b491ecb9ff91aa9c2ef4acc5b1dcab27"
dependencies = [
"brownstone",
"indent_write",
"joinery",
"memchr",
"nom",
]
[[package]]
name = "num"
version = "0.4.3"
@ -2324,28 +2384,6 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "onig"
version = "6.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
dependencies = [
"bitflags 1.3.2",
"libc",
"once_cell",
"onig_sys",
]
[[package]]
name = "onig_sys"
version = "69.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7"
dependencies = [
"cc",
"pkg-config",
]
[[package]]
name = "oo7"
version = "0.3.2"
@ -2554,20 +2592,6 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "plist"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9"
dependencies = [
"base64 0.21.7",
"indexmap",
"line-wrap",
"quick-xml",
"serde",
"time",
]
[[package]]
name = "png"
version = "0.16.8"
@ -3062,6 +3086,15 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde-mobile"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c32e12ac49f4f1fde3b44b9eccfcc6cb70bbb2622dac40698b34c3d607cf21a4"
dependencies = [
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.201"
@ -3352,28 +3385,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "syntect"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
dependencies = [
"bincode",
"bitflags 1.3.2",
"flate2",
"fnv",
"once_cell",
"onig",
"plist",
"regex-syntax",
"serde",
"serde_derive",
"serde_json",
"thiserror",
"walkdir",
"yaml-rust",
]
[[package]]
name = "sys-locale"
version = "0.3.1"
@ -3640,6 +3651,38 @@ dependencies = [
"tracing",
]
[[package]]
name = "tree-sitter"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df7cc499ceadd4dcdf7ec6d4cbc34ece92c3fa07821e287aedecd4416c516dca"
dependencies = [
"cc",
"regex",
]
[[package]]
name = "tree-sitter-highlight"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaca0fe34fa96eec6aaa8e63308dbe1bafe65a6317487c287f93938959b21907"
dependencies = [
"lazy_static",
"regex",
"thiserror",
"tree-sitter",
]
[[package]]
name = "tree-sitter-rust"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "277690f420bf90741dea984f3da038ace46c4fe6047cba57a66822226cde1c93"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "ttf-parser"
version = "0.20.0"
@ -3759,7 +3802,7 @@ version = "0.41.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c704361d822337cfc00387672c7b59eaa72a1f0744f62b2a68aa228a0c6927d"
dependencies = [
"base64 0.22.1",
"base64",
"data-url",
"flate2",
"imagesize",
@ -4285,15 +4328,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "yazi"
version = "0.1.6"

View file

@ -8,8 +8,11 @@ funnylog.workspace = true
ming.workspace = true
anyhow.workspace = true
widestring = "1.1.0"
syntect = "5.2.0"
log.workspace = true
tree-sitter-highlight = "0.22.6"
tree-sitter-rust = "0.21.2"
serde = { workspace = true, features = ["derive"] }
kaydle = "0.2.0"
[workspace]
members = [
@ -57,13 +60,7 @@ schemars = "0.8"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_derive = { version = "1.0", features = ["deserialize_in_place"] }
serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] }
serde_json_lenient = { version = "0.1", features = [
"preserve_order",
"raw_value",
] }
serde_repr = "0.1"
smallvec = { version = "1.6", features = ["union"] }
sha2 = "0.10"
thiserror = "1"
time = { version = "0.3", features = [
"macros",

View file

@ -29,12 +29,12 @@ use std::any::{Any, TypeId};
/// macro, which only generates the code needed to register your action before `main`.
///
/// ```
/// #[derive(gpui::private::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone)]
/// #[derive(ming::private::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone)]
/// pub struct Paste {
/// pub content: SharedString,
/// }
///
/// impl gpui::Action for Paste {
/// impl ming::Action for Paste {
/// ///...
/// }
/// register_action!(Paste);
@ -184,18 +184,18 @@ macro_rules! actions {
$(
#[doc = "The `"]
#[doc = stringify!($name)]
#[doc = "` action, see [`gpui::actions!`]"]
#[derive(::std::cmp::PartialEq, ::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, gpui::private::serde_derive::Deserialize)]
#[serde(crate = "gpui::private::serde")]
#[doc = "` action, see [`ming::actions!`]"]
#[derive(::std::cmp::PartialEq, ::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ming::private::serde_derive::Deserialize)]
#[serde(crate = "ming::private::serde")]
pub struct $name;
gpui::__impl_action!($namespace, $name,
fn build(_: gpui::private::serde_json::Value) -> gpui::Result<::std::boxed::Box<dyn gpui::Action>> {
ming::__impl_action!($namespace, $name,
fn build(_: ming::private::serde_json::Value) -> ming::Result<::std::boxed::Box<dyn ming::Action>> {
Ok(Box::new(Self))
}
);
gpui::register_action!($name);
ming::register_action!($name);
)*
};
}
@ -205,13 +205,13 @@ macro_rules! actions {
macro_rules! impl_actions {
($namespace:path, [ $($name:ident),* $(,)? ]) => {
$(
gpui::__impl_action!($namespace, $name,
fn build(value: gpui::private::serde_json::Value) -> gpui::Result<::std::boxed::Box<dyn gpui::Action>> {
Ok(std::boxed::Box::new(gpui::private::serde_json::from_value::<Self>(value)?))
ming::__impl_action!($namespace, $name,
fn build(value: ming::private::serde_json::Value) -> ming::Result<::std::boxed::Box<dyn ming::Action>> {
Ok(std::boxed::Box::new(ming::private::serde_json::from_value::<Self>(value)?))
}
);
gpui::register_action!($name);
ming::register_action!($name);
)*
};
}
@ -220,7 +220,7 @@ macro_rules! impl_actions {
#[macro_export]
macro_rules! __impl_action {
($namespace:path, $name:ident, $build:item) => {
impl gpui::Action for $name {
impl ming::Action for $name {
fn name(&self) -> &'static str
{
concat!(
@ -243,14 +243,14 @@ macro_rules! __impl_action {
$build
fn partial_eq(&self, action: &dyn gpui::Action) -> bool {
fn partial_eq(&self, action: &dyn ming::Action) -> bool {
action
.as_any()
.downcast_ref::<Self>()
.map_or(false, |a| self == a)
}
fn boxed_clone(&self) -> std::boxed::Box<dyn gpui::Action> {
fn boxed_clone(&self) -> std::boxed::Box<dyn ming::Action> {
::std::boxed::Box::new(self.clone())
}
@ -262,7 +262,7 @@ macro_rules! __impl_action {
}
mod no_action {
use crate as gpui;
use crate as ming;
actions!(zed, [NoAction]);
}

View file

@ -78,6 +78,21 @@ impl<'de> Visitor<'de> for RgbaVisitor {
fn visit_str<E: de::Error>(self, value: &str) -> Result<Rgba, E> {
Rgba::try_from(value).map_err(E::custom)
}
fn visit_u32<E>(self, hex: u32) -> Result<Self::Value, E>
where
E: de::Error,
{
let r = ((hex >> 24) & 0xFF) as f32 / 255.0;
let g = ((hex >> 16) & 0xFF) as f32 / 255.0;
let b = ((hex >> 8) & 0xFF) as f32 / 255.0;
let mut a = (hex & 0xFF) as f32 / 255.0;
if a == 0. {
a = 1.;
}
Ok(Rgba { r, g, b, a })
}
}
impl<'de> Deserialize<'de> for Rgba {
@ -174,7 +189,7 @@ impl TryFrom<&'_ str> for Rgba {
}
/// An HSLA color
#[derive(Default, Copy, Clone, Debug)]
#[derive(Default, Copy, Clone, Debug, serde::Serialize)]
#[repr(C)]
pub struct Hsla {
/// Hue, in a range from 0 to 1

View file

@ -110,6 +110,14 @@ impl<T: Clone + Debug + Default> Point<T> {
Self { x, y }
}
/// Splats a `value` across both `x` and `y`
pub const fn all(value: T) -> Self where T: Copy {
Self {
x: value,
y: value
}
}
/// Transforms the point to a `Point<U>` by applying the given function to both coordinates.
///
/// This method allows for converting a `Point<T>` to a `Point<U>` by specifying a closure

View file

@ -25,6 +25,7 @@ use std::{
fmt::{Debug, Display, Formatter},
hash::{Hash, Hasher},
ops::{Deref, DerefMut, Range},
str::FromStr,
sync::Arc,
};
@ -593,8 +594,75 @@ impl FontWeight {
pub const BLACK: FontWeight = FontWeight(900.0);
}
impl FromStr for FontWeight {
type Err = ();
fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
Ok(match s {
"thin" => Self::THIN,
"extra_light" => Self::EXTRA_LIGHT,
"light" => Self::LIGHT,
"normal" => Self::NORMAL,
"medium" => Self::MEDIUM,
"semibold" => Self::SEMIBOLD,
"bold" => Self::BOLD,
"extra_bold" => Self::EXTRA_BOLD,
"black" => Self::BLACK,
_ => return Err(()),
})
}
}
impl<'de> serde::Deserialize<'de> for FontWeight {
fn deserialize<D>(deserializer: D) -> std::prelude::v1::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = FontWeight;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a font weight value (e.g. 700 or 'bold')")
}
fn visit_f32<E>(self, v: f32) -> std::prelude::v1::Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(FontWeight(v))
}
fn visit_f64<E>(self, v: f64) -> std::prelude::v1::Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(FontWeight(v as f32))
}
fn visit_i64<E>(self, v: i64) -> std::prelude::v1::Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(FontWeight(v as f32))
}
fn visit_str<E>(self, v: &str) -> std::prelude::v1::Result<Self::Value, E>
where
E: serde::de::Error,
{
v.parse()
.map_err(|()| E::custom("expected a font weight value (e.g. 'normal' or 'bold')"))
}
}
}
}
/// Allows italic or oblique faces to be selected.
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash, Default)]
#[derive(
Clone, Copy, Eq, PartialEq, Debug, Hash, Default, serde::Serialize, serde::Deserialize,
)]
pub enum FontStyle {
/// A face that is neither italic not obliqued.
#[default]

View file

@ -17,7 +17,7 @@ pub(crate) fn register_action(type_name: &Ident) -> proc_macro2::TokenStream {
format_ident!("__GPUI_ACTIONS_{}", type_name.to_string().to_uppercase());
let action_builder_fn_name = format_ident!(
"__gpui_actions_builder_{}",
"__ming_actions_builder_{}",
type_name.to_string().to_lowercase()
);
@ -29,17 +29,17 @@ pub(crate) fn register_action(type_name: &Ident) -> proc_macro2::TokenStream {
fn __autogenerated() {
/// This is an auto generated function, do not use.
#[doc(hidden)]
fn #action_builder_fn_name() -> gpui::ActionData {
gpui::ActionData {
name: <#type_name as gpui::Action>::debug_name(),
fn #action_builder_fn_name() -> ming::ActionData {
ming::ActionData {
name: <#type_name as ming::Action>::debug_name(),
type_id: ::std::any::TypeId::of::<#type_name>(),
build: <#type_name as gpui::Action>::build,
build: <#type_name as ming::Action>::build,
}
}
#[doc(hidden)]
#[gpui::private::linkme::distributed_slice(gpui::__GPUI_ACTIONS)]
#[linkme(crate = gpui::private::linkme)]
static #static_slice_name: gpui::MacroActionBuilder = #action_builder_fn_name;
#[ming::private::linkme::distributed_slice(ming::__GPUI_ACTIONS)]
#[linkme(crate = ming::private::linkme)]
static #static_slice_name: ming::MacroActionBuilder = #action_builder_fn_name;
}
}

View file

@ -68,7 +68,7 @@
scripts = {
fmt.exec = "${config.treefmt.build.wrapper}/bin/treefmt .";
nite.exec = "RUST_LOG=info,nite=trace,ming=trace cargo run -- $@";
nite.exec = "RUST_LOG=error,nite=trace,ming=trace cargo run -- $@";
};
};
};

View file

@ -1,10 +1,5 @@
use std::{ops::Range, path::PathBuf};
use syntect::{
highlighting::{
Color, FontStyle as SFontStyle, HighlightState, Highlighter, RangedHighlightIterator, Theme,
},
parsing::{ParseState, ScopeStack, SyntaxSet},
};
use tree_sitter_highlight::{HighlightConfiguration, Highlighter};
use widestring::Utf16String;
use super::*;
@ -19,7 +14,6 @@ pub struct Buffer {
impl Buffer {
pub fn read(path: PathBuf) -> anyhow::Result<Self> {
let text = std::fs::read_to_string(&path)?;
log::trace!("read file: {text}");
Ok(Self {
text: text.into(),
path: Some(path),
@ -40,9 +34,8 @@ impl Buffer {
pub fn styled(
&self,
default_style: &TextStyle,
theme: &Theme,
theme: &crate::editor::Theme,
syntax_set: &SyntaxSet,
scrolled: usize,
) -> Vec<StyledText> {
let text = self.text.to_string();
@ -51,7 +44,19 @@ impl Buffer {
.as_ref()
.and_then(|path| path.extension())
.and_then(|extension| {
syntax_set.find_syntax_by_extension(extension.to_str().expect("non-utf8 file ext"))
Some(
match extension.to_str().expect("non-utf8 file ext") {
"rs" => HighlightConfiguration::new(
tree_sitter_rust::language(),
"rust",
tree_sitter_rust::HIGHLIGHTS_QUERY,
tree_sitter_rust::INJECTIONS_QUERY,
"",
),
_ => return None,
}
.unwrap(),
)
})
{
let mut parse = ParseState::new(syntax);
@ -59,7 +64,6 @@ impl Buffer {
let mut hl = HighlightState::new(&hler, ScopeStack::new());
text.lines()
.skip(scrolled)
.flat_map(|line| {
parse.parse_line(line, &syntax_set).map(|parsed| {
StyledText::new(Arc::from(line)).with_highlights(
@ -94,7 +98,6 @@ impl Buffer {
.collect()
} else {
text.lines()
.skip(scrolled)
.map(|line| StyledText::new(Arc::from(line)))
.collect()
}

View file

@ -1,6 +1,6 @@
use std::path::PathBuf;
use std::{collections::HashMap, path::PathBuf};
use syntect::{highlighting::ThemeSet, parsing::SyntaxSet};
use serde::{Deserialize, Serialize};
use super::*;
@ -8,15 +8,50 @@ mod element;
mod input;
pub struct EditorSettings {
theme_set: ThemeSet,
syntax_set: SyntaxSet,
style: EditorStyle,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Highlight {
pub color: Option<Rgba>,
#[serde(default)]
pub style: Option<FontStyle>,
#[serde(default)]
pub weight: Option<FontWeight>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Theme {
pub name: String,
pub background_color: Rgba,
pub text_color: Rgba,
pub highlights: HashMap<String, Highlight>,
}
impl Theme {
pub fn load(text: &str) -> Result<Self, kaydle::serde::de::Error> {
kaydle::serde::from_str(text)
}
}
#[derive(Clone)]
pub struct EditorStyle {
pub font_family: SharedString,
pub font_size: AbsoluteLength,
pub theme: Arc<Theme>,
}
impl EditorSettings {
pub fn load_defaults() -> Self {
Self {
theme_set: ThemeSet::load_defaults(),
syntax_set: SyntaxSet::load_defaults_nonewlines(),
style: EditorStyle {
font_size: AbsoluteLength::Pixels(px(14.0)),
font_family: SharedString::from_static("ComicShannsMono Nerd Font Mono"),
theme: Arc::new(
Theme::load(include_str!("../themes/catppuccin/mocha-teal.kdl"))
.expect("mocha theme failed to parse (how?)"),
),
},
}
}
}
@ -25,12 +60,15 @@ pub struct Editor {
focus_handle: FocusHandle,
buf: Model<crate::buffer::Buffer>,
settings: Model<EditorSettings>,
cursor: Point<usize>,
logger: Logger,
}
impl Editor {
pub fn make<V: 'static>(
cx: &mut ViewContext<V>,
settings: Model<EditorSettings>,
logger: Logger,
) -> View<Self> {
cx.new_view(|cx| Self {
buf: cx.new_model(|_cx| {
@ -42,27 +80,38 @@ impl Editor {
}),
focus_handle: cx.focus_handle(),
settings,
logger,
cursor: Point::default(),
})
}
}
impl Render for Editor {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
element::EditorElement::new(
cx.view(),
element::EditorStyle {
font_size: AbsoluteLength::Pixels(px(14.0)),
font_family: SharedString::from_static("ComicShannsMono Nerd Font Mono"),
hl_theme: self
.settings
.read(cx)
.theme_set
.themes
.get("base16-mocha.dark")
.expect("mocha.dark wasn't available even if it's told it's there")
.clone(),
},
)
cx.focus(&self.focus_handle);
div()
.key_context("Editor")
.on_action(cx.listener(|me, event: &action::CursorDown, cx| {
me.cursor.y = me.cursor.y.saturating_add(1).min(
me.buf
.read(cx)
.text
.chars()
.filter(|char| *char == '\n')
.count(),
);
funnylog::trace!(me.logger, ?me.cursor, "down");
}))
.on_action(cx.listener(|me, event: &action::CursorUp, cx| {
me.cursor.y = me.cursor.y.saturating_sub(1);
funnylog::trace!(me.logger, ?me.cursor, "up");
}))
.child(element::EditorElement::new(
cx.view(),
self.settings.read(cx).style.clone(),
self.cursor,
))
}
}
@ -71,3 +120,9 @@ impl FocusableView for Editor {
self.focus_handle.clone()
}
}
pub mod action {
use ming::actions;
actions!(nite, [CursorDown, CursorUp]);
}

View file

@ -1,29 +1,20 @@
use std::{cell::Cell, rc::Rc};
use syntect::highlighting::Theme;
use self::buffer::hsla_from_syntect;
use crate::buffer::hsla_from_syntect;
use super::*;
pub struct EditorStyle {
pub font_family: SharedString,
pub font_size: AbsoluteLength,
pub hl_theme: Theme,
}
pub struct EditorElement {
editor: View<Editor>,
style: EditorStyle,
scrolled: Rc<Cell<usize>>,
cursor: Point<usize>,
}
impl EditorElement {
pub fn new(viewref: &View<Editor>, style: EditorStyle) -> Self {
pub fn new(viewref: &View<Editor>, style: EditorStyle, cursor: Point<usize>) -> Self {
Self {
editor: viewref.clone(),
style,
scrolled: Rc::new(Cell::new(0)),
cursor,
}
}
}
@ -61,9 +52,7 @@ impl Element for EditorElement {
font_family: self.style.font_family.clone(),
..Default::default()
},
&self.style.hl_theme,
&editor.settings.read(cx).syntax_set,
self.scrolled.get(),
&self.style.theme,
);
let children = styled
@ -77,6 +66,14 @@ impl Element for EditorElement {
display: Display::Flex,
flex_direction: FlexDirection::Column,
align_content: Some(AlignContent::FlexStart),
overflow: Point::all(Overflow::Scroll),
size: Size::full(),
background: self
.style
.theme
.settings
.background
.map(|bg| Fill::Color(hsla_from_syntect(bg))),
..Default::default()
},
children.iter().copied(),
@ -98,13 +95,35 @@ impl Element for EditorElement {
request_layout: &mut Self::RequestLayoutState,
cx: &mut WindowContext,
) -> Self::PrepaintState {
request_layout
.styled
.iter_mut()
.for_each(|(id, styled, bounds)| {
*bounds = cx.layout_bounds(*id);
styled.prepaint(None, *bounds, &mut (), cx)
if self.cursor.y > 0 {
let offset = Point::new(
px(0.),
request_layout.styled.iter_mut().take(self.cursor.y).fold(
px(0.),
|px, (id, _, bounds)| {
*bounds = cx.layout_bounds(*id);
px + bounds.size.height
},
),
);
cx.with_element_offset(offset, |cx| {
request_layout
.styled
.iter_mut()
.skip(self.cursor.y)
.for_each(|(_id, styled, bounds)| styled.prepaint(None, *bounds, &mut (), cx));
});
} else {
request_layout
.styled
.iter_mut()
.skip(self.cursor.y)
.for_each(|(id, styled, bounds)| {
*bounds = cx.layout_bounds(*id);
styled.prepaint(None, *bounds, &mut (), cx)
});
}
EditorLayout {}
}
@ -126,41 +145,37 @@ impl Element for EditorElement {
ElementInputHandler::new(bounds, self.editor.clone()),
);
let scrolled = self.scrolled.clone();
let view = self.editor.clone();
let font_size = self.style.font_size.to_pixels(px(4.));
cx.on_mouse_event(move |scroll: &ScrollWheelEvent, _dispatch, cx| {
match scroll.delta {
ScrollDelta::Lines(lines) => scrolled.set({
log::trace!("{scroll:#?}");
view.update(cx, |editor, cx| match scroll.delta {
ScrollDelta::Lines(lines) => {
let lines_y = lines.y.ceil() as i32;
scrolled.get().saturating_add_signed(lines_y as isize)
}),
ScrollDelta::Pixels(pix) => scrolled.set({
editor.cursor.y = editor.cursor.y.saturating_add_signed(lines_y as isize)
}
ScrollDelta::Pixels(pix) => {
let px_y = (pix.y.ceil().0 / font_size.0) as i32;
scrolled.get().saturating_add_signed(px_y as isize)
}),
};
editor.cursor.y = editor.cursor.y.saturating_add_signed(px_y as isize)
}
});
});
cx.with_text_style(
Some(TextStyleRefinement {
color: self
.style
.hl_theme
.theme
.settings
.foreground
.map(hsla_from_syntect),
background_color: self
.style
.hl_theme
.settings
.background
.map(hsla_from_syntect),
..Default::default()
}),
|cx| {
request_layout
.styled
.iter_mut()
.skip(self.cursor.y)
.for_each(|(id, styled, bounds)| {
styled.paint(None, *bounds, &mut (), &mut (), cx);
});

View file

@ -1,6 +1,6 @@
use std::sync::Arc;
use funnylog::Drain;
use funnylog::{filter::LevelFilter, span, Drain, Level};
use ming::*;
mod buffer;
@ -41,10 +41,14 @@ fn main() {
.env_filter("RUST_LOG")
.ignore_error(),
);
funnylog::stdlog::setup(drain.clone()).unwrap();
funnylog::stdlog::setup_with_level(drain.clone(), LevelFilter(Some(Level::Trace))).unwrap();
let logger = Logger::new(drain);
App::new().run(|cx| {
cx.bind_keys([
KeyBinding::new("up", editor::action::CursorUp, Some("Editor")),
KeyBinding::new("down", editor::action::CursorDown, Some("Editor")),
]);
cx.open_window(
WindowOptions {
..Default::default()
@ -54,10 +58,7 @@ fn main() {
let settings = cx.new_model(|_cx| editor::EditorSettings::load_defaults());
cx.new_view(|cx| Nite {
editor: editor::Editor::make(
cx,
settings,
),
editor: editor::Editor::make(cx, settings, logger.branch(span!("editor"))),
logger,
})
},

View file

@ -0,0 +1,24 @@
name "Catppuccin Mocha"
background_color "#1e1e2e"
text_color "#cdd6f4"
highlights {
attribute "#f9e2af"
boolean "#fab387"
comment "#7f849c"
comment.doc "#7f849c"
constant "#fab387"
constructor "#89b4fa"
embedded "#eba0ac"
emphasis "#f38ba8"
emphasis.strong "#f38ba8" font_weight=700
enum "#94e2d5" font_weight=700
function "#89b4fa"
hint "#94e2d5"
keyword "#cba6f7"
link_text "#89b4fa"
link_uri "#89b4fa"
number "#fab387"
}

View file

@ -0,0 +1,40 @@
---
whiskers:
version: 2.0.2
matrix:
- variant: ["", "-no-italics"]
- flavor
- accent
filename: "{{flavor.identifier}}-{{accent}}{{variant}}.kdl"
---
{%set c = flavor.colors-%}
{%set accent = c[accent]-%}
{%if variant == "-no-italics"%}
{%set italic = "font_style=italic"-%}
{%else%}
{%set italic = ""-%}
{%endif%}
name "Catppuccin {{flavor.name}} {%- if variant == "-no-italics" %} (no italics) {%- endif -%}"
background_color "#{{c.base.hex}}"
text_color "#{{c.text.hex}}"
highlights {
attribute "#{{c.yellow.hex}}"
boolean "#{{c.peach.hex}}"
comment "#{{c.overlay1.hex}}" {{italic}}
comment.doc "#{{c.overlay1.hex}}" {{italic}}
constant "#{{c.peach.hex}}"
constructor "#{{c.blue.hex}}"
embedded "#{{c.maroon.hex}}"
emphasis "#{{c.red.hex}}" {{italic}}
emphasis.strong "#{{c.red.hex}}" font_weight=700
enum "#{{c.teal.hex}}" font_weight=700
function "#{{c.blue.hex}}" {{italic}}
hint "#{{c.teal.hex}}" {{italic}}
keyword "#{{c.mauve.hex}}"
link_text "#{{c.blue.hex}}"
link_uri "#{{c.blue.hex}}"
number "#{{c.peach.hex}}"
}