it fucken works!!
This commit is contained in:
parent
d7fe624e8b
commit
4382205e84
13 changed files with 413 additions and 51 deletions
116
Cargo.lock
generated
116
Cargo.lock
generated
|
@ -306,12 +306,27 @@ dependencies = [
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.21.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode"
|
||||||
|
version = "1.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
|
@ -1834,6 +1849,18 @@ dependencies = [
|
||||||
"vcpkg",
|
"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]]
|
[[package]]
|
||||||
name = "linkme"
|
name = "linkme"
|
||||||
version = "0.3.26"
|
version = "0.3.26"
|
||||||
|
@ -1998,6 +2025,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
"smol",
|
||||||
"taffy",
|
"taffy",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"time",
|
"time",
|
||||||
|
@ -2105,7 +2133,9 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"funnylog",
|
"funnylog",
|
||||||
|
"log",
|
||||||
"ming",
|
"ming",
|
||||||
|
"syntect",
|
||||||
"widestring",
|
"widestring",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2294,6 +2324,28 @@ version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
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]]
|
[[package]]
|
||||||
name = "oo7"
|
name = "oo7"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -2502,6 +2554,20 @@ version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
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]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.16.8"
|
version = "0.16.8"
|
||||||
|
@ -3164,6 +3230,23 @@ dependencies = [
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smol"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e635339259e51ef85ac7aa29a1cd991b957047507288697a690e80ab97d07cad"
|
||||||
|
dependencies = [
|
||||||
|
"async-channel 2.3.0",
|
||||||
|
"async-executor",
|
||||||
|
"async-fs",
|
||||||
|
"async-io",
|
||||||
|
"async-lock",
|
||||||
|
"async-net",
|
||||||
|
"async-process",
|
||||||
|
"blocking",
|
||||||
|
"futures-lite 2.3.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.7"
|
version = "0.5.7"
|
||||||
|
@ -3269,6 +3352,28 @@ dependencies = [
|
||||||
"unicode-ident",
|
"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]]
|
[[package]]
|
||||||
name = "sys-locale"
|
name = "sys-locale"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
@ -3654,7 +3759,7 @@ version = "0.41.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c704361d822337cfc00387672c7b59eaa72a1f0744f62b2a68aa228a0c6927d"
|
checksum = "5c704361d822337cfc00387672c7b59eaa72a1f0744f62b2a68aa228a0c6927d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64 0.22.1",
|
||||||
"data-url",
|
"data-url",
|
||||||
"flate2",
|
"flate2",
|
||||||
"imagesize",
|
"imagesize",
|
||||||
|
@ -4180,6 +4285,15 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
|
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]]
|
[[package]]
|
||||||
name = "yazi"
|
name = "yazi"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
|
|
@ -8,6 +8,8 @@ funnylog.workspace = true
|
||||||
ming.workspace = true
|
ming.workspace = true
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
widestring = "1.1.0"
|
widestring = "1.1.0"
|
||||||
|
syntect = "5.2.0"
|
||||||
|
log.workspace = true
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
|
|
@ -61,6 +61,7 @@ time.workspace = true
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
waker-fn = "1.1.0"
|
waker-fn = "1.1.0"
|
||||||
|
smol = "2.0.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
backtrace = "0.3"
|
backtrace = "0.3"
|
||||||
|
|
|
@ -143,7 +143,13 @@ impl StyledText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// todo!()
|
/// Get a reference to the text inside this [`StyledText`]
|
||||||
|
pub fn text(&self) -> &str {
|
||||||
|
&self.text
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the text layout.
|
||||||
|
/// This method is not intended to be used outside ming.
|
||||||
pub fn layout(&self) -> &TextLayout {
|
pub fn layout(&self) -> &TextLayout {
|
||||||
&self.layout
|
&self.layout
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,9 @@ use util::arc_cow::ArcCow;
|
||||||
pub struct SharedString(ArcCow<'static, str>);
|
pub struct SharedString(ArcCow<'static, str>);
|
||||||
|
|
||||||
impl SharedString {
|
impl SharedString {
|
||||||
/// Create a new shared string from anything that can be turned into an [`ArcCow`], including:
|
/// Create a new empty [`SharedString`].
|
||||||
/// - `&'static `[`str`]
|
pub fn new() -> Self {
|
||||||
/// - [`String`]
|
Self(ArcCow::Borrowed(""))
|
||||||
/// - [`Arc`]`<`[`str`]`>`
|
|
||||||
/// - a reference to any of the above
|
|
||||||
pub fn new(ac: impl Into<ArcCow<'static, str>>) -> Self {
|
|
||||||
Self(ac.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new shared string from a `&'static `[`str`].
|
/// Create a new shared string from a `&'static `[`str`].
|
||||||
|
|
|
@ -102,7 +102,7 @@ impl<T: 'static> futures::Stream for Observation<T> {
|
||||||
|
|
||||||
/// observe returns a stream of the change events from the given `View` or `Model`
|
/// observe returns a stream of the change events from the given `View` or `Model`
|
||||||
pub fn observe<T: 'static>(entity: &impl Entity<T>, cx: &mut TestAppContext) -> Observation<()> {
|
pub fn observe<T: 'static>(entity: &impl Entity<T>, cx: &mut TestAppContext) -> Observation<()> {
|
||||||
let (tx, rx) = smol::channel::unbounded();
|
let (tx, rx) = channel::unbounded();
|
||||||
let _subscription = cx.update(|cx| {
|
let _subscription = cx.update(|cx| {
|
||||||
cx.observe(entity, move |_, _| {
|
cx.observe(entity, move |_, _| {
|
||||||
let _ = smol::block_on(tx.send(()));
|
let _ = smol::block_on(tx.send(()));
|
||||||
|
|
|
@ -2,10 +2,7 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
use futures::Future;
|
use futures::{Future, FutureExt};
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
|
||||||
use smol::future::FutureExt;
|
|
||||||
|
|
||||||
pub use util::*;
|
pub use util::*;
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
|
|
||||||
scripts = {
|
scripts = {
|
||||||
fmt.exec = "${config.treefmt.build.wrapper}/bin/treefmt .";
|
fmt.exec = "${config.treefmt.build.wrapper}/bin/treefmt .";
|
||||||
nite.exec = "RUST_LOG=info,nite=trace,ming=trace cargo run";
|
nite.exec = "RUST_LOG=info,nite=trace,ming=trace cargo run -- $@";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
use std::{ops::Range, path::PathBuf};
|
use std::{ops::Range, path::PathBuf};
|
||||||
|
use syntect::{
|
||||||
|
highlighting::{
|
||||||
|
Color, FontStyle as SFontStyle, HighlightState, Highlighter, RangedHighlightIterator, Theme,
|
||||||
|
},
|
||||||
|
parsing::{ParseState, ScopeStack, SyntaxSet},
|
||||||
|
};
|
||||||
use widestring::Utf16String;
|
use widestring::Utf16String;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -6,18 +12,19 @@ use super::*;
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
pub text: Utf16String,
|
pub text: Utf16String,
|
||||||
pub path: Option<PathBuf>,
|
pub path: Option<PathBuf>,
|
||||||
pub marked: Option<Range<usize>>
|
pub marked: Option<Range<usize>>,
|
||||||
|
pub selected: Option<Range<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
pub fn make_scratch<V>(cx: &mut ViewContext<V>) -> Model<Self> {
|
|
||||||
cx.new_model(|_cx| Self::scratch())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(path: PathBuf) -> anyhow::Result<Self> {
|
pub fn read(path: PathBuf) -> anyhow::Result<Self> {
|
||||||
|
let text = std::fs::read_to_string(&path)?;
|
||||||
|
log::trace!("read file: {text}");
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
text: std::fs::read_to_string(&path)?,
|
text: text.into(),
|
||||||
path: Some(path),
|
path: Some(path),
|
||||||
|
marked: None,
|
||||||
|
selected: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +32,81 @@ impl Buffer {
|
||||||
Self {
|
Self {
|
||||||
text: Utf16String::new(),
|
text: Utf16String::new(),
|
||||||
path: None,
|
path: None,
|
||||||
|
marked: None,
|
||||||
|
selected: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn styled(
|
||||||
|
&self,
|
||||||
|
default_style: &TextStyle,
|
||||||
|
theme: &Theme,
|
||||||
|
syntax_set: &SyntaxSet,
|
||||||
|
scrolled: usize,
|
||||||
|
) -> Vec<StyledText> {
|
||||||
|
let text = self.text.to_string();
|
||||||
|
|
||||||
|
if let Some(syntax) = self
|
||||||
|
.path
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|path| path.extension())
|
||||||
|
.and_then(|extension| {
|
||||||
|
syntax_set.find_syntax_by_extension(extension.to_str().expect("non-utf8 file ext"))
|
||||||
|
})
|
||||||
|
{
|
||||||
|
let mut parse = ParseState::new(syntax);
|
||||||
|
let hler = Highlighter::new(theme);
|
||||||
|
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(
|
||||||
|
default_style,
|
||||||
|
RangedHighlightIterator::new(&mut hl, &parsed, line, &hler).map(
|
||||||
|
move |(style, _text, range)| {
|
||||||
|
(
|
||||||
|
range,
|
||||||
|
HighlightStyle {
|
||||||
|
color: Some(hsla_from_syntect(style.foreground)),
|
||||||
|
background_color: None,
|
||||||
|
font_style: style
|
||||||
|
.font_style
|
||||||
|
.contains(SFontStyle::ITALIC)
|
||||||
|
.then(|| FontStyle::Italic),
|
||||||
|
underline: style
|
||||||
|
.font_style
|
||||||
|
.contains(SFontStyle::UNDERLINE)
|
||||||
|
.then(|| UnderlineStyle::default()),
|
||||||
|
font_weight: style
|
||||||
|
.font_style
|
||||||
|
.contains(SFontStyle::BOLD)
|
||||||
|
.then(|| FontWeight::BOLD),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
text.lines()
|
||||||
|
.skip(scrolled)
|
||||||
|
.map(|line| StyledText::new(Arc::from(line)))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hsla_from_syntect(color: Color) -> Hsla {
|
||||||
|
Rgba {
|
||||||
|
r: color.r as f32 / 255.0,
|
||||||
|
g: color.g as f32 / 255.0,
|
||||||
|
b: color.b as f32 / 255.0,
|
||||||
|
a: color.a as f32 / 255.0,
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
|
@ -1,25 +1,68 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use syntect::{highlighting::ThemeSet, parsing::SyntaxSet};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
mod element;
|
mod element;
|
||||||
mod input;
|
mod input;
|
||||||
|
|
||||||
|
pub struct EditorSettings {
|
||||||
|
theme_set: ThemeSet,
|
||||||
|
syntax_set: SyntaxSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EditorSettings {
|
||||||
|
pub fn load_defaults() -> Self {
|
||||||
|
Self {
|
||||||
|
theme_set: ThemeSet::load_defaults(),
|
||||||
|
syntax_set: SyntaxSet::load_defaults_nonewlines(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Editor {
|
pub struct Editor {
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
buf: Model<crate::buffer::Buffer>
|
buf: Model<crate::buffer::Buffer>,
|
||||||
|
settings: Model<EditorSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn make<V: 'static>(cx: &mut ViewContext<V>) -> View<Self> {
|
pub fn make<V: 'static>(
|
||||||
|
cx: &mut ViewContext<V>,
|
||||||
|
settings: Model<EditorSettings>,
|
||||||
|
) -> View<Self> {
|
||||||
cx.new_view(|cx| Self {
|
cx.new_view(|cx| Self {
|
||||||
buf: crate::buffer::Buffer::make_scratch(cx),
|
buf: cx.new_model(|_cx| {
|
||||||
focus_handle: cx.focus_handle()
|
if let Some(path) = std::env::args().skip(1).next() {
|
||||||
|
crate::buffer::Buffer::read(PathBuf::from(path)).expect("file failed to read")
|
||||||
|
} else {
|
||||||
|
crate::buffer::Buffer::scratch()
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
focus_handle: cx.focus_handle(),
|
||||||
|
settings,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
element::EditorElement::new(cx.view())
|
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(),
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
|
use std::{cell::Cell, rc::Rc};
|
||||||
|
|
||||||
|
use syntect::highlighting::Theme;
|
||||||
|
|
||||||
|
use self::buffer::hsla_from_syntect;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub struct EditorStyle {
|
pub struct EditorStyle {
|
||||||
pub font_family: SharedString,
|
pub font_family: SharedString,
|
||||||
pub font_size: AbsoluteLength,
|
pub font_size: AbsoluteLength,
|
||||||
}
|
pub hl_theme: Theme,
|
||||||
|
|
||||||
impl Default for EditorStyle {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
font_family: SharedString::from_static("Monospace"),
|
|
||||||
font_size: AbsoluteLength::Pixels(px(14)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EditorElement {
|
pub struct EditorElement {
|
||||||
editor: View<Editor>,
|
editor: View<Editor>,
|
||||||
style: EditorStyle,
|
style: EditorStyle,
|
||||||
|
scrolled: Rc<Cell<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditorElement {
|
impl EditorElement {
|
||||||
pub fn new(viewref: &View<Editor>) -> Self {
|
pub fn new(viewref: &View<Editor>, style: EditorStyle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
editor: viewref.clone(),
|
editor: viewref.clone(),
|
||||||
style: EditorStyle::default(),
|
style,
|
||||||
|
scrolled: Rc::new(Cell::new(0)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,13 @@ impl IntoElement for EditorElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EditorLayout {}
|
pub struct EditorLayout {}
|
||||||
|
pub struct EditorRequestLayout {
|
||||||
|
styled: Vec<(LayoutId, StyledText, Bounds<Pixels>)>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Element for EditorElement {
|
impl Element for EditorElement {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = EditorRequestLayout;
|
||||||
type PrepaintState = EditorLayout;
|
type PrepaintState = EditorLayout;
|
||||||
|
|
||||||
fn id(&self) -> Option<ElementId> {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
@ -51,6 +54,41 @@ impl Element for EditorElement {
|
||||||
id: Option<&GlobalElementId>,
|
id: Option<&GlobalElementId>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> (LayoutId, Self::RequestLayoutState) {
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
|
let editor = self.editor.read(cx);
|
||||||
|
let mut styled = editor.buf.read(cx).styled(
|
||||||
|
&TextStyle {
|
||||||
|
font_size: self.style.font_size,
|
||||||
|
font_family: self.style.font_family.clone(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&self.style.hl_theme,
|
||||||
|
&editor.settings.read(cx).syntax_set,
|
||||||
|
self.scrolled.get(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let children = styled
|
||||||
|
.iter_mut()
|
||||||
|
.map(|styled| styled.request_layout(None, cx).0)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
(
|
||||||
|
cx.request_layout(
|
||||||
|
Style {
|
||||||
|
display: Display::Flex,
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_content: Some(AlignContent::FlexStart),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
children.iter().copied(),
|
||||||
|
),
|
||||||
|
EditorRequestLayout {
|
||||||
|
styled: children
|
||||||
|
.into_iter()
|
||||||
|
.zip(styled)
|
||||||
|
.map(|(id, styled)| (id, styled, Bounds::default()))
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
|
@ -60,6 +98,14 @@ impl Element for EditorElement {
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Self::PrepaintState {
|
) -> Self::PrepaintState {
|
||||||
|
request_layout
|
||||||
|
.styled
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|(id, styled, bounds)| {
|
||||||
|
*bounds = cx.layout_bounds(*id);
|
||||||
|
styled.prepaint(None, *bounds, &mut (), cx)
|
||||||
|
});
|
||||||
|
|
||||||
EditorLayout {}
|
EditorLayout {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,14 +126,44 @@ impl Element for EditorElement {
|
||||||
ElementInputHandler::new(bounds, self.editor.clone()),
|
ElementInputHandler::new(bounds, self.editor.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let scrolled = self.scrolled.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({
|
||||||
|
let lines_y = lines.y.ceil() as i32;
|
||||||
|
scrolled.get().saturating_add_signed(lines_y as isize)
|
||||||
|
}),
|
||||||
|
ScrollDelta::Pixels(pix) => scrolled.set({
|
||||||
|
let px_y = (pix.y.ceil().0 / font_size.0) as i32;
|
||||||
|
scrolled.get().saturating_add_signed(px_y as isize)
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
cx.with_text_style(
|
cx.with_text_style(
|
||||||
Some(TextStyleRefinement {
|
Some(TextStyleRefinement {
|
||||||
font_size: Some(self.style.font_size),
|
color: self
|
||||||
font_family: Some(self.style.font_family),
|
.style
|
||||||
|
.hl_theme
|
||||||
|
.settings
|
||||||
|
.foreground
|
||||||
|
.map(hsla_from_syntect),
|
||||||
|
background_color: self
|
||||||
|
.style
|
||||||
|
.hl_theme
|
||||||
|
.settings
|
||||||
|
.background
|
||||||
|
.map(hsla_from_syntect),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|cx| {
|
|cx| {
|
||||||
todo!("draw text??")
|
request_layout
|
||||||
|
.styled
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|(id, styled, bounds)| {
|
||||||
|
styled.paint(None, *bounds, &mut (), &mut (), cx);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use widestring::Utf16Str;
|
use widestring::{Utf16Str, Utf16String};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -41,6 +41,30 @@ impl ViewInputHandler for Editor {
|
||||||
element_bounds: Bounds<Pixels>,
|
element_bounds: Bounds<Pixels>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<Bounds<Pixels>> {
|
) -> Option<Bounds<Pixels>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selected_text_range(
|
||||||
|
&mut self,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) -> Option<std::ops::Range<usize>> {
|
||||||
|
self.buf.read(cx).selected.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_text_in_range(
|
||||||
|
&mut self,
|
||||||
|
range: Option<std::ops::Range<usize>>,
|
||||||
|
text: &str,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) {
|
||||||
|
let text = Utf16String::from_str(text);
|
||||||
|
self.buf.update(cx, |buf, cx| {
|
||||||
|
if let Some(range) = range {
|
||||||
|
buf.text.replace_range(range, &text)
|
||||||
|
} else {
|
||||||
|
buf.text = text;
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_and_mark_text_in_range(
|
fn replace_and_mark_text_in_range(
|
||||||
|
@ -50,7 +74,13 @@ impl ViewInputHandler for Editor {
|
||||||
new_selected_range: Option<std::ops::Range<usize>>,
|
new_selected_range: Option<std::ops::Range<usize>>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
|
let new_text = Utf16String::from_str(new_text);
|
||||||
self.buf.update(cx, |buf, cx| {
|
self.buf.update(cx, |buf, cx| {
|
||||||
|
if let Some(range) = range {
|
||||||
|
buf.text.replace_range(range, &new_text)
|
||||||
|
} else {
|
||||||
|
buf.text = new_text;
|
||||||
|
}
|
||||||
buf.marked = new_selected_range;
|
buf.marked = new_selected_range;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
31
src/main.rs
31
src/main.rs
|
@ -8,10 +8,16 @@ mod editor;
|
||||||
|
|
||||||
struct Nite {
|
struct Nite {
|
||||||
editor: View<editor::Editor>,
|
editor: View<editor::Editor>,
|
||||||
logger: Logger
|
logger: Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Logger = funnylog::Logger<Arc<funnylog::IgnoreError<funnylog::filter::FilterDrain<funnylog::terminal::TerminalDrain<std::io::Stderr>>>>>;
|
type Logger = funnylog::Logger<
|
||||||
|
Arc<
|
||||||
|
funnylog::IgnoreError<
|
||||||
|
funnylog::filter::FilterDrain<funnylog::terminal::TerminalDrain<std::io::Stderr>>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>;
|
||||||
|
|
||||||
impl Render for Nite {
|
impl Render for Nite {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
|
@ -19,8 +25,8 @@ impl Render for Nite {
|
||||||
.flex()
|
.flex()
|
||||||
.size(Length::Definite(DefiniteLength::Fraction(1f32)))
|
.size(Length::Definite(DefiniteLength::Fraction(1f32)))
|
||||||
.bg(transparent_black())
|
.bg(transparent_black())
|
||||||
.justify_center()
|
.justify_start()
|
||||||
.items_center()
|
.items_start()
|
||||||
.text_xl()
|
.text_xl()
|
||||||
.text_color(white())
|
.text_color(white())
|
||||||
.font_family("ComicShannsMono Nerd Font Mono")
|
.font_family("ComicShannsMono Nerd Font Mono")
|
||||||
|
@ -29,8 +35,13 @@ impl Render for Nite {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let drain = Arc::new(funnylog::terminal::TerminalConfig::default().to_stderr().env_filter("RUST_LOG").ignore_error());
|
let drain = Arc::new(
|
||||||
funnylog::stdlog::setup(drain.clone());
|
funnylog::terminal::TerminalConfig::default()
|
||||||
|
.to_stderr()
|
||||||
|
.env_filter("RUST_LOG")
|
||||||
|
.ignore_error(),
|
||||||
|
);
|
||||||
|
funnylog::stdlog::setup(drain.clone()).unwrap();
|
||||||
let logger = Logger::new(drain);
|
let logger = Logger::new(drain);
|
||||||
|
|
||||||
App::new().run(|cx| {
|
App::new().run(|cx| {
|
||||||
|
@ -41,9 +52,13 @@ fn main() {
|
||||||
|cx| {
|
|cx| {
|
||||||
funnylog::info!(logger, "Hello from nite");
|
funnylog::info!(logger, "Hello from nite");
|
||||||
|
|
||||||
|
let settings = cx.new_model(|_cx| editor::EditorSettings::load_defaults());
|
||||||
cx.new_view(|cx| Nite {
|
cx.new_view(|cx| Nite {
|
||||||
editor: editor::Editor::make(cx),
|
editor: editor::Editor::make(
|
||||||
logger
|
cx,
|
||||||
|
settings,
|
||||||
|
),
|
||||||
|
logger,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue