editor load buffer

This commit is contained in:
Dongdong Zhou 2020-09-17 22:33:59 +01:00
parent 8e06b494e1
commit 48e3f842f0
13 changed files with 790 additions and 124 deletions

417
Cargo.lock generated
View File

@ -30,6 +30,12 @@ version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
[[package]]
name = "anymap"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
[[package]]
name = "arrayvec"
version = "0.4.12"
@ -161,12 +167,45 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]]
name = "bumpalo"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytecount"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
[[package]]
name = "byteorder"
version = "1.3.4"
@ -220,6 +259,16 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chashmap"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45"
dependencies = [
"owning_ref 0.3.3",
"parking_lot 0.4.8",
]
[[package]]
name = "clang-sys"
version = "1.0.0"
@ -397,6 +446,7 @@ dependencies = [
name = "crane"
version = "0.0.1"
dependencies = [
"anyhow",
"druid",
"fzyr",
"lazy_static 1.4.0",
@ -407,6 +457,8 @@ dependencies = [
"strum_macros 0.19.2",
"syntect",
"uuid",
"xi-core-lib",
"xi-rope",
]
[[package]]
@ -424,7 +476,7 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7408247b1b87f480890f28b670c5f8d9a8a4274833433fe74dc0dfd46d33650"
dependencies = [
"crossbeam-channel",
"crossbeam-channel 0.2.6",
"crossbeam-deque",
"crossbeam-epoch 0.5.2",
"crossbeam-utils 0.5.0",
@ -443,6 +495,15 @@ dependencies = [
"smallvec 0.6.13",
]
[[package]]
name = "crossbeam-channel"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa"
dependencies = [
"crossbeam-utils 0.6.6",
]
[[package]]
name = "crossbeam-deque"
version = "0.5.2"
@ -497,6 +558,26 @@ dependencies = [
"lazy_static 1.4.0",
]
[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg 1.0.1",
"cfg-if",
"lazy_static 1.4.0",
]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array",
]
[[package]]
name = "discard"
version = "1.0.4"
@ -520,7 +601,7 @@ dependencies = [
"simple_logger",
"unic-langid",
"unicode-segmentation",
"xi-unicode",
"xi-unicode 0.2.1",
]
[[package]]
@ -560,7 +641,7 @@ dependencies = [
"log",
"objc",
"piet-common",
"time",
"time 0.2.18",
"wasm-bindgen",
"web-sys",
"winapi 0.3.9",
@ -598,6 +679,24 @@ dependencies = [
"termcolor",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "filetime"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"winapi 0.3.9",
]
[[package]]
name = "flate2"
version = "1.0.17"
@ -661,12 +760,47 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fsevent"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
dependencies = [
"bitflags",
"fsevent-sys",
]
[[package]]
name = "fsevent-sys"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
dependencies = [
"libc",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
dependencies = [
"bitflags",
"fuchsia-zircon-sys",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "futures"
version = "0.3.5"
@ -850,6 +984,15 @@ dependencies = [
"system-deps",
]
[[package]]
name = "generic-array"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
dependencies = [
"typenum",
]
[[package]]
name = "gio"
version = "0.9.1"
@ -1029,6 +1172,26 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "inotify"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f"
dependencies = [
"bitflags",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
dependencies = [
"libc",
]
[[package]]
name = "instant"
version = "0.1.6"
@ -1060,6 +1223,15 @@ dependencies = [
"unic-langid",
]
[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
dependencies = [
"libc",
]
[[package]]
name = "itertools"
version = "0.7.11"
@ -1176,7 +1348,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
dependencies = [
"owning_ref",
"owning_ref 0.4.1",
"scopeguard 0.3.3",
]
@ -1262,6 +1434,49 @@ dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
dependencies = [
"cfg-if",
"fuchsia-zircon",
"fuchsia-zircon-sys",
"iovec",
"kernel32-sys",
"libc",
"log",
"miow",
"net2",
"slab",
"winapi 0.2.8",
]
[[package]]
name = "mio-extras"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
dependencies = [
"lazycell",
"log",
"mio",
"slab",
]
[[package]]
name = "miow"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
dependencies = [
"kernel32-sys",
"net2",
"winapi 0.2.8",
"ws2_32-sys",
]
[[package]]
name = "ndarray"
version = "0.11.2"
@ -1274,6 +1489,17 @@ dependencies = [
"num-traits 0.1.43",
]
[[package]]
name = "net2"
version = "0.2.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853"
dependencies = [
"cfg-if",
"libc",
"winapi 0.3.9",
]
[[package]]
name = "nodrop"
version = "0.1.14"
@ -1290,6 +1516,28 @@ dependencies = [
"version_check",
]
[[package]]
name = "notify"
version = "5.0.0-pre.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d742ae493f34bd2e20ec2f3c1276fc1981343a8efd7ef12bca4368d0303bed50"
dependencies = [
"anymap",
"bitflags",
"chashmap",
"crossbeam-channel 0.3.9",
"filetime",
"fsevent",
"fsevent-sys",
"inotify",
"kernel32-sys",
"libc",
"mio",
"mio-extras",
"walkdir",
"winapi 0.3.9",
]
[[package]]
name = "num-complex"
version = "0.1.43"
@ -1355,6 +1603,21 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "owning_ref"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
dependencies = [
"stable_deref_trait",
]
[[package]]
name = "owning_ref"
version = "0.4.1"
@ -1391,6 +1654,16 @@ dependencies = [
"system-deps",
]
[[package]]
name = "parking_lot"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
dependencies = [
"owning_ref 0.3.3",
"parking_lot_core 0.2.14",
]
[[package]]
name = "parking_lot"
version = "0.6.4"
@ -1412,6 +1685,18 @@ dependencies = [
"parking_lot_core 0.8.0",
]
[[package]]
name = "parking_lot_core"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa"
dependencies = [
"libc",
"rand 0.4.6",
"smallvec 0.6.13",
"winapi 0.3.9",
]
[[package]]
name = "parking_lot_core"
version = "0.3.1"
@ -1470,7 +1755,7 @@ dependencies = [
"cairo-rs",
"piet",
"unicode-segmentation",
"xi-unicode",
"xi-unicode 0.2.1",
]
[[package]]
@ -1531,7 +1816,7 @@ dependencies = [
"unicode-segmentation",
"wasm-bindgen",
"web-sys",
"xi-unicode",
"xi-unicode 0.2.1",
]
[[package]]
@ -1649,6 +1934,19 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi 0.3.9",
]
[[package]]
name = "rand"
version = "0.5.6"
@ -1939,6 +2237,18 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
[[package]]
name = "sha2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
dependencies = [
"block-buffer",
"digest",
"fake-simd",
"opaque-debug",
]
[[package]]
name = "shlex"
version = "0.1.1"
@ -2187,6 +2497,17 @@ dependencies = [
"lazy_static 1.4.0",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"winapi 0.3.9",
]
[[package]]
name = "time"
version = "0.2.18"
@ -2255,6 +2576,12 @@ dependencies = [
"fxhash",
]
[[package]]
name = "typenum"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
[[package]]
name = "unic-bidi"
version = "0.9.0"
@ -2416,6 +2743,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasm-bindgen"
version = "0.2.68"
@ -2541,12 +2874,84 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
dependencies = [
"winapi 0.2.8",
"winapi-build",
]
[[package]]
name = "xi-core-lib"
version = "0.3.0"
dependencies = [
"crossbeam-channel 0.3.9",
"log",
"memchr",
"notify",
"regex",
"serde",
"serde_derive",
"serde_json",
"sha2",
"syntect",
"time 0.1.44",
"toml",
"xi-rope",
"xi-rpc",
"xi-trace",
"xi-unicode 0.3.0",
]
[[package]]
name = "xi-rope"
version = "0.3.0"
dependencies = [
"bytecount",
"memchr",
"regex",
"serde",
"unicode-segmentation",
]
[[package]]
name = "xi-rpc"
version = "0.3.0"
dependencies = [
"crossbeam-utils 0.7.2",
"log",
"serde",
"serde_derive",
"serde_json",
"xi-trace",
]
[[package]]
name = "xi-trace"
version = "0.2.0"
dependencies = [
"lazy_static 1.4.0",
"libc",
"log",
"serde",
"serde_derive",
"serde_json",
"time 0.1.44",
]
[[package]]
name = "xi-unicode"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e71b85d8b1b8bfaf4b5c834187554d201a8cd621c2bbfa33efd41a3ecabd48b2"
[[package]]
name = "xi-unicode"
version = "0.3.0"
[[package]]
name = "xml-rs"
version = "0.8.3"

View File

@ -5,6 +5,7 @@ authors = ["Dongdong Zhou <dzhou121@gmail.com>"]
edition = "2018"
[dependencies]
anyhow = "1.0.32"
strum = "0.19"
strum_macros = "0.19"
lazy_static = "1.4.0"
@ -12,8 +13,8 @@ lazy_static = "1.4.0"
serde = "1.0"
serde_json = "1.0"
syntect = "3.2"
# xi-core-lib = { path = "../xi-editor/rust/core-lib/" }
# xi-rpc = { path = "../xi-editor/rust/rpc/" }
xi-core-lib = { path = "../xi-editor/rust/core-lib/" }
xi-rope = { path = "../xi-editor/rust/rope/" }
fzyr = "0.1.2"
uuid = { version = "0.7.4", features = ["v4"] }
# crane_ui = {path = "./ui"}

47
src/buffer.rs Normal file
View File

@ -0,0 +1,47 @@
use anyhow::Result;
use std::fs::File;
use std::io::{self, Read, Write};
use xi_rope::{rope::Rope, LinesMetric};
#[derive(Eq, PartialEq, Hash, Clone)]
pub struct BufferId(pub usize);
pub struct Buffer {
pub rope: Rope,
pub num_lines: usize,
pub max_line_len: usize,
}
impl Buffer {
pub fn new(buffer_id: BufferId, path: &str) -> Buffer {
let rope = if let Ok(rope) = load_file(path) {
rope
} else {
Rope::from("")
};
let num_lines = rope.line_of_offset(rope.len()) + 1;
let mut pre_offset = 0;
let mut max_line_len = 0;
for i in 0..num_lines {
let offset = rope.offset_of_line(i);
let line_len = offset - pre_offset;
pre_offset = offset;
if line_len > max_line_len {
max_line_len = line_len;
}
}
Buffer {
rope,
num_lines,
max_line_len,
}
}
}
fn load_file(path: &str) -> Result<Rope> {
let mut f = File::open(path)?;
let mut bytes = Vec::new();
f.read_to_end(&mut bytes)?;
Ok(Rope::from(std::str::from_utf8(&bytes)?))
}

View File

@ -32,9 +32,8 @@ pub enum CraneCommand {
#[derive(Debug)]
pub enum CraneUICommand {
Show,
Hide,
RequestLayout,
RequestPaint,
EnsureVisible((Rect, (f64, f64))),
ScrollTo((f64, f64)),
}

View File

@ -1,6 +1,11 @@
use crate::command::{CraneCommand, CRANE_COMMAND};
use crate::state::CRANE_STATE;
use crate::{
command::{CraneCommand, CRANE_COMMAND},
editor::Editor,
editor::EditorState,
palette::PaletteWrapper,
};
use crate::{palette::Palette, split::CraneSplit};
use crate::{scroll::CraneScroll, state::CRANE_STATE};
use druid::{
kurbo::{Line, Rect},
widget::IdentityWrapper,
@ -26,19 +31,40 @@ pub struct CraneContainer<T> {
}
impl<T: Data> CraneContainer<T> {
pub fn new(
palette: impl Widget<T> + 'static,
editor_split: impl Widget<T> + 'static,
) -> Self {
pub fn new() -> Self {
let palette = PaletteWrapper::new();
let palette_id = WidgetId::next();
let palette =
WidgetPod::new(IdentityWrapper::wrap(palette, palette_id)).boxed();
let editor_split = WidgetPod::new(editor_split).boxed();
CRANE_STATE
.palette
.lock()
.unwrap()
.set_widget_id(palette_id);
let editor_id = WidgetId::next();
let editor = Editor::new(editor_id);
let scroll_id = WidgetId::next();
let editor_state = EditorState::new(editor_id, scroll_id);
CRANE_STATE
.editor_split
.lock()
.unwrap()
.editors
.insert(editor_id, editor_state);
CRANE_STATE
.editor_split
.lock()
.unwrap()
.set_active(editor_id);
let editor_split = WidgetPod::new(CraneSplit::new(true).with_child(
IdentityWrapper::wrap(
CraneScroll::new(IdentityWrapper::wrap(editor, editor_id)),
scroll_id,
),
))
.boxed();
CraneContainer {
palette_max_size: Size::new(600.0, 400.0),
palette_rect: Rect::ZERO
@ -60,7 +86,10 @@ fn event(
) {
ctx.request_focus();
match event {
Event::Internal(_) => self.palette.event(ctx, event, data, env),
Event::Internal(_) => {
self.palette.event(ctx, event, data, env);
self.editor_split.event(ctx, event, data, env);
}
Event::KeyDown(key_event) => CRANE_STATE.key_down(key_event),
Event::Command(cmd) => {
match cmd {
@ -84,7 +113,9 @@ fn event(
| Event::MouseUp(mouse)
| Event::MouseMove(mouse)
| Event::Wheel(mouse) => {
if self.palette_rect.contains(mouse.pos) {
if !CRANE_STATE.palette.lock().unwrap().hidden
&& self.palette_rect.contains(mouse.pos)
{
self.palette.event(ctx, event, data, env);
return;
} else {

View File

@ -1,28 +1,127 @@
use crate::{
buffer::{Buffer, BufferId},
command::CraneUICommand,
command::CRANE_UI_COMMAND,
container::CraneContainer,
state::CRANE_STATE,
theme::CraneTheme,
};
use druid::{
theme, BoxConstraints, Cursor, Data, Env, Event, EventCtx, ExtEventSink,
Key, KeyEvent, LayoutCtx, LifeCycle, LifeCycleCtx, Modifiers, PaintCtx,
Point, RenderContext, Selector, Size, Target, TextLayout, UpdateCtx,
Widget, WidgetPod,
Widget, WidgetId, WidgetPod,
};
use lazy_static::lazy_static;
use std::time::Duration;
use std::{any::Any, thread};
use std::{collections::HashMap, sync::Arc, sync::Mutex};
use crate::container::CraneContainer;
pub struct CraneUI {
container: CraneContainer<u32>,
}
#[derive(Debug, Default)]
pub struct Counter(usize);
impl Counter {
pub fn next(&mut self) -> usize {
let n = self.0;
self.0 = n + 1;
n + 1
}
}
pub struct EditorState {
id: WidgetId,
scroll_id: WidgetId,
buffer_id: Option<BufferId>,
}
impl EditorState {
pub fn new(id: WidgetId, scroll_id: WidgetId) -> EditorState {
EditorState {
id,
scroll_id,
buffer_id: None,
}
}
}
pub struct EditorSplitState {
active: WidgetId,
pub editors: HashMap<WidgetId, EditorState>,
buffers: HashMap<BufferId, Buffer>,
open_files: HashMap<String, BufferId>,
id_counter: Counter,
}
impl EditorSplitState {
pub fn new() -> EditorSplitState {
EditorSplitState {
active: WidgetId::next(),
editors: HashMap::new(),
id_counter: Counter::default(),
buffers: HashMap::new(),
open_files: HashMap::new(),
}
}
pub fn set_active(&mut self, widget_id: WidgetId) {
self.active = widget_id;
}
pub fn open_file(&mut self, path: &str) {
let buffer_id = if let Some(buffer_id) = self.open_files.get(path) {
buffer_id.clone()
} else {
let buffer_id = self.next_buffer_id();
let buffer = Buffer::new(buffer_id.clone(), path);
self.buffers.insert(buffer_id.clone(), buffer);
buffer_id
};
if let Some(active_editor) = self.editors.get_mut(&self.active) {
if let Some(active_buffer) = active_editor.buffer_id.as_mut() {
if active_buffer == &buffer_id {
return;
}
}
active_editor.buffer_id = Some(buffer_id);
println!("submit ui scroll request layout");
CRANE_STATE.submit_ui_command(
CraneUICommand::RequestLayout,
active_editor.scroll_id,
);
}
}
fn next_buffer_id(&mut self) -> BufferId {
BufferId(self.id_counter.next())
}
pub fn get_buffer_id(
&self,
editor_widget_id: &WidgetId,
) -> Option<BufferId> {
self.editors
.get(editor_widget_id)
.map(|e| e.buffer_id.clone())
.unwrap()
}
}
pub struct Editor {
text_layout: TextLayout,
widget_id: WidgetId,
}
impl Editor {
pub fn new() -> Self {
pub fn new(widget_id: WidgetId) -> Self {
let text_layout = TextLayout::new("");
Editor { text_layout }
Editor {
text_layout,
widget_id,
}
}
}
@ -34,6 +133,28 @@ fn event(
data: &mut T,
env: &Env,
) {
match event {
Event::Command(cmd) => match cmd {
_ if cmd.is(CRANE_UI_COMMAND) => {
let command = cmd.get_unchecked(CRANE_UI_COMMAND);
match command {
CraneUICommand::RequestLayout => {
println!("editor request layout");
ctx.request_layout();
}
CraneUICommand::RequestPaint => {
ctx.request_paint();
}
_ => println!(
"editor unprocessed ui command {:?}",
command
),
}
}
_ => (),
},
_ => (),
}
}
fn lifecycle(
@ -61,12 +182,63 @@ fn layout(
data: &T,
env: &Env,
) -> Size {
Size::new(500.0, 1000.0)
let buffer_id = {
CRANE_STATE
.editor_split
.lock()
.unwrap()
.get_buffer_id(&self.widget_id)
};
if let Some(buffer_id) = buffer_id {
let buffers = &CRANE_STATE.editor_split.lock().unwrap().buffers;
let buffer = buffers.get(&buffer_id).unwrap();
let width = 7.6171875;
Size::new(
width * buffer.max_line_len as f64,
25.0 * buffer.num_lines as f64,
)
} else {
Size::new(0.0, 0.0)
}
}
fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
let mut layout = TextLayout::new("abc sldkjfdslkjf");
layout.rebuild_if_needed(&mut ctx.text(), env);
layout.draw(ctx, Point::new(10.0, 10.0));
let line_height = env.get(CraneTheme::EDITOR_LINE_HEIGHT);
let buffer_id = {
CRANE_STATE
.editor_split
.lock()
.unwrap()
.get_buffer_id(&self.widget_id)
};
if let Some(buffer_id) = buffer_id {
let buffers = &CRANE_STATE.editor_split.lock().unwrap().buffers;
let buffer = buffers.get(&buffer_id).unwrap();
let width = 7.6171875;
let rects = ctx.region().rects().to_vec();
for rect in rects {
let start_line = (rect.y0 / line_height).floor() as usize;
let num_lines = (rect.height() / line_height).floor() as usize;
for (i, line) in buffer
.rope
.lines_raw(
buffer.rope.offset_of_line(start_line)
..buffer.rope.offset_of_line(
(start_line + num_lines + 1)
.min(buffer.num_lines),
),
)
.enumerate()
{
let mut layout = TextLayout::new(line);
layout.set_font(CraneTheme::EDITOR_FONT);
layout.rebuild_if_needed(&mut ctx.text(), env);
layout.draw(
ctx,
Point::new(0.0, line_height * (i + start_line) as f64),
);
}
}
}
}
}

15
src/font.rs Normal file
View File

@ -0,0 +1,15 @@
use druid::{FontDescriptor, FontFamily, TextLayout};
pub struct CraneFont {
font: FontDescriptor,
}
impl CraneFont {
pub fn new(font_name: &str, size: f64) {
let font =
FontDescriptor::new(FontFamily::new_unchecked("Cascadia Code"))
.with_size(size);
let mut text_layout = TextLayout::new("W");
text_layout.set_font(font.clone());
}
}

View File

@ -1,6 +1,8 @@
mod buffer;
mod command;
mod container;
mod editor;
mod font;
mod palette;
mod scroll;
mod split;
@ -15,7 +17,7 @@
use crate::split::CraneSplit;
use crate::state::CRANE_STATE;
use druid::{piet::Color, Size};
use druid::{piet::Color, FontDescriptor, FontFamily, Size};
use druid::{
widget::{Align, Container, Flex, Label, Padding, Scroll, Split},
Point,
@ -24,23 +26,7 @@
use palette::PaletteWrapper;
fn build_app() -> impl Widget<u32> {
let editor = Editor::new();
let mut split = CraneSplit::new(true)
.with_child(Scroll::new(Padding::new(
(100.0, 100.0, 100.0, 100.0),
Container::new(editor),
)))
.with_child(Scroll::new(Padding::new(
(100.0, 100.0, 100.0, 100.0),
Container::new(Editor::new())
.border(Color::rgb(122.0, 0.0, 0.0), 2.0),
)));
// .env_scope(|env: &mut druid::Env, data: &u32| {
// env.set(theme::SCROLLBAR_RADIUS, 0.0);
// env.set(theme::SCROLLBAR_WIDTH, 15.0);
// env.set(theme::SCROLLBAR_EDGE_WIDTH, 0.0);
// });
let container = CraneContainer::new(PaletteWrapper::new(0), split);
let container = CraneContainer::new();
container.env_scope(|env: &mut druid::Env, data: &u32| {
env.set(theme::CraneTheme::EDITOR_LINE_HEIGHT, 25.0);
env.set(
@ -59,6 +45,11 @@ fn build_app() -> impl Widget<u32> {
theme::CraneTheme::PALETTE_INPUT_BORDER,
Color::rgb8(0, 0, 0),
);
env.set(
theme::CraneTheme::EDITOR_FONT,
FontDescriptor::new(FontFamily::new_unchecked("Cascadia Code"))
.with_size(13.0),
);
})
}

View File

@ -50,6 +50,7 @@ pub struct PaletteState {
items: Vec<PaletteItem>,
filtered_items: Vec<PaletteItem>,
index: usize,
pub hidden: bool,
}
impl PaletteState {
@ -64,6 +65,7 @@ pub fn new() -> PaletteState {
input: "".to_string(),
cursor: 0,
index: 0,
hidden: true,
}
}
}
@ -87,62 +89,30 @@ pub fn set_width(&mut self, width: f64) {
pub fn run(&mut self) {
self.items = self.get_files();
CRANE_STATE
.ui_sink
.lock()
.unwrap()
.as_ref()
.unwrap()
.submit_command(
CRANE_UI_COMMAND,
CraneUICommand::Show,
Target::Widget(self.widget_id.unwrap().clone()),
);
self.hidden = false;
self.request_layout();
}
pub fn cancel(&mut self) {
self.input = "".to_string();
self.cursor = 0;
self.index = 0;
CRANE_STATE
.ui_sink
.lock()
.unwrap()
.as_ref()
.unwrap()
.submit_command(
CRANE_UI_COMMAND,
CraneUICommand::Hide,
Target::Widget(self.widget_id.unwrap().clone()),
);
self.hidden = true;
self.request_paint();
}
fn request_layout(&self) {
CRANE_STATE
.ui_sink
.lock()
.unwrap()
.as_ref()
.unwrap()
.submit_command(
CRANE_UI_COMMAND,
CraneUICommand::RequestLayout,
Target::Widget(self.widget_id.unwrap().clone()),
);
CRANE_STATE.submit_ui_command(
CraneUICommand::RequestLayout,
self.widget_id.unwrap(),
);
}
fn request_paint(&self) {
CRANE_STATE
.ui_sink
.lock()
.unwrap()
.as_ref()
.unwrap()
.submit_command(
CRANE_UI_COMMAND,
CraneUICommand::RequestPaint,
Target::Widget(self.widget_id.unwrap().clone()),
);
CRANE_STATE.submit_ui_command(
CraneUICommand::RequestPaint,
self.widget_id.unwrap(),
);
}
fn ensure_visible(&self) {
@ -151,17 +121,10 @@ fn ensure_visible(&self) {
.with_size(Size::new(self.width, self.line_height));
let margin = (0.0, 0.0);
CRANE_STATE
.ui_sink
.lock()
.unwrap()
.as_ref()
.unwrap()
.submit_command(
CRANE_UI_COMMAND,
CraneUICommand::EnsureVisible((rect, margin)),
Target::Widget(self.scroll_widget_id.unwrap().clone()),
);
CRANE_STATE.submit_ui_command(
CraneUICommand::EnsureVisible((rect, margin)),
self.widget_id.unwrap(),
);
}
pub fn insert(&mut self, content: &str) {
@ -272,8 +235,8 @@ pub fn select(&mut self) {
if items.is_empty() {
return;
}
let file = &items[self.index];
println!("open file {}", file.text);
CRANE_STATE.open_file(&items[self.index].text);
self.cancel();
}
pub fn change_index(&mut self, n: i64) {
@ -304,7 +267,6 @@ pub struct Palette<T> {
pub struct PaletteWrapper<T> {
palette: WidgetPod<T, Box<dyn Widget<T>>>,
hidden: bool,
}
pub struct PaletteInput {}
@ -756,17 +718,14 @@ pub fn new() -> PaletteInput {
}
impl<T: Data> PaletteWrapper<T> {
pub fn new(data: T) -> PaletteWrapper<T> {
pub fn new() -> PaletteWrapper<T> {
let palette = WidgetPod::new(
Palette::new()
.border(theme::BORDER_LIGHT, 1.0)
.background(CraneTheme::PALETTE_BACKGROUND),
)
.boxed();
PaletteWrapper {
palette,
hidden: true,
}
PaletteWrapper { palette }
}
}
@ -1024,28 +983,22 @@ fn event(
data: &mut T,
env: &Env,
) {
println!("event {:?}", event);
match event {
Event::Internal(_) => self.palette.event(ctx, event, data, env),
Event::Command(cmd) => match cmd {
_ if cmd.is(CRANE_UI_COMMAND) => {
let command = cmd.get_unchecked(CRANE_UI_COMMAND);
match command {
CraneUICommand::Show => {
self.hidden = false;
ctx.request_layout();
}
CraneUICommand::Hide => {
self.hidden = true;
ctx.request_paint();
}
CraneUICommand::RequestLayout => {
ctx.request_layout();
}
CraneUICommand::RequestPaint => {
ctx.request_paint();
}
_ => println!("unprocessed ui command {:?}", command),
_ => println!(
"palette unprocessed ui command {:?}",
command
),
}
}
_ => (),
@ -1092,7 +1045,7 @@ fn layout(
}
fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
if self.hidden {
if CRANE_STATE.palette.lock().unwrap().hidden {
return;
}
self.palette.paint(ctx, data, env);

View File

@ -88,6 +88,12 @@ pub fn scroll(&mut self, delta: Vec2, layout_size: Size) -> bool {
scrolled
}
fn scroll_to(&mut self, x: f64, y: f64) {
let offset = Vec2::new(x, y);
self.scroll_component.scroll_offset = offset;
self.child.set_viewport_offset(offset);
}
fn ensure_visible(
&mut self,
scroll_size: Size,
@ -135,11 +141,25 @@ fn event(
_ if cmd.is(CRANE_UI_COMMAND) => {
let command = cmd.get_unchecked(CRANE_UI_COMMAND);
match command {
CraneUICommand::RequestLayout => {
println!("scroll request layout");
ctx.request_layout();
}
CraneUICommand::RequestPaint => {
ctx.request_paint();
}
CraneUICommand::EnsureVisible((rect, margin)) => {
self.ensure_visible(ctx.size(), rect, margin);
return;
}
_ => println!("unprocessed ui command {:?}", command),
CraneUICommand::ScrollTo((x, y)) => {
self.scroll_to(*x, *y);
return;
}
_ => println!(
"scroll unprocessed ui command {:?}",
command
),
}
}
_ => (),

View File

@ -102,6 +102,14 @@ fn event(
data: &mut T,
env: &Env,
) {
match event {
Event::Internal(_) => {
for child in self.children.as_mut_slice() {
child.event(ctx, event, data, env);
}
}
_ => (),
}
for child in self.children.as_mut_slice() {
if child.is_active() {
child.event(ctx, event, data, env);
@ -200,7 +208,9 @@ fn layout(
let width = if i < children_sizes.len() {
children_sizes[i] * my_size.width
} else {
my_size.width * (1.0 - children_sizes[i - 1])
my_size.width
* (1.0
- if i > 0 { children_sizes[i - 1] } else { 0.0 })
};
let child_bc = BoxConstraints::new(

View File

@ -1,4 +1,5 @@
use std::{
cell::Cell,
collections::HashMap,
str::FromStr,
sync::{Arc, Mutex},
@ -6,11 +7,16 @@
time::Duration,
};
use druid::{ExtEventSink, KeyEvent, Modifiers, Target};
use druid::{ExtEventSink, KeyEvent, Modifiers, Target, WidgetId};
use lazy_static::lazy_static;
use crate::{
buffer::Buffer,
buffer::BufferId,
command::CraneUICommand,
command::CRANE_UI_COMMAND,
command::{CraneCommand, CRANE_COMMAND},
editor::EditorSplitState,
palette::PaletteState,
};
@ -33,6 +39,7 @@ pub struct CraneState {
pub last_focus: Arc<Mutex<CraneWidget>>,
pub focus: Arc<Mutex<CraneWidget>>,
pub ui_sink: Arc<Mutex<Option<ExtEventSink>>>,
pub editor_split: Arc<Mutex<EditorSplitState>>,
}
impl CraneState {
@ -104,6 +111,7 @@ pub fn new() -> CraneState {
focus: Arc::new(Mutex::new(CraneWidget::Editor)),
last_focus: Arc::new(Mutex::new(CraneWidget::Editor)),
palette: Arc::new(Mutex::new(PaletteState::new())),
editor_split: Arc::new(Mutex::new(EditorSplitState::new())),
}
}
@ -245,4 +253,17 @@ pub fn key_down(&self, key_event: &KeyEvent) {
pub fn set_ui_sink(&self, ui_sink: ExtEventSink) {
*self.ui_sink.lock().unwrap() = Some(ui_sink);
}
pub fn open_file(&self, path: &str) {
self.editor_split.lock().unwrap().open_file(path);
}
pub fn submit_ui_command(&self, cmd: CraneUICommand, widget_id: WidgetId) {
self.ui_sink
.lock()
.unwrap()
.as_ref()
.unwrap()
.submit_command(CRANE_UI_COMMAND, cmd, Target::Widget(widget_id));
}
}

View File

@ -1,4 +1,4 @@
use druid::{Color, Key};
use druid::{Color, FontDescriptor, Key};
pub struct CraneTheme {}
@ -13,4 +13,5 @@ impl CraneTheme {
Key::new("crane.palette_input_foreground");
pub const PALETTE_INPUT_BORDER: Key<Color> =
Key::new("crane.palette_input_border");
pub const EDITOR_FONT: Key<FontDescriptor> = Key::new("crane.eidtor_font");
}