Compare commits
11 Commits
compile_ti
...
fix-hover-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30239b3cc6 | ||
|
|
180421fe5a | ||
|
|
1a13995b8f | ||
|
|
b6379a9177 | ||
|
|
2cb041504b | ||
|
|
4d8dc79d7e | ||
|
|
474c806331 | ||
|
|
2db6ccd803 | ||
|
|
2d6a227258 | ||
|
|
a3ce933b04 | ||
|
|
816c48b7d6 |
231
Cargo.lock
generated
231
Cargo.lock
generated
@@ -415,9 +415,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.6"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c"
|
||||
checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"futures-core",
|
||||
@@ -692,9 +692,9 @@ checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.77"
|
||||
version = "0.1.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
||||
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3313,6 +3313,7 @@ dependencies = [
|
||||
"fuzzy",
|
||||
"gpui",
|
||||
"log",
|
||||
"picker",
|
||||
"project",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -3994,15 +3995,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.14"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
||||
checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"fnv",
|
||||
"log",
|
||||
"regex-automata 0.4.5",
|
||||
"regex-syntax 0.8.2",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4523,16 +4524,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.22"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
|
||||
checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata 0.4.5",
|
||||
"regex",
|
||||
"same-file",
|
||||
"thread_local",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
]
|
||||
@@ -4744,15 +4746,6 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
@@ -4806,7 +4799,7 @@ dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"settings",
|
||||
"shellexpand 2.1.2",
|
||||
"shellexpand",
|
||||
"util",
|
||||
"workspace",
|
||||
]
|
||||
@@ -5001,89 +4994,6 @@ dependencies = [
|
||||
"workspace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "languages"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-compression",
|
||||
"async-tar",
|
||||
"async-trait",
|
||||
"collections",
|
||||
"feature_flags",
|
||||
"futures 0.3.28",
|
||||
"gpui",
|
||||
"language",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"lsp",
|
||||
"node_runtime",
|
||||
"parking_lot 0.11.2",
|
||||
"project",
|
||||
"regex",
|
||||
"rope",
|
||||
"rust-embed",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"shellexpand 3.1.0",
|
||||
"smol",
|
||||
"task",
|
||||
"text",
|
||||
"theme",
|
||||
"toml 0.8.10",
|
||||
"tree-sitter",
|
||||
"tree-sitter-astro",
|
||||
"tree-sitter-bash",
|
||||
"tree-sitter-c",
|
||||
"tree-sitter-c-sharp",
|
||||
"tree-sitter-clojure",
|
||||
"tree-sitter-cpp",
|
||||
"tree-sitter-css",
|
||||
"tree-sitter-dart",
|
||||
"tree-sitter-dockerfile",
|
||||
"tree-sitter-elixir",
|
||||
"tree-sitter-elm",
|
||||
"tree-sitter-embedded-template",
|
||||
"tree-sitter-erlang",
|
||||
"tree-sitter-gitcommit",
|
||||
"tree-sitter-gleam",
|
||||
"tree-sitter-glsl",
|
||||
"tree-sitter-go",
|
||||
"tree-sitter-gomod",
|
||||
"tree-sitter-gowork",
|
||||
"tree-sitter-haskell",
|
||||
"tree-sitter-hcl",
|
||||
"tree-sitter-heex",
|
||||
"tree-sitter-html",
|
||||
"tree-sitter-json 0.20.0",
|
||||
"tree-sitter-lua",
|
||||
"tree-sitter-markdown",
|
||||
"tree-sitter-nix",
|
||||
"tree-sitter-nu",
|
||||
"tree-sitter-ocaml",
|
||||
"tree-sitter-php",
|
||||
"tree-sitter-prisma-io",
|
||||
"tree-sitter-proto",
|
||||
"tree-sitter-purescript",
|
||||
"tree-sitter-python",
|
||||
"tree-sitter-racket",
|
||||
"tree-sitter-ruby",
|
||||
"tree-sitter-rust",
|
||||
"tree-sitter-scheme",
|
||||
"tree-sitter-svelte",
|
||||
"tree-sitter-toml",
|
||||
"tree-sitter-typescript",
|
||||
"tree-sitter-uiua",
|
||||
"tree-sitter-vue",
|
||||
"tree-sitter-yaml",
|
||||
"tree-sitter-zig",
|
||||
"unindent",
|
||||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -7011,7 +6921,6 @@ dependencies = [
|
||||
"postage",
|
||||
"prettier",
|
||||
"pretty_assertions",
|
||||
"project_core",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"release_channel",
|
||||
@@ -7036,37 +6945,6 @@ dependencies = [
|
||||
"which 6.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"client",
|
||||
"clock",
|
||||
"collections",
|
||||
"fs",
|
||||
"futures 0.3.28",
|
||||
"fuzzy",
|
||||
"git",
|
||||
"gpui",
|
||||
"ignore",
|
||||
"itertools 0.12.1",
|
||||
"language",
|
||||
"log",
|
||||
"lsp",
|
||||
"parking_lot 0.11.2",
|
||||
"postage",
|
||||
"rpc",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"smol",
|
||||
"sum_tree",
|
||||
"text",
|
||||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project_panel"
|
||||
version = "0.1.0"
|
||||
@@ -7461,6 +7339,7 @@ dependencies = [
|
||||
name = "recent_projects"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"editor",
|
||||
"futures 0.3.28",
|
||||
"fuzzy",
|
||||
"gpui",
|
||||
@@ -7922,9 +7801,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.2.0"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a82c0bbc10308ed323529fd3c1dce8badda635aa319a5ff0e6466f33b8101e3f"
|
||||
checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
@@ -7933,9 +7812,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "8.2.0"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6227c01b1783cdfee1bcf844eb44594cd16ec71c35305bf1c9fb5aade2735e16"
|
||||
checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -7946,9 +7825,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "8.2.0"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cb0a25bfbb2d4b4402179c2cf030387d9990857ce08a32592c6238db9fa8665"
|
||||
checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada"
|
||||
dependencies = [
|
||||
"globset",
|
||||
"sha2 0.10.7",
|
||||
@@ -8667,20 +8546,11 @@ dependencies = [
|
||||
"dirs 4.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellexpand"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
@@ -9511,6 +9381,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"db",
|
||||
"editor",
|
||||
"fs",
|
||||
"futures 0.3.28",
|
||||
"fuzzy",
|
||||
@@ -9585,7 +9456,7 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"shellexpand 2.1.2",
|
||||
"shellexpand",
|
||||
"smallvec",
|
||||
"smol",
|
||||
"task",
|
||||
@@ -9620,7 +9491,7 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"shellexpand 2.1.2",
|
||||
"shellexpand",
|
||||
"smallvec",
|
||||
"smol",
|
||||
"task",
|
||||
@@ -12135,7 +12006,6 @@ dependencies = [
|
||||
"language",
|
||||
"language_selector",
|
||||
"language_tools",
|
||||
"languages",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -12169,7 +12039,7 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"shellexpand 2.1.2",
|
||||
"shellexpand",
|
||||
"simplelog",
|
||||
"smallvec",
|
||||
"smol",
|
||||
@@ -12184,7 +12054,52 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tiny_http",
|
||||
"toml 0.8.10",
|
||||
"tree-sitter",
|
||||
"tree-sitter-astro",
|
||||
"tree-sitter-bash",
|
||||
"tree-sitter-c",
|
||||
"tree-sitter-c-sharp",
|
||||
"tree-sitter-clojure",
|
||||
"tree-sitter-cpp",
|
||||
"tree-sitter-css",
|
||||
"tree-sitter-dart",
|
||||
"tree-sitter-dockerfile",
|
||||
"tree-sitter-elixir",
|
||||
"tree-sitter-elm",
|
||||
"tree-sitter-embedded-template",
|
||||
"tree-sitter-erlang",
|
||||
"tree-sitter-gitcommit",
|
||||
"tree-sitter-gleam",
|
||||
"tree-sitter-glsl",
|
||||
"tree-sitter-go",
|
||||
"tree-sitter-gomod",
|
||||
"tree-sitter-gowork",
|
||||
"tree-sitter-haskell",
|
||||
"tree-sitter-hcl",
|
||||
"tree-sitter-heex",
|
||||
"tree-sitter-html",
|
||||
"tree-sitter-json 0.20.0",
|
||||
"tree-sitter-lua",
|
||||
"tree-sitter-markdown",
|
||||
"tree-sitter-nix",
|
||||
"tree-sitter-nu",
|
||||
"tree-sitter-ocaml",
|
||||
"tree-sitter-php",
|
||||
"tree-sitter-prisma-io",
|
||||
"tree-sitter-proto",
|
||||
"tree-sitter-purescript",
|
||||
"tree-sitter-python",
|
||||
"tree-sitter-racket",
|
||||
"tree-sitter-ruby",
|
||||
"tree-sitter-rust",
|
||||
"tree-sitter-scheme",
|
||||
"tree-sitter-svelte",
|
||||
"tree-sitter-toml",
|
||||
"tree-sitter-typescript",
|
||||
"tree-sitter-uiua",
|
||||
"tree-sitter-vue",
|
||||
"tree-sitter-yaml",
|
||||
"tree-sitter-zig",
|
||||
"unindent",
|
||||
"url",
|
||||
"urlencoding",
|
||||
|
||||
@@ -38,7 +38,6 @@ members = [
|
||||
"crates/language",
|
||||
"crates/language_selector",
|
||||
"crates/language_tools",
|
||||
"crates/languages",
|
||||
"crates/live_kit_client",
|
||||
"crates/live_kit_server",
|
||||
"crates/lsp",
|
||||
@@ -54,7 +53,6 @@ members = [
|
||||
"crates/plugin_macros",
|
||||
"crates/prettier",
|
||||
"crates/project",
|
||||
"crates/project_core",
|
||||
"crates/project_panel",
|
||||
"crates/project_symbols",
|
||||
"crates/quick_action_bar",
|
||||
@@ -149,7 +147,6 @@ plugin = { path = "crates/plugin" }
|
||||
plugin_macros = { path = "crates/plugin_macros" }
|
||||
prettier = { path = "crates/prettier" }
|
||||
project = { path = "crates/project" }
|
||||
project_core = { path = "crates/project_core" }
|
||||
project_panel = { path = "crates/project_panel" }
|
||||
project_symbols = { path = "crates/project_symbols" }
|
||||
quick_action_bar = { path = "crates/quick_action_bar" }
|
||||
|
||||
@@ -2672,24 +2672,32 @@ fn render_tree_branch(is_last: bool, overdraw: bool, cx: &mut WindowContext) ->
|
||||
let right = bounds.right();
|
||||
let top = bounds.top();
|
||||
|
||||
cx.paint_quad(fill(
|
||||
Bounds::from_corners(
|
||||
point(start_x, top),
|
||||
point(
|
||||
start_x + thickness,
|
||||
if is_last {
|
||||
start_y
|
||||
} else {
|
||||
bounds.bottom() + if overdraw { px(1.) } else { px(0.) }
|
||||
},
|
||||
cx.paint_quad(
|
||||
fill(
|
||||
Bounds::from_corners(
|
||||
point(start_x, top),
|
||||
point(
|
||||
start_x + thickness,
|
||||
if is_last {
|
||||
start_y
|
||||
} else {
|
||||
bounds.bottom() + if overdraw { px(1.) } else { px(0.) }
|
||||
},
|
||||
),
|
||||
),
|
||||
color,
|
||||
),
|
||||
color,
|
||||
));
|
||||
cx.paint_quad(fill(
|
||||
Bounds::from_corners(point(start_x, start_y), point(right, start_y + thickness)),
|
||||
color,
|
||||
));
|
||||
None,
|
||||
None,
|
||||
);
|
||||
cx.paint_quad(
|
||||
fill(
|
||||
Bounds::from_corners(point(start_x, start_y), point(right, start_y + thickness)),
|
||||
color,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
})
|
||||
.w(width)
|
||||
.h(line_height)
|
||||
|
||||
@@ -15,6 +15,7 @@ client.workspace = true
|
||||
collections.workspace = true
|
||||
# HACK: We're only depending on `copilot` here for `CommandPaletteFilter`. See the attached comment on that type.
|
||||
copilot.workspace = true
|
||||
editor.workspace = true
|
||||
fuzzy.workspace = true
|
||||
gpui.workspace = true
|
||||
picker.workspace = true
|
||||
|
||||
@@ -1584,6 +1584,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn editor_blocks(editor: &View<Editor>, cx: &mut WindowContext) -> Vec<(u32, SharedString)> {
|
||||
let editor_view = editor.clone();
|
||||
editor.update(cx, |editor, cx| {
|
||||
let snapshot = editor.snapshot(cx);
|
||||
snapshot
|
||||
@@ -1592,6 +1593,7 @@ mod tests {
|
||||
.filter_map(|(ix, (row, block))| {
|
||||
let name: SharedString = match block {
|
||||
TransformBlock::Custom(block) => cx.with_element_context({
|
||||
let editor_view = editor_view.clone();
|
||||
|cx| -> Option<SharedString> {
|
||||
block
|
||||
.render(&mut BlockContext {
|
||||
@@ -1602,6 +1604,7 @@ mod tests {
|
||||
em_width: px(0.),
|
||||
max_width: px(0.),
|
||||
block_id: ix,
|
||||
view: editor_view,
|
||||
editor_style: &editor::EditorStyle::default(),
|
||||
})
|
||||
.inner_id()?
|
||||
|
||||
@@ -24,7 +24,10 @@ mod tab_map;
|
||||
mod wrap_map;
|
||||
|
||||
use crate::EditorStyle;
|
||||
use crate::{hover_links::InlayHighlight, movement::TextLayoutDetails, InlayId};
|
||||
use crate::{
|
||||
hover_links::InlayHighlight, movement::TextLayoutDetails, Anchor, AnchorRangeExt, InlayId,
|
||||
MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
|
||||
};
|
||||
pub use block_map::{BlockMap, BlockPoint};
|
||||
use collections::{BTreeMap, HashMap, HashSet};
|
||||
use fold_map::FoldMap;
|
||||
@@ -34,7 +37,6 @@ use language::{
|
||||
language_settings::language_settings, OffsetUtf16, Point, Subscription as BufferSubscription,
|
||||
};
|
||||
use lsp::DiagnosticSeverity;
|
||||
use multi_buffer::{Anchor, AnchorRangeExt, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint};
|
||||
use std::{any::TypeId, borrow::Cow, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc};
|
||||
use sum_tree::{Bias, TreeMap};
|
||||
use tab_map::TabMap;
|
||||
|
||||
@@ -2,11 +2,10 @@ use super::{
|
||||
wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot},
|
||||
Highlights,
|
||||
};
|
||||
use crate::{EditorStyle, GutterDimensions};
|
||||
use crate::{Anchor, Editor, EditorStyle, ExcerptId, ExcerptRange, GutterDimensions, ToPoint as _};
|
||||
use collections::{Bound, HashMap, HashSet};
|
||||
use gpui::{AnyElement, ElementContext, Pixels};
|
||||
use gpui::{AnyElement, ElementContext, Pixels, View};
|
||||
use language::{BufferSnapshot, Chunk, Patch, Point};
|
||||
use multi_buffer::{Anchor, ExcerptId, ExcerptRange, ToPoint as _};
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
@@ -86,6 +85,7 @@ pub enum BlockStyle {
|
||||
|
||||
pub struct BlockContext<'a, 'b> {
|
||||
pub context: &'b mut ElementContext<'a>,
|
||||
pub view: View<Editor>,
|
||||
pub anchor_x: Pixels,
|
||||
pub max_width: Pixels,
|
||||
pub gutter_dimensions: &'b GutterDimensions,
|
||||
|
||||
@@ -2,9 +2,9 @@ use super::{
|
||||
inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot},
|
||||
Highlights,
|
||||
};
|
||||
use crate::{Anchor, AnchorRangeExt, MultiBufferSnapshot, ToOffset};
|
||||
use gpui::{ElementId, HighlightStyle, Hsla};
|
||||
use language::{Chunk, Edit, Point, TextSummary};
|
||||
use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferSnapshot, ToOffset};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
cmp::{self, Ordering},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::InlayId;
|
||||
use crate::{Anchor, InlayId, MultiBufferSnapshot, ToOffset};
|
||||
use collections::{BTreeMap, BTreeSet};
|
||||
use gpui::HighlightStyle;
|
||||
use language::{Chunk, Edit, Point, TextSummary};
|
||||
use multi_buffer::{Anchor, MultiBufferChunks, MultiBufferRows, MultiBufferSnapshot, ToOffset};
|
||||
use multi_buffer::{MultiBufferChunks, MultiBufferRows};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
cmp,
|
||||
|
||||
@@ -2,8 +2,8 @@ use super::{
|
||||
fold_map::{self, FoldChunks, FoldEdit, FoldPoint, FoldSnapshot},
|
||||
Highlights,
|
||||
};
|
||||
use crate::MultiBufferSnapshot;
|
||||
use language::{Chunk, Point};
|
||||
use multi_buffer::MultiBufferSnapshot;
|
||||
use std::{cmp, mem, num::NonZeroU32, ops::Range};
|
||||
use sum_tree::Bias;
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ use super::{
|
||||
tab_map::{self, TabEdit, TabPoint, TabSnapshot},
|
||||
Highlights,
|
||||
};
|
||||
use crate::MultiBufferSnapshot;
|
||||
use gpui::{AppContext, Context, Font, LineWrapper, Model, ModelContext, Pixels, Task};
|
||||
use language::{Chunk, Point};
|
||||
use lazy_static::lazy_static;
|
||||
use multi_buffer::MultiBufferSnapshot;
|
||||
use smol::future::yield_now;
|
||||
use std::{cmp, collections::VecDeque, mem, ops::Range, time::Duration};
|
||||
use sum_tree::{Bias, Cursor, SumTree};
|
||||
|
||||
@@ -122,7 +122,7 @@ use ui::{
|
||||
};
|
||||
use util::{maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
|
||||
use workspace::Toast;
|
||||
use workspace::{searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace};
|
||||
use workspace::{searchable::SearchEvent, ItemNavHistory, Pane, SplitDirection, ViewId, Workspace};
|
||||
|
||||
use crate::hover_links::find_url;
|
||||
|
||||
@@ -356,6 +356,7 @@ type InlayBackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<InlayHighlight>);
|
||||
///
|
||||
/// See the [module level documentation](self) for more information.
|
||||
pub struct Editor {
|
||||
handle: WeakView<Self>,
|
||||
focus_handle: FocusHandle,
|
||||
/// The text buffer being edited
|
||||
buffer: Model<MultiBuffer>,
|
||||
@@ -1487,6 +1488,7 @@ impl Editor {
|
||||
cx.on_blur(&focus_handle, Self::handle_blur).detach();
|
||||
|
||||
let mut this = Self {
|
||||
handle: cx.view().downgrade(),
|
||||
focus_handle,
|
||||
buffer: buffer.clone(),
|
||||
display_map: display_map.clone(),
|
||||
@@ -1684,6 +1686,10 @@ impl Editor {
|
||||
self.workspace.as_ref()?.0.upgrade()
|
||||
}
|
||||
|
||||
pub fn pane(&self, cx: &AppContext) -> Option<View<Pane>> {
|
||||
self.workspace()?.read(cx).pane_for(&self.handle.upgrade()?)
|
||||
}
|
||||
|
||||
pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
|
||||
self.buffer().read(cx).title(cx)
|
||||
}
|
||||
|
||||
@@ -632,8 +632,8 @@ impl EditorElement {
|
||||
let scroll_top =
|
||||
layout.position_map.snapshot.scroll_position().y * layout.position_map.line_height;
|
||||
let gutter_bg = cx.theme().colors().editor_gutter_background;
|
||||
cx.paint_quad(fill(gutter_bounds, gutter_bg));
|
||||
cx.paint_quad(fill(text_bounds, self.style.background));
|
||||
cx.paint_quad(fill(gutter_bounds, gutter_bg), None, None);
|
||||
cx.paint_quad(fill(text_bounds, self.style.background), None, None);
|
||||
|
||||
if let EditorMode::Full = layout.mode {
|
||||
let mut active_rows = layout.active_rows.iter().peekable();
|
||||
@@ -657,7 +657,7 @@ impl EditorElement {
|
||||
layout.position_map.line_height * (end_row - start_row + 1) as f32,
|
||||
);
|
||||
let active_line_bg = cx.theme().colors().editor_active_line_background;
|
||||
cx.paint_quad(fill(Bounds { origin, size }, active_line_bg));
|
||||
cx.paint_quad(fill(Bounds { origin, size }, active_line_bg), None, None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -673,7 +673,11 @@ impl EditorElement {
|
||||
layout.position_map.line_height * highlighted_rows.len() as f32,
|
||||
);
|
||||
let highlighted_line_bg = cx.theme().colors().editor_highlighted_line_background;
|
||||
cx.paint_quad(fill(Bounds { origin, size }, highlighted_line_bg));
|
||||
cx.paint_quad(
|
||||
fill(Bounds { origin, size }, highlighted_line_bg),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
let scroll_left =
|
||||
@@ -694,13 +698,17 @@ impl EditorElement {
|
||||
} else {
|
||||
cx.theme().colors().editor_wrap_guide
|
||||
};
|
||||
cx.paint_quad(fill(
|
||||
Bounds {
|
||||
origin: point(x, text_bounds.origin.y),
|
||||
size: size(px(1.), text_bounds.size.height),
|
||||
},
|
||||
color,
|
||||
));
|
||||
cx.paint_quad(
|
||||
fill(
|
||||
Bounds {
|
||||
origin: point(x, text_bounds.origin.y),
|
||||
size: size(px(1.), text_bounds.size.height),
|
||||
},
|
||||
color,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -804,13 +812,17 @@ impl EditorElement {
|
||||
let highlight_origin = bounds.origin + point(-width, start_y);
|
||||
let highlight_size = size(width * 2., end_y - start_y);
|
||||
let highlight_bounds = Bounds::new(highlight_origin, highlight_size);
|
||||
cx.paint_quad(quad(
|
||||
highlight_bounds,
|
||||
Corners::all(1. * line_height),
|
||||
cx.theme().status().modified,
|
||||
Edges::default(),
|
||||
transparent_black(),
|
||||
));
|
||||
cx.paint_quad(
|
||||
quad(
|
||||
highlight_bounds,
|
||||
Corners::all(1. * line_height),
|
||||
cx.theme().status().modified,
|
||||
Edges::default(),
|
||||
transparent_black(),
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -837,13 +849,17 @@ impl EditorElement {
|
||||
let highlight_origin = bounds.origin + point(-width, start_y);
|
||||
let highlight_size = size(width * 2., end_y - start_y);
|
||||
let highlight_bounds = Bounds::new(highlight_origin, highlight_size);
|
||||
cx.paint_quad(quad(
|
||||
highlight_bounds,
|
||||
Corners::all(1. * line_height),
|
||||
cx.theme().status().deleted,
|
||||
Edges::default(),
|
||||
transparent_black(),
|
||||
));
|
||||
cx.paint_quad(
|
||||
quad(
|
||||
highlight_bounds,
|
||||
Corners::all(1. * line_height),
|
||||
cx.theme().status().deleted,
|
||||
Edges::default(),
|
||||
transparent_black(),
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -877,13 +893,17 @@ impl EditorElement {
|
||||
let highlight_origin = bounds.origin + point(-width, start_y);
|
||||
let highlight_size = size(width * 2., end_y - start_y);
|
||||
let highlight_bounds = Bounds::new(highlight_origin, highlight_size);
|
||||
cx.paint_quad(quad(
|
||||
highlight_bounds,
|
||||
Corners::all(0.05 * line_height),
|
||||
color,
|
||||
Edges::default(),
|
||||
transparent_black(),
|
||||
));
|
||||
cx.paint_quad(
|
||||
quad(
|
||||
highlight_bounds,
|
||||
Corners::all(0.05 * line_height),
|
||||
color,
|
||||
Edges::default(),
|
||||
transparent_black(),
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1346,18 +1366,22 @@ impl EditorElement {
|
||||
let thumb_bounds = Bounds::from_corners(point(left, thumb_top), point(right, thumb_bottom));
|
||||
|
||||
if layout.show_scrollbars {
|
||||
cx.paint_quad(quad(
|
||||
track_bounds,
|
||||
Corners::default(),
|
||||
cx.theme().colors().scrollbar_track_background,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: Pixels::ZERO,
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_track_border,
|
||||
));
|
||||
cx.paint_quad(
|
||||
quad(
|
||||
track_bounds,
|
||||
Corners::default(),
|
||||
cx.theme().colors().scrollbar_track_background,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: Pixels::ZERO,
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_track_border,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let scrollbar_settings = EditorSettings::get_global(cx).scrollbar;
|
||||
if layout.is_singleton && scrollbar_settings.selections {
|
||||
let start_anchor = Anchor::min();
|
||||
@@ -1377,18 +1401,22 @@ impl EditorElement {
|
||||
end_y = start_y + px(1.);
|
||||
}
|
||||
let bounds = Bounds::from_corners(point(left, start_y), point(right, end_y));
|
||||
cx.paint_quad(quad(
|
||||
bounds,
|
||||
Corners::default(),
|
||||
cx.theme().status().info,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
));
|
||||
cx.paint_quad(
|
||||
quad(
|
||||
bounds,
|
||||
Corners::default(),
|
||||
cx.theme().status().info,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1415,18 +1443,22 @@ impl EditorElement {
|
||||
}
|
||||
let bounds = Bounds::from_corners(point(left, start_y), point(right, end_y));
|
||||
|
||||
cx.paint_quad(quad(
|
||||
bounds,
|
||||
Corners::default(),
|
||||
cx.theme().status().info,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
));
|
||||
cx.paint_quad(
|
||||
quad(
|
||||
bounds,
|
||||
Corners::default(),
|
||||
cx.theme().status().info,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1458,18 +1490,22 @@ impl EditorElement {
|
||||
DiffHunkStatus::Modified => cx.theme().status().modified,
|
||||
DiffHunkStatus::Removed => cx.theme().status().deleted,
|
||||
};
|
||||
cx.paint_quad(quad(
|
||||
bounds,
|
||||
Corners::default(),
|
||||
color,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
));
|
||||
cx.paint_quad(
|
||||
quad(
|
||||
bounds,
|
||||
Corners::default(),
|
||||
color,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1516,33 +1552,41 @@ impl EditorElement {
|
||||
DiagnosticSeverity::INFORMATION => cx.theme().status().info,
|
||||
_ => cx.theme().status().hint,
|
||||
};
|
||||
cx.paint_quad(quad(
|
||||
bounds,
|
||||
Corners::default(),
|
||||
color,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
));
|
||||
cx.paint_quad(
|
||||
quad(
|
||||
bounds,
|
||||
Corners::default(),
|
||||
color,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cx.paint_quad(quad(
|
||||
thumb_bounds,
|
||||
Corners::default(),
|
||||
cx.theme().colors().scrollbar_thumb_background,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
));
|
||||
cx.paint_quad(
|
||||
quad(
|
||||
thumb_bounds,
|
||||
Corners::default(),
|
||||
cx.theme().colors().scrollbar_thumb_background,
|
||||
Edges {
|
||||
top: Pixels::ZERO,
|
||||
right: px(1.),
|
||||
bottom: Pixels::ZERO,
|
||||
left: px(1.),
|
||||
},
|
||||
cx.theme().colors().scrollbar_thumb_border,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
let interactive_track_bounds = InteractiveBounds {
|
||||
@@ -2225,6 +2269,7 @@ impl EditorElement {
|
||||
.width;
|
||||
let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.width;
|
||||
|
||||
let editor_view = cx.view().clone();
|
||||
let (scroll_width, blocks) = cx.with_element_context(|cx| {
|
||||
cx.with_element_id(Some("editor_blocks"), |cx| {
|
||||
self.layout_blocks(
|
||||
@@ -2240,6 +2285,7 @@ impl EditorElement {
|
||||
&style,
|
||||
&line_layouts,
|
||||
editor,
|
||||
editor_view,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
@@ -2434,6 +2480,7 @@ impl EditorElement {
|
||||
style: &EditorStyle,
|
||||
line_layouts: &[LineWithInvisibles],
|
||||
editor: &mut Editor,
|
||||
editor_view: View<Editor>,
|
||||
cx: &mut ElementContext,
|
||||
) -> (Pixels, Vec<BlockLayout>) {
|
||||
let mut block_id = 0;
|
||||
@@ -2474,6 +2521,7 @@ impl EditorElement {
|
||||
em_width,
|
||||
block_id,
|
||||
max_width: scroll_width.max(text_width),
|
||||
view: editor_view.clone(),
|
||||
editor_style: &self.style,
|
||||
})
|
||||
}
|
||||
@@ -3417,7 +3465,7 @@ impl Cursor {
|
||||
})
|
||||
}
|
||||
|
||||
cx.paint_quad(cursor);
|
||||
cx.paint_quad(cursor, None, None);
|
||||
|
||||
if let Some(block_text) = &self.block_text {
|
||||
block_text
|
||||
|
||||
@@ -24,6 +24,7 @@ futures.workspace = true
|
||||
fuzzy.workspace = true
|
||||
gpui.workspace = true
|
||||
log.workspace = true
|
||||
picker.workspace = true
|
||||
project.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
@@ -94,7 +94,7 @@ fn generate_shader_bindings() -> PathBuf {
|
||||
let mut builder = cbindgen::Builder::new();
|
||||
|
||||
let src_paths = [
|
||||
crate_dir.join("src/scene.rs"),
|
||||
crate_dir.join("src/scene/primitives.rs"),
|
||||
crate_dir.join("src/geometry.rs"),
|
||||
crate_dir.join("src/color.rs"),
|
||||
crate_dir.join("src/window.rs"),
|
||||
|
||||
363
crates/gpui/src/bounds_tree.rs
Normal file
363
crates/gpui/src/bounds_tree.rs
Normal file
@@ -0,0 +1,363 @@
|
||||
use crate::{Bounds, Half, Point};
|
||||
use std::{
|
||||
cmp,
|
||||
fmt::Debug,
|
||||
ops::{Add, Sub},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BoundsTree<U, T>
|
||||
where
|
||||
U: Default + Clone + Debug,
|
||||
T: Clone + Debug,
|
||||
{
|
||||
root: Option<usize>,
|
||||
nodes: Vec<Node<U, T>>,
|
||||
stack: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<U, T> BoundsTree<U, T>
|
||||
where
|
||||
U: Clone + Debug + PartialOrd + Add<U, Output = U> + Sub<Output = U> + Half + Default,
|
||||
T: Clone + Debug,
|
||||
{
|
||||
pub fn clear(&mut self) {
|
||||
self.root = None;
|
||||
self.nodes.clear();
|
||||
self.stack.clear();
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, new_bounds: Bounds<U>, payload: T) -> u32 {
|
||||
// If the tree is empty, make the root the new leaf.
|
||||
if self.root.is_none() {
|
||||
let new_node = self.push_leaf(new_bounds, payload, 1);
|
||||
self.root = Some(new_node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Search for the best place to add the new leaf based on heuristics.
|
||||
let mut max_intersecting_ordering = 0;
|
||||
let mut index = self.root.unwrap();
|
||||
while let Node::Internal {
|
||||
left,
|
||||
right,
|
||||
bounds: node_bounds,
|
||||
..
|
||||
} = &mut self.nodes[index]
|
||||
{
|
||||
let left = *left;
|
||||
let right = *right;
|
||||
*node_bounds = node_bounds.union(&new_bounds);
|
||||
self.stack.push(index);
|
||||
|
||||
// Descend to the best-fit child, based on which one would increase
|
||||
// the surface area the least. This attempts to keep the tree balanced
|
||||
// in terms of surface area. If there is an intersection with the other child,
|
||||
// add its keys to the intersections vector.
|
||||
let left_cost = new_bounds
|
||||
.union(&self.nodes[left].bounds())
|
||||
.half_perimeter();
|
||||
let right_cost = new_bounds
|
||||
.union(&self.nodes[right].bounds())
|
||||
.half_perimeter();
|
||||
if left_cost < right_cost {
|
||||
max_intersecting_ordering =
|
||||
self.find_max_ordering(right, &new_bounds, max_intersecting_ordering);
|
||||
index = left;
|
||||
} else {
|
||||
max_intersecting_ordering =
|
||||
self.find_max_ordering(left, &new_bounds, max_intersecting_ordering);
|
||||
index = right;
|
||||
}
|
||||
}
|
||||
|
||||
// We've found a leaf ('index' now refers to a leaf node).
|
||||
// We'll insert a new parent node above the leaf and attach our new leaf to it.
|
||||
let sibling = index;
|
||||
|
||||
// Check for collision with the located leaf node
|
||||
let Node::Leaf {
|
||||
bounds: sibling_bounds,
|
||||
order: sibling_ordering,
|
||||
..
|
||||
} = &self.nodes[index]
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
if sibling_bounds.intersects(&new_bounds) {
|
||||
max_intersecting_ordering = cmp::max(max_intersecting_ordering, *sibling_ordering);
|
||||
}
|
||||
|
||||
let ordering = max_intersecting_ordering + 1;
|
||||
let new_node = self.push_leaf(new_bounds, payload, ordering);
|
||||
let new_parent = self.push_internal(sibling, new_node);
|
||||
|
||||
// If there was an old parent, we need to update its children indices.
|
||||
if let Some(old_parent) = self.stack.last().copied() {
|
||||
let Node::Internal { left, right, .. } = &mut self.nodes[old_parent] else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
if *left == sibling {
|
||||
*left = new_parent;
|
||||
} else {
|
||||
*right = new_parent;
|
||||
}
|
||||
} else {
|
||||
// If the old parent was the root, the new parent is the new root.
|
||||
self.root = Some(new_parent);
|
||||
}
|
||||
|
||||
for node_index in self.stack.drain(..) {
|
||||
let Node::Internal {
|
||||
max_order: max_ordering,
|
||||
..
|
||||
} = &mut self.nodes[node_index]
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
*max_ordering = cmp::max(*max_ordering, ordering);
|
||||
}
|
||||
|
||||
ordering
|
||||
}
|
||||
|
||||
/// Finds all nodes whose bounds contain the given point and pushes their (bounds, payload) pairs onto the result vector.
|
||||
pub(crate) fn find_containing(
|
||||
&mut self,
|
||||
point: &Point<U>,
|
||||
result: &mut Vec<BoundsSearchResult<U, T>>,
|
||||
) {
|
||||
if let Some(mut index) = self.root {
|
||||
self.stack.clear();
|
||||
self.stack.push(index);
|
||||
|
||||
while let Some(current_index) = self.stack.pop() {
|
||||
match &self.nodes[current_index] {
|
||||
Node::Leaf {
|
||||
bounds,
|
||||
order,
|
||||
data,
|
||||
} => {
|
||||
if bounds.contains(point) {
|
||||
result.push(BoundsSearchResult {
|
||||
bounds: bounds.clone(),
|
||||
order: *order,
|
||||
data: data.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Node::Internal {
|
||||
left,
|
||||
right,
|
||||
bounds,
|
||||
..
|
||||
} => {
|
||||
if bounds.contains(point) {
|
||||
self.stack.push(*left);
|
||||
self.stack.push(*right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_max_ordering(&self, index: usize, bounds: &Bounds<U>, mut max_ordering: u32) -> u32 {
|
||||
match {
|
||||
let this = &self;
|
||||
&this.nodes[index]
|
||||
} {
|
||||
Node::Leaf {
|
||||
bounds: node_bounds,
|
||||
order: ordering,
|
||||
..
|
||||
} => {
|
||||
if bounds.intersects(node_bounds) {
|
||||
max_ordering = cmp::max(*ordering, max_ordering);
|
||||
}
|
||||
}
|
||||
Node::Internal {
|
||||
left,
|
||||
right,
|
||||
bounds: node_bounds,
|
||||
max_order: node_max_ordering,
|
||||
..
|
||||
} => {
|
||||
if bounds.intersects(node_bounds) && max_ordering < *node_max_ordering {
|
||||
let left_max_ordering = self.nodes[*left].max_ordering();
|
||||
let right_max_ordering = self.nodes[*right].max_ordering();
|
||||
if left_max_ordering > right_max_ordering {
|
||||
max_ordering = self.find_max_ordering(*left, bounds, max_ordering);
|
||||
max_ordering = self.find_max_ordering(*right, bounds, max_ordering);
|
||||
} else {
|
||||
max_ordering = self.find_max_ordering(*right, bounds, max_ordering);
|
||||
max_ordering = self.find_max_ordering(*left, bounds, max_ordering);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
max_ordering
|
||||
}
|
||||
|
||||
fn push_leaf(&mut self, bounds: Bounds<U>, payload: T, order: u32) -> usize {
|
||||
self.nodes.push(Node::Leaf {
|
||||
bounds,
|
||||
data: payload,
|
||||
order,
|
||||
});
|
||||
self.nodes.len() - 1
|
||||
}
|
||||
|
||||
fn push_internal(&mut self, left: usize, right: usize) -> usize {
|
||||
let left_node = &self.nodes[left];
|
||||
let right_node = &self.nodes[right];
|
||||
let new_bounds = left_node.bounds().union(right_node.bounds());
|
||||
let max_ordering = cmp::max(left_node.max_ordering(), right_node.max_ordering());
|
||||
self.nodes.push(Node::Internal {
|
||||
bounds: new_bounds,
|
||||
left,
|
||||
right,
|
||||
max_order: max_ordering,
|
||||
});
|
||||
self.nodes.len() - 1
|
||||
}
|
||||
}
|
||||
|
||||
impl<U, T> Default for BoundsTree<U, T>
|
||||
where
|
||||
U: Default + Clone + Debug,
|
||||
T: Clone + Debug,
|
||||
{
|
||||
fn default() -> Self {
|
||||
BoundsTree {
|
||||
root: None,
|
||||
nodes: Vec::new(),
|
||||
stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Node<U, T>
|
||||
where
|
||||
U: Clone + Default + Debug,
|
||||
T: Clone + Debug,
|
||||
{
|
||||
Leaf {
|
||||
bounds: Bounds<U>,
|
||||
order: u32,
|
||||
data: T,
|
||||
},
|
||||
Internal {
|
||||
left: usize,
|
||||
right: usize,
|
||||
bounds: Bounds<U>,
|
||||
max_order: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl<U, T> Node<U, T>
|
||||
where
|
||||
U: Clone + Default + Debug,
|
||||
T: Clone + Debug,
|
||||
{
|
||||
fn bounds(&self) -> &Bounds<U> {
|
||||
match self {
|
||||
Node::Leaf { bounds, .. } => bounds,
|
||||
Node::Internal { bounds, .. } => bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn max_ordering(&self) -> u32 {
|
||||
match self {
|
||||
Node::Leaf {
|
||||
order: ordering, ..
|
||||
} => *ordering,
|
||||
Node::Internal {
|
||||
max_order: max_ordering,
|
||||
..
|
||||
} => *max_ordering,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BoundsSearchResult<U: Clone + Default + Debug, T> {
|
||||
pub bounds: Bounds<U>,
|
||||
pub order: u32,
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{Bounds, Point, Size};
|
||||
|
||||
#[test]
|
||||
fn test_insert_and_find_containing() {
|
||||
let mut tree = BoundsTree::<f32, String>::default();
|
||||
let bounds1 = Bounds {
|
||||
origin: Point { x: 0.0, y: 0.0 },
|
||||
size: Size {
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
},
|
||||
};
|
||||
let bounds2 = Bounds {
|
||||
origin: Point { x: 5.0, y: 5.0 },
|
||||
size: Size {
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
},
|
||||
};
|
||||
let bounds3 = Bounds {
|
||||
origin: Point { x: 10.0, y: 10.0 },
|
||||
size: Size {
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
},
|
||||
};
|
||||
|
||||
// Insert bounds into the tree
|
||||
tree.insert(bounds1.clone(), "Payload 1".to_string());
|
||||
tree.insert(bounds2.clone(), "Payload 2".to_string());
|
||||
tree.insert(bounds3.clone(), "Payload 3".to_string());
|
||||
|
||||
// Points for testing
|
||||
let point_inside_bounds1 = Point { x: 1.0, y: 1.0 };
|
||||
let point_inside_bounds1_and_2 = Point { x: 6.0, y: 6.0 };
|
||||
let point_inside_bounds2_and_3 = Point { x: 12.0, y: 12.0 };
|
||||
let point_outside_all_bounds = Point { x: 21.0, y: 21.0 };
|
||||
|
||||
assert!(!bounds1.contains(&point_inside_bounds2_and_3));
|
||||
assert!(!bounds1.contains(&point_outside_all_bounds));
|
||||
assert!(bounds2.contains(&point_inside_bounds1_and_2));
|
||||
assert!(bounds2.contains(&point_inside_bounds2_and_3));
|
||||
assert!(!bounds2.contains(&point_outside_all_bounds));
|
||||
assert!(!bounds3.contains(&point_inside_bounds1));
|
||||
assert!(bounds3.contains(&point_inside_bounds2_and_3));
|
||||
assert!(!bounds3.contains(&point_outside_all_bounds));
|
||||
|
||||
// Test find_containing for different points
|
||||
let mut result = Vec::new();
|
||||
tree.find_containing(&point_inside_bounds1, &mut result);
|
||||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result[0].data, "Payload 1");
|
||||
|
||||
result.clear();
|
||||
tree.find_containing(&point_inside_bounds1_and_2, &mut result);
|
||||
assert_eq!(result.len(), 2);
|
||||
assert!(result.iter().any(|r| r.data == "Payload 1"));
|
||||
assert!(result.iter().any(|r| r.data == "Payload 2"));
|
||||
|
||||
result.clear();
|
||||
tree.find_containing(&point_inside_bounds2_and_3, &mut result);
|
||||
assert_eq!(result.len(), 2);
|
||||
assert!(result.iter().any(|r| r.data == "Payload 2"));
|
||||
assert!(result.iter().any(|r| r.data == "Payload 3"));
|
||||
|
||||
result.clear();
|
||||
tree.find_containing(&point_outside_all_bounds, &mut result);
|
||||
assert_eq!(result.len(), 0);
|
||||
}
|
||||
}
|
||||
@@ -338,6 +338,11 @@ impl Hsla {
|
||||
self.a == 0.0
|
||||
}
|
||||
|
||||
/// Returns true if the HSLA color is fully opaque, false otherwise.
|
||||
pub fn is_opaque(&self) -> bool {
|
||||
self.a == 1.0
|
||||
}
|
||||
|
||||
/// Blends `other` on top of `self` based on `other`'s alpha value. The resulting color is a combination of `self`'s and `other`'s colors.
|
||||
///
|
||||
/// If `other`'s alpha value is 1.0 or greater, `other` color is fully opaque, thus `other` is returned as the output color.
|
||||
|
||||
@@ -45,7 +45,7 @@ impl Element for Canvas {
|
||||
}
|
||||
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, style: &mut Style, cx: &mut ElementContext) {
|
||||
style.paint(bounds, cx, |cx| {
|
||||
style.paint(bounds, None, None, cx, |cx| {
|
||||
(self.paint_callback.take().unwrap())(&bounds, cx)
|
||||
});
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -152,7 +152,7 @@ impl Element for Img {
|
||||
let size = size(surface.width().into(), surface.height().into());
|
||||
let new_bounds = preserve_aspect_ratio(bounds, size);
|
||||
// TODO: Add support for corner_radii and grayscale.
|
||||
cx.paint_surface(new_bounds, surface);
|
||||
cx.paint_surface(new_bounds, surface, true);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -828,6 +828,28 @@ where
|
||||
y: self.origin.y.clone() + self.size.height.clone().half(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the half perimeter of a rectangle defined by the bounds.
|
||||
///
|
||||
/// The half perimeter is calculated as the sum of the width and the height of the rectangle.
|
||||
/// This method is generic over the type `T` which must implement the `Sub` trait to allow
|
||||
/// calculation of the width and height from the bounds' origin and size, as well as the `Add` trait
|
||||
/// to sum the width and height for the half perimeter.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use zed::{Bounds, Point, Size};
|
||||
/// let bounds = Bounds {
|
||||
/// origin: Point { x: 0, y: 0 },
|
||||
/// size: Size { width: 10, height: 20 },
|
||||
/// };
|
||||
/// let half_perimeter = bounds.half_perimeter();
|
||||
/// assert_eq!(half_perimeter, 30);
|
||||
/// ```
|
||||
pub fn half_perimeter(&self) -> T {
|
||||
self.size.width.clone() + self.size.height.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Default + Debug + PartialOrd + Add<T, Output = T> + Sub<Output = T>> Bounds<T> {
|
||||
@@ -2617,6 +2639,12 @@ pub trait Half {
|
||||
fn half(&self) -> Self;
|
||||
}
|
||||
|
||||
impl Half for i32 {
|
||||
fn half(&self) -> Self {
|
||||
self / 2
|
||||
}
|
||||
}
|
||||
|
||||
impl Half for f32 {
|
||||
fn half(&self) -> Self {
|
||||
self / 2.
|
||||
|
||||
@@ -70,6 +70,7 @@ mod app;
|
||||
|
||||
mod arena;
|
||||
mod assets;
|
||||
mod bounds_tree;
|
||||
mod color;
|
||||
mod element;
|
||||
mod elements;
|
||||
@@ -117,6 +118,7 @@ pub use anyhow::Result;
|
||||
pub use app::*;
|
||||
pub(crate) use arena::*;
|
||||
pub use assets::*;
|
||||
pub(crate) use bounds_tree::*;
|
||||
pub use color::*;
|
||||
pub use ctor::ctor;
|
||||
pub use element::*;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
345
crates/gpui/src/scene/primitives.rs
Normal file
345
crates/gpui/src/scene/primitives.rs
Normal file
@@ -0,0 +1,345 @@
|
||||
use crate::{
|
||||
point, AtlasTile, Bounds, ContentMask, Corners, Edges, EntityId, Hsla, Pixels, Point,
|
||||
ScaledPixels,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Default, Debug, Clone, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct Quad {
|
||||
pub view_id: ViewId,
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub background: Hsla,
|
||||
pub border_color: Hsla,
|
||||
pub corner_radii: Corners<ScaledPixels>,
|
||||
pub border_widths: Edges<ScaledPixels>,
|
||||
}
|
||||
|
||||
impl Ord for Quad {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Quad {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct Underline {
|
||||
pub view_id: ViewId,
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub color: Hsla,
|
||||
pub thickness: ScaledPixels,
|
||||
pub wavy: bool,
|
||||
}
|
||||
|
||||
impl Ord for Underline {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Underline {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct Shadow {
|
||||
pub view_id: ViewId,
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub corner_radii: Corners<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub color: Hsla,
|
||||
pub blur_radius: ScaledPixels,
|
||||
pub pad: u32, // align to 8 bytes
|
||||
}
|
||||
|
||||
impl Ord for Shadow {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Shadow {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MonochromeSprite {
|
||||
pub view_id: ViewId,
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub color: Hsla,
|
||||
pub tile: AtlasTile,
|
||||
}
|
||||
|
||||
impl Ord for MonochromeSprite {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
match self.order.cmp(&other.order) {
|
||||
std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
|
||||
order => order,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for MonochromeSprite {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct PolychromeSprite {
|
||||
pub view_id: ViewId,
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub corner_radii: Corners<ScaledPixels>,
|
||||
pub tile: AtlasTile,
|
||||
pub grayscale: bool,
|
||||
pub pad: u32, // align to 8 bytes
|
||||
}
|
||||
|
||||
impl Ord for PolychromeSprite {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
match self.order.cmp(&other.order) {
|
||||
std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
|
||||
order => order,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for PolychromeSprite {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub(crate) struct Surface {
|
||||
pub view_id: ViewId,
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
#[cfg(target_os = "macos")]
|
||||
pub image_buffer: media::core_video::CVImageBuffer,
|
||||
}
|
||||
|
||||
impl Ord for Surface {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Surface {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct PathId(pub(crate) usize);
|
||||
|
||||
/// A line made up of a series of vertices and control points.
|
||||
#[derive(Debug)]
|
||||
pub struct Path<P: Clone + Default + Debug> {
|
||||
pub(crate) id: PathId,
|
||||
pub(crate) view_id: ViewId,
|
||||
pub(crate) order: u32,
|
||||
pub(crate) bounds: Bounds<P>,
|
||||
pub(crate) content_mask: ContentMask<P>,
|
||||
pub(crate) vertices: Vec<PathVertex<P>>,
|
||||
pub(crate) color: Hsla,
|
||||
pub(crate) start: Point<P>,
|
||||
pub(crate) current: Point<P>,
|
||||
pub(crate) contour_count: usize,
|
||||
}
|
||||
|
||||
impl Path<Pixels> {
|
||||
/// Create a new path with the given starting point.
|
||||
pub fn new(start: Point<Pixels>) -> Self {
|
||||
Self {
|
||||
id: PathId(0),
|
||||
view_id: ViewId::default(),
|
||||
order: u32::default(),
|
||||
vertices: Vec::new(),
|
||||
start,
|
||||
current: start,
|
||||
bounds: Bounds {
|
||||
origin: start,
|
||||
size: Default::default(),
|
||||
},
|
||||
content_mask: Default::default(),
|
||||
color: Default::default(),
|
||||
contour_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Scale this path by the given factor.
|
||||
pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
|
||||
Path {
|
||||
id: self.id,
|
||||
view_id: self.view_id,
|
||||
order: self.order,
|
||||
bounds: self.bounds.scale(factor),
|
||||
content_mask: self.content_mask.scale(factor),
|
||||
vertices: self
|
||||
.vertices
|
||||
.iter()
|
||||
.map(|vertex| vertex.scale(factor))
|
||||
.collect(),
|
||||
start: self.start.map(|start| start.scale(factor)),
|
||||
current: self.current.scale(factor),
|
||||
contour_count: self.contour_count,
|
||||
color: self.color,
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a straight line from the current point to the given point.
|
||||
pub fn line_to(&mut self, to: Point<Pixels>) {
|
||||
self.contour_count += 1;
|
||||
if self.contour_count > 1 {
|
||||
self.push_triangle(
|
||||
(self.start, self.current, to),
|
||||
(point(0., 1.), point(0., 1.), point(0., 1.)),
|
||||
);
|
||||
}
|
||||
self.current = to;
|
||||
}
|
||||
|
||||
/// Draw a curve from the current point to the given point, using the given control point.
|
||||
pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
|
||||
self.contour_count += 1;
|
||||
if self.contour_count > 1 {
|
||||
self.push_triangle(
|
||||
(self.start, self.current, to),
|
||||
(point(0., 1.), point(0., 1.), point(0., 1.)),
|
||||
);
|
||||
}
|
||||
|
||||
self.push_triangle(
|
||||
(self.current, ctrl, to),
|
||||
(point(0., 0.), point(0.5, 0.), point(1., 1.)),
|
||||
);
|
||||
self.current = to;
|
||||
}
|
||||
|
||||
fn push_triangle(
|
||||
&mut self,
|
||||
xy: (Point<Pixels>, Point<Pixels>, Point<Pixels>),
|
||||
st: (Point<f32>, Point<f32>, Point<f32>),
|
||||
) {
|
||||
self.bounds = self
|
||||
.bounds
|
||||
.union(&Bounds {
|
||||
origin: xy.0,
|
||||
size: Default::default(),
|
||||
})
|
||||
.union(&Bounds {
|
||||
origin: xy.1,
|
||||
size: Default::default(),
|
||||
})
|
||||
.union(&Bounds {
|
||||
origin: xy.2,
|
||||
size: Default::default(),
|
||||
});
|
||||
|
||||
self.vertices.push(PathVertex {
|
||||
xy_position: xy.0,
|
||||
st_position: st.0,
|
||||
content_mask: Default::default(),
|
||||
});
|
||||
self.vertices.push(PathVertex {
|
||||
xy_position: xy.1,
|
||||
st_position: st.1,
|
||||
content_mask: Default::default(),
|
||||
});
|
||||
self.vertices.push(PathVertex {
|
||||
xy_position: xy.2,
|
||||
st_position: st.2,
|
||||
content_mask: Default::default(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Path<ScaledPixels> {}
|
||||
|
||||
impl PartialEq for Path<ScaledPixels> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.order == other.order
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Path<ScaledPixels> {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Path<ScaledPixels> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct PathVertex<P: Clone + Default + Debug> {
|
||||
pub(crate) xy_position: Point<P>,
|
||||
pub(crate) st_position: Point<f32>,
|
||||
pub(crate) content_mask: ContentMask<P>,
|
||||
}
|
||||
|
||||
impl PathVertex<Pixels> {
|
||||
pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> {
|
||||
PathVertex {
|
||||
xy_position: self.xy_position.scale(factor),
|
||||
st_position: self.st_position,
|
||||
content_mask: self.content_mask.scale(factor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types, unused)]
|
||||
pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct ViewId {
|
||||
low_bits: u32,
|
||||
high_bits: u32,
|
||||
}
|
||||
|
||||
impl From<EntityId> for ViewId {
|
||||
fn from(value: EntityId) -> Self {
|
||||
let value = value.as_u64();
|
||||
Self {
|
||||
low_bits: value as u32,
|
||||
high_bits: (value >> 32) as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ViewId> for EntityId {
|
||||
fn from(value: ViewId) -> Self {
|
||||
let value = (value.low_bits as u64) | ((value.high_bits as u64) << 32);
|
||||
value.into()
|
||||
}
|
||||
}
|
||||
@@ -383,10 +383,12 @@ impl Style {
|
||||
}
|
||||
}
|
||||
|
||||
/// Paints the background of an element styled with this style.
|
||||
/// Paints the background of an element styled with this style, then calls the continuation function, then paints the border.
|
||||
pub fn paint(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
hover: Option<Self>,
|
||||
group_hover: Option<(SharedString, Option<Self>)>,
|
||||
cx: &mut ElementContext,
|
||||
continuation: impl FnOnce(&mut ElementContext),
|
||||
) {
|
||||
@@ -397,7 +399,7 @@ impl Style {
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if self.debug || cx.has_global::<DebugBelow>() {
|
||||
cx.paint_quad(crate::outline(bounds, crate::red()));
|
||||
cx.paint_quad(crate::outline(bounds, crate::red()), None, None);
|
||||
}
|
||||
|
||||
let rem_size = cx.rem_size();
|
||||
@@ -410,101 +412,229 @@ impl Style {
|
||||
);
|
||||
});
|
||||
|
||||
let background_color = self.background.as_ref().and_then(Fill::color);
|
||||
if background_color.map_or(false, |color| !color.is_transparent()) {
|
||||
cx.with_z_index(1, |cx| {
|
||||
let mut border_color = background_color.unwrap_or_default();
|
||||
border_color.a = 0.;
|
||||
cx.paint_quad(quad(
|
||||
bounds,
|
||||
self.corner_radii.to_pixels(bounds.size, rem_size),
|
||||
background_color.unwrap_or_default(),
|
||||
Edges::default(),
|
||||
border_color,
|
||||
));
|
||||
});
|
||||
}
|
||||
let named_hover_group = group_hover
|
||||
.as_ref()
|
||||
.map(|(group_name, _)| group_name.clone());
|
||||
cx.with_hover_group(named_hover_group, |cx| {
|
||||
let background_color = self.background_color();
|
||||
let hover_background_color = hover
|
||||
.as_ref()
|
||||
.map(|hover_style| hover_style.background_color())
|
||||
.unwrap_or_default();
|
||||
let group_hover_background_color = group_hover
|
||||
.as_ref()
|
||||
.and_then(|(_, group_hover_style)| {
|
||||
Some(group_hover_style.as_ref()?.background_color())
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
cx.with_z_index(2, |cx| {
|
||||
continuation(cx);
|
||||
});
|
||||
if !background_color.is_transparent()
|
||||
|| !hover_background_color.is_transparent()
|
||||
|| !group_hover_background_color.is_transparent()
|
||||
{
|
||||
cx.with_z_index(1, |cx| {
|
||||
let corner_radii = self.corner_radii.to_pixels(bounds.size, rem_size);
|
||||
|
||||
if self.is_border_visible() {
|
||||
cx.with_z_index(3, |cx| {
|
||||
let corner_radii = self.corner_radii.to_pixels(bounds.size, rem_size);
|
||||
let border_widths = self.border_widths.to_pixels(rem_size);
|
||||
let max_border_width = border_widths.max();
|
||||
let max_corner_radius = corner_radii.max();
|
||||
let mut border_color = background_color;
|
||||
border_color.a = 0.;
|
||||
let base_quad = quad(
|
||||
bounds,
|
||||
corner_radii,
|
||||
background_color,
|
||||
Edges::default(),
|
||||
border_color,
|
||||
);
|
||||
|
||||
let top_bounds = Bounds::from_corners(
|
||||
bounds.origin,
|
||||
bounds.upper_right()
|
||||
+ point(Pixels::ZERO, max_border_width.max(max_corner_radius)),
|
||||
);
|
||||
let bottom_bounds = Bounds::from_corners(
|
||||
bounds.lower_left()
|
||||
- point(Pixels::ZERO, max_border_width.max(max_corner_radius)),
|
||||
bounds.lower_right(),
|
||||
);
|
||||
let left_bounds = Bounds::from_corners(
|
||||
top_bounds.lower_left(),
|
||||
bottom_bounds.origin + point(max_border_width, Pixels::ZERO),
|
||||
);
|
||||
let right_bounds = Bounds::from_corners(
|
||||
top_bounds.lower_right() - point(max_border_width, Pixels::ZERO),
|
||||
bottom_bounds.upper_right(),
|
||||
);
|
||||
let hover_quad = if hover_background_color.is_transparent() {
|
||||
None
|
||||
} else {
|
||||
let mut border_color = hover_background_color;
|
||||
border_color.a = 0.;
|
||||
Some(quad(
|
||||
bounds,
|
||||
corner_radii,
|
||||
hover_background_color,
|
||||
Edges::default(),
|
||||
border_color,
|
||||
))
|
||||
};
|
||||
|
||||
let mut background = self.border_color.unwrap_or_default();
|
||||
background.a = 0.;
|
||||
let quad = quad(
|
||||
bounds,
|
||||
corner_radii,
|
||||
background,
|
||||
border_widths,
|
||||
self.border_color.unwrap_or_default(),
|
||||
);
|
||||
let group_hover_quad = group_hover.as_ref().map(|(group_id, _)| {
|
||||
let quad = if group_hover_background_color.is_transparent() {
|
||||
None
|
||||
} else {
|
||||
let mut border_color = group_hover_background_color;
|
||||
border_color.a = 0.;
|
||||
Some(quad(
|
||||
bounds,
|
||||
corner_radii,
|
||||
group_hover_background_color,
|
||||
Edges::default(),
|
||||
border_color,
|
||||
))
|
||||
};
|
||||
(group_id.clone(), quad)
|
||||
});
|
||||
|
||||
cx.with_content_mask(Some(ContentMask { bounds: top_bounds }), |cx| {
|
||||
cx.paint_quad(quad.clone());
|
||||
cx.paint_quad(base_quad, hover_quad, group_hover_quad);
|
||||
});
|
||||
cx.with_content_mask(
|
||||
Some(ContentMask {
|
||||
bounds: right_bounds,
|
||||
}),
|
||||
|cx| {
|
||||
cx.paint_quad(quad.clone());
|
||||
},
|
||||
);
|
||||
cx.with_content_mask(
|
||||
Some(ContentMask {
|
||||
bounds: bottom_bounds,
|
||||
}),
|
||||
|cx| {
|
||||
cx.paint_quad(quad.clone());
|
||||
},
|
||||
);
|
||||
cx.with_content_mask(
|
||||
Some(ContentMask {
|
||||
bounds: left_bounds,
|
||||
}),
|
||||
|cx| {
|
||||
cx.paint_quad(quad);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if self.debug_below {
|
||||
cx.remove_global::<DebugBelow>();
|
||||
cx.with_z_index(2, |cx| {
|
||||
continuation(cx);
|
||||
});
|
||||
|
||||
let border_color = self.border_color();
|
||||
let hover_border_color = hover
|
||||
.as_ref()
|
||||
.map(|hover_style| hover_style.border_color())
|
||||
.unwrap_or_default();
|
||||
let group_hover_border_color = group_hover
|
||||
.as_ref()
|
||||
.and_then(|(_, group_hover_style)| Some(group_hover_style.as_ref()?.border_color()))
|
||||
.unwrap_or_default();
|
||||
if self.border_widths.any(|width| !width.is_zero())
|
||||
&& (!border_color.is_transparent()
|
||||
|| !hover_border_color.is_transparent()
|
||||
|| !group_hover_border_color.is_transparent())
|
||||
{
|
||||
cx.with_z_index(3, |cx| {
|
||||
let corner_radii = self.corner_radii.to_pixels(bounds.size, rem_size);
|
||||
let border_widths = self.border_widths.to_pixels(rem_size);
|
||||
let max_border_width = border_widths.max();
|
||||
let max_corner_radius = corner_radii.max();
|
||||
|
||||
let top_bounds = Bounds::from_corners(
|
||||
bounds.origin,
|
||||
bounds.upper_right()
|
||||
+ point(Pixels::ZERO, max_border_width.max(max_corner_radius)),
|
||||
);
|
||||
let bottom_bounds = Bounds::from_corners(
|
||||
bounds.lower_left()
|
||||
- point(Pixels::ZERO, max_border_width.max(max_corner_radius)),
|
||||
bounds.lower_right(),
|
||||
);
|
||||
let left_bounds = Bounds::from_corners(
|
||||
top_bounds.lower_left(),
|
||||
bottom_bounds.origin + point(max_border_width, Pixels::ZERO),
|
||||
);
|
||||
let right_bounds = Bounds::from_corners(
|
||||
top_bounds.lower_right() - point(max_border_width, Pixels::ZERO),
|
||||
bottom_bounds.upper_right(),
|
||||
);
|
||||
|
||||
let mut background = border_color;
|
||||
background.a = 0.;
|
||||
let border_quad = quad(
|
||||
bounds,
|
||||
corner_radii,
|
||||
background,
|
||||
border_widths,
|
||||
border_color,
|
||||
);
|
||||
let hover_border_quad = if hover_border_color.is_transparent() {
|
||||
None
|
||||
} else {
|
||||
let mut background = hover_border_color;
|
||||
background.a = 0.;
|
||||
Some(quad(
|
||||
bounds,
|
||||
corner_radii,
|
||||
background,
|
||||
border_widths,
|
||||
hover_border_color,
|
||||
))
|
||||
};
|
||||
let group_hover_border_quad = group_hover.as_ref().map(|(group_id, _)| {
|
||||
let quad = if group_hover_border_color.is_transparent() {
|
||||
None
|
||||
} else {
|
||||
let mut background = group_hover_border_color;
|
||||
background.a = 0.;
|
||||
Some(quad(
|
||||
bounds,
|
||||
corner_radii,
|
||||
background,
|
||||
border_widths,
|
||||
group_hover_border_color,
|
||||
))
|
||||
};
|
||||
(group_id.clone(), quad)
|
||||
});
|
||||
|
||||
cx.with_content_mask(Some(ContentMask { bounds: top_bounds }), |cx| {
|
||||
cx.paint_quad(
|
||||
border_quad.clone(),
|
||||
hover_border_quad.clone(),
|
||||
group_hover_border_quad.clone(),
|
||||
);
|
||||
});
|
||||
cx.with_content_mask(
|
||||
Some(ContentMask {
|
||||
bounds: right_bounds,
|
||||
}),
|
||||
|cx| {
|
||||
cx.paint_quad(
|
||||
border_quad.clone(),
|
||||
hover_border_quad.clone(),
|
||||
group_hover_border_quad.clone(),
|
||||
);
|
||||
},
|
||||
);
|
||||
cx.with_content_mask(
|
||||
Some(ContentMask {
|
||||
bounds: bottom_bounds,
|
||||
}),
|
||||
|cx| {
|
||||
cx.paint_quad(
|
||||
border_quad.clone(),
|
||||
hover_border_quad.clone(),
|
||||
group_hover_border_quad.clone(),
|
||||
);
|
||||
},
|
||||
);
|
||||
cx.with_content_mask(
|
||||
Some(ContentMask {
|
||||
bounds: left_bounds,
|
||||
}),
|
||||
|cx| {
|
||||
cx.paint_quad(border_quad, hover_border_quad, group_hover_border_quad);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if self.debug_below {
|
||||
cx.remove_global::<DebugBelow>();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the background color of the style based on the visibility.
|
||||
/// If the visibility is `Visible`, it returns the background color of the style if set,
|
||||
/// otherwise it returns the default color. If the visibility is `Hidden`, it returns
|
||||
/// a transparent black color.
|
||||
fn background_color(&self) -> Hsla {
|
||||
match self.visibility {
|
||||
Visibility::Visible => self
|
||||
.background
|
||||
.as_ref()
|
||||
.and_then(Fill::color)
|
||||
.unwrap_or_default(),
|
||||
Visibility::Hidden => Hsla::transparent_black(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_border_visible(&self) -> bool {
|
||||
self.border_color
|
||||
.map_or(false, |color| !color.is_transparent())
|
||||
&& self.border_widths.any(|length| !length.is_zero())
|
||||
/// Returns the border color of the style based on the visibility.
|
||||
/// If the visibility is `Visible`, it returns the border color of the style if set,
|
||||
/// otherwise it returns the default color. If the visibility is `Hidden`, it returns
|
||||
/// a transparent black color.
|
||||
fn border_color(&self) -> Hsla {
|
||||
match self.visibility {
|
||||
Visibility::Visible => self.border_color.unwrap_or_default(),
|
||||
Visibility::Hidden => Hsla::transparent_black(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,13 +130,17 @@ fn paint_line(
|
||||
if wraps.peek() == Some(&&WrapBoundary { run_ix, glyph_ix }) {
|
||||
wraps.next();
|
||||
if let Some((background_origin, background_color)) = current_background.as_mut() {
|
||||
cx.paint_quad(fill(
|
||||
Bounds {
|
||||
origin: *background_origin,
|
||||
size: size(glyph_origin.x - background_origin.x, line_height),
|
||||
},
|
||||
*background_color,
|
||||
));
|
||||
cx.paint_quad(
|
||||
fill(
|
||||
Bounds {
|
||||
origin: *background_origin,
|
||||
size: size(glyph_origin.x - background_origin.x, line_height),
|
||||
},
|
||||
*background_color,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
background_origin.x = origin.x;
|
||||
background_origin.y += line_height;
|
||||
}
|
||||
@@ -229,13 +233,17 @@ fn paint_line(
|
||||
}
|
||||
|
||||
if let Some((background_origin, background_color)) = finished_background {
|
||||
cx.paint_quad(fill(
|
||||
Bounds {
|
||||
origin: background_origin,
|
||||
size: size(glyph_origin.x - background_origin.x, line_height),
|
||||
},
|
||||
background_color,
|
||||
));
|
||||
cx.paint_quad(
|
||||
fill(
|
||||
Bounds {
|
||||
origin: background_origin,
|
||||
size: size(glyph_origin.x - background_origin.x, line_height),
|
||||
},
|
||||
background_color,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some((underline_origin, underline_style)) = finished_underline {
|
||||
@@ -289,13 +297,17 @@ fn paint_line(
|
||||
}
|
||||
|
||||
if let Some((background_origin, background_color)) = current_background.take() {
|
||||
cx.paint_quad(fill(
|
||||
Bounds {
|
||||
origin: background_origin,
|
||||
size: size(last_line_end_x - background_origin.x, line_height),
|
||||
},
|
||||
background_color,
|
||||
));
|
||||
cx.paint_quad(
|
||||
fill(
|
||||
Bounds {
|
||||
origin: background_origin,
|
||||
size: size(last_line_end_x - background_origin.x, line_height),
|
||||
},
|
||||
background_color,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some((underline_start, underline_style)) = current_underline.take() {
|
||||
|
||||
@@ -212,7 +212,8 @@ impl AnyView {
|
||||
/// When using this method, the view's previous layout and paint will be recycled from the previous frame if [ViewContext::notify] has not been called since it was rendered.
|
||||
/// The one exception is when [WindowContext::refresh] is called, in which case caching is ignored.
|
||||
pub fn cached(mut self) -> Self {
|
||||
self.cache = true;
|
||||
// TODO!: ENABLE ME!
|
||||
// self.cache = true;
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ use crate::{
|
||||
Global, GlobalElementId, Hsla, KeyBinding, KeyContext, KeyDownEvent, KeyMatch, KeymatchResult,
|
||||
Keystroke, KeystrokeEvent, Model, ModelContext, Modifiers, MouseButton, MouseMoveEvent,
|
||||
MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformWindow, Point,
|
||||
PromptLevel, Render, ScaledPixels, SharedString, Size, SubscriberSet, Subscription,
|
||||
TaffyLayoutEngine, Task, View, VisualContext, WeakView, WindowAppearance, WindowBounds,
|
||||
PromptLevel, Quad, Render, ScaledPixels, SharedString, Size, SubscriberSet, Subscription,
|
||||
TaffyLayoutEngine, Task, View, ViewId, VisualContext, WeakView, WindowAppearance, WindowBounds,
|
||||
WindowOptions, WindowTextSystem,
|
||||
};
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
@@ -1043,9 +1043,10 @@ impl<'a> WindowContext<'a> {
|
||||
self.window.layout_engine.as_mut().unwrap().clear();
|
||||
self.text_system()
|
||||
.finish_frame(&self.window.next_frame.reused_views);
|
||||
let mouse_position = self.window.mouse_position.scale(self.window.scale_factor);
|
||||
self.window
|
||||
.next_frame
|
||||
.finish(&mut self.window.rendered_frame);
|
||||
.finish(&mut self.window.rendered_frame, mouse_position);
|
||||
ELEMENT_ARENA.with_borrow_mut(|element_arena| {
|
||||
let percentage = (element_arena.len() as f32 / element_arena.capacity() as f32) * 100.;
|
||||
if percentage >= 80. {
|
||||
@@ -2797,6 +2798,24 @@ impl PaintQuad {
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_primitive(
|
||||
self,
|
||||
view_id: impl Into<ViewId>,
|
||||
scale_factor: f32,
|
||||
content_mask: ContentMask<Pixels>,
|
||||
) -> Quad {
|
||||
Quad {
|
||||
view_id: view_id.into(),
|
||||
order: 0,
|
||||
bounds: self.bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
background: self.background,
|
||||
border_color: self.border_color,
|
||||
corner_radii: self.corner_radii.scale(scale_factor),
|
||||
border_widths: self.border_widths.scale(scale_factor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a quad with the given parameters.
|
||||
|
||||
@@ -34,9 +34,9 @@ use crate::{
|
||||
EntityId, FocusHandle, FocusId, FontId, GlobalElementId, GlyphId, Hsla, ImageData,
|
||||
InputHandler, IsZero, KeyContext, KeyEvent, LayoutId, MonochromeSprite, MouseEvent, PaintQuad,
|
||||
Path, Pixels, PlatformInputHandler, Point, PolychromeSprite, Quad, RenderGlyphParams,
|
||||
RenderImageParams, RenderSvgParams, Scene, Shadow, SharedString, Size, StackingContext,
|
||||
StackingOrder, StrikethroughStyle, Style, TextStyleRefinement, Underline, UnderlineStyle,
|
||||
Window, WindowContext, SUBPIXEL_VARIANTS,
|
||||
RenderImageParams, RenderSvgParams, ScaledPixels, Scene, Shadow, SharedString, Size,
|
||||
StackingContext, StackingOrder, StrikethroughStyle, Style, TextStyleRefinement, Underline,
|
||||
UnderlineStyle, Window, WindowContext, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
|
||||
type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut ElementContext) + 'static>;
|
||||
@@ -124,7 +124,7 @@ impl Frame {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
|
||||
pub(crate) fn finish(&mut self, prev_frame: &mut Self, mouse_position: Point<ScaledPixels>) {
|
||||
// Reuse mouse listeners that didn't change since the last frame.
|
||||
for (type_id, listeners) in &mut prev_frame.mouse_listeners {
|
||||
let next_listeners = self.mouse_listeners.entry(*type_id).or_default();
|
||||
@@ -157,7 +157,7 @@ impl Frame {
|
||||
// Reuse geometry that didn't change since the last frame.
|
||||
self.scene
|
||||
.reuse_views(&self.reused_views, &mut prev_frame.scene);
|
||||
self.scene.finish();
|
||||
self.scene.finish(mouse_position);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,6 +651,7 @@ impl<'a> ElementContext<'a> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Paint one or more drop shadows into the scene for the next frame at the current z-index.
|
||||
pub fn paint_shadows(
|
||||
&mut self,
|
||||
@@ -666,11 +667,9 @@ impl<'a> ElementContext<'a> {
|
||||
let mut shadow_bounds = bounds;
|
||||
shadow_bounds.origin += shadow.offset;
|
||||
shadow_bounds.dilate(shadow.spread_radius);
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
window.next_frame.scene.insert_shadow(
|
||||
Shadow {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds: shadow_bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
@@ -679,6 +678,8 @@ impl<'a> ElementContext<'a> {
|
||||
blur_radius: shadow.blur_radius.scale(scale_factor),
|
||||
pad: 0,
|
||||
},
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -686,17 +687,20 @@ impl<'a> ElementContext<'a> {
|
||||
/// Paint one or more quads into the scene for the next frame at the current stacking context.
|
||||
/// Quads are colored rectangular regions with an optional background, border, and corner radius.
|
||||
/// see [`fill`](crate::fill), [`outline`](crate::outline), and [`quad`](crate::quad) to construct this type.
|
||||
pub fn paint_quad(&mut self, quad: PaintQuad) {
|
||||
pub fn paint_quad(
|
||||
&mut self,
|
||||
quad: PaintQuad,
|
||||
hover: Option<PaintQuad>,
|
||||
group_hover: Option<(SharedString, Option<PaintQuad>)>,
|
||||
) {
|
||||
let scale_factor = self.scale_factor();
|
||||
let content_mask = self.content_mask();
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
window.next_frame.scene.insert_quad(
|
||||
Quad {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds: quad.bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
@@ -705,6 +709,13 @@ impl<'a> ElementContext<'a> {
|
||||
corner_radii: quad.corner_radii.scale(scale_factor),
|
||||
border_widths: quad.border_widths.scale(scale_factor),
|
||||
},
|
||||
hover.map(|quad| quad.into_primitive(view_id, scale_factor, content_mask.clone())),
|
||||
group_hover.map(|(group_id, quad)| {
|
||||
(
|
||||
group_id,
|
||||
quad.map(|quad| quad.into_primitive(view_id, scale_factor, content_mask)),
|
||||
)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -721,7 +732,7 @@ impl<'a> ElementContext<'a> {
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.insert(&window.next_frame.z_index_stack, path.scale(scale_factor));
|
||||
.insert_path(path.scale(scale_factor), None, None);
|
||||
}
|
||||
|
||||
/// Paint an underline into the scene for the next frame at the current z-index.
|
||||
@@ -745,11 +756,9 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
window.next_frame.scene.insert_underline(
|
||||
Underline {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds: bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
@@ -757,6 +766,8 @@ impl<'a> ElementContext<'a> {
|
||||
thickness: style.thickness.scale(scale_factor),
|
||||
wavy: style.wavy,
|
||||
},
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -777,11 +788,9 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
window.next_frame.scene.insert_underline(
|
||||
Underline {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds: bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
@@ -789,6 +798,8 @@ impl<'a> ElementContext<'a> {
|
||||
color: style.color.unwrap_or_default(),
|
||||
wavy: false,
|
||||
},
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -837,17 +848,17 @@ impl<'a> ElementContext<'a> {
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
let view_id = self.parent_view_id();
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
window.next_frame.scene.insert_monochrome_sprite(
|
||||
MonochromeSprite {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds,
|
||||
content_mask,
|
||||
color,
|
||||
tile,
|
||||
},
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
@@ -895,11 +906,9 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
let window = &mut *self.window;
|
||||
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
window.next_frame.scene.insert_polychrome_sprite(
|
||||
PolychromeSprite {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds,
|
||||
corner_radii: Default::default(),
|
||||
@@ -908,6 +917,8 @@ impl<'a> ElementContext<'a> {
|
||||
grayscale: false,
|
||||
pad: 0,
|
||||
},
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
@@ -941,17 +952,17 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
window.next_frame.scene.insert_monochrome_sprite(
|
||||
MonochromeSprite {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds,
|
||||
content_mask,
|
||||
color,
|
||||
tile,
|
||||
},
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -980,11 +991,9 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
window.next_frame.scene.insert_polychrome_sprite(
|
||||
PolychromeSprite {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds,
|
||||
content_mask,
|
||||
@@ -993,28 +1002,34 @@ impl<'a> ElementContext<'a> {
|
||||
grayscale,
|
||||
pad: 0,
|
||||
},
|
||||
None,
|
||||
None,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Paint a surface into the scene for the next frame at the current z-index.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVImageBuffer) {
|
||||
pub fn paint_surface(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
image_buffer: CVImageBuffer,
|
||||
occludes_hover: bool,
|
||||
) {
|
||||
let scale_factor = self.scale_factor();
|
||||
let bounds = bounds.scale(scale_factor);
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
let view_id = self.parent_view_id();
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
window.next_frame.scene.insert_surface(
|
||||
crate::Surface {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds,
|
||||
content_mask,
|
||||
image_buffer,
|
||||
},
|
||||
occludes_hover,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1161,6 +1176,22 @@ impl<'a> ElementContext<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Invoke the given function with the given hover group id present on the hover stack.
|
||||
/// This is a fairly low-level method used to paint hover effects for views that share
|
||||
/// the same hover group.
|
||||
pub fn with_hover_group<R>(
|
||||
&mut self,
|
||||
name: Option<SharedString>,
|
||||
f: impl FnOnce(&mut Self) -> R,
|
||||
) -> R {
|
||||
let window = &mut self.window;
|
||||
let group = window.next_frame.scene.hover_group(name);
|
||||
window.hover_group_stack.push(group);
|
||||
let result = f(self);
|
||||
window.hover_group_stack.pop();
|
||||
result
|
||||
}
|
||||
|
||||
/// Sets an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the
|
||||
/// platform to receive textual input with proper integration with concerns such
|
||||
/// as IME interactions. This handler will be active for the upcoming frame until the following frame is
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
[package]
|
||||
name = "languages"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
license = "GPL-3.0-or-later"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
gpui.workspace = true
|
||||
language.workspace = true
|
||||
node_runtime.workspace = true
|
||||
rust-embed = "8.2.0"
|
||||
settings.workspace = true
|
||||
|
||||
tree-sitter-astro.workspace = true
|
||||
tree-sitter-bash.workspace = true
|
||||
tree-sitter-c-sharp.workspace = true
|
||||
tree-sitter-c.workspace = true
|
||||
tree-sitter-clojure.workspace = true
|
||||
tree-sitter-cpp.workspace = true
|
||||
tree-sitter-css.workspace = true
|
||||
tree-sitter-dockerfile.workspace = true
|
||||
tree-sitter-dart.workspace = true
|
||||
tree-sitter-elixir.workspace = true
|
||||
tree-sitter-elm.workspace = true
|
||||
tree-sitter-embedded-template.workspace = true
|
||||
tree-sitter-erlang.workspace = true
|
||||
tree-sitter-gitcommit.workspace = true
|
||||
tree-sitter-gleam.workspace = true
|
||||
tree-sitter-glsl.workspace = true
|
||||
tree-sitter-go.workspace = true
|
||||
tree-sitter-gomod.workspace = true
|
||||
tree-sitter-gowork.workspace = true
|
||||
tree-sitter-haskell.workspace = true
|
||||
tree-sitter-hcl.workspace = true
|
||||
tree-sitter-heex.workspace = true
|
||||
tree-sitter-html.workspace = true
|
||||
tree-sitter-json.workspace = true
|
||||
tree-sitter-lua.workspace = true
|
||||
tree-sitter-markdown.workspace = true
|
||||
tree-sitter-nix.workspace = true
|
||||
tree-sitter-nu.workspace = true
|
||||
tree-sitter-ocaml.workspace = true
|
||||
tree-sitter-php.workspace = true
|
||||
tree-sitter-prisma-io.workspace = true
|
||||
tree-sitter-proto.workspace = true
|
||||
tree-sitter-purescript.workspace = true
|
||||
tree-sitter-python.workspace = true
|
||||
tree-sitter-racket.workspace = true
|
||||
tree-sitter-ruby.workspace = true
|
||||
tree-sitter-rust.workspace = true
|
||||
tree-sitter-scheme.workspace = true
|
||||
tree-sitter-svelte.workspace = true
|
||||
tree-sitter-toml.workspace = true
|
||||
tree-sitter-typescript.workspace = true
|
||||
tree-sitter-uiua.workspace = true
|
||||
tree-sitter-vue.workspace = true
|
||||
tree-sitter-yaml.workspace = true
|
||||
tree-sitter-zig.workspace = true
|
||||
tree-sitter.workspace = true
|
||||
util.workspace = true
|
||||
lsp.workspace = true
|
||||
async-trait = "0.1.77"
|
||||
shellexpand = "3.1.0"
|
||||
serde_json.workspace = true
|
||||
serde_derive.workspace = true
|
||||
futures.workspace = true
|
||||
smol.workspace = true
|
||||
toml.workspace = true
|
||||
lazy_static.workspace = true
|
||||
schemars.workspace = true
|
||||
log.workspace = true
|
||||
task.workspace = true
|
||||
parking_lot.workspace = true
|
||||
async-compression = "0.4.6"
|
||||
collections.workspace = true
|
||||
async-tar = "0.4.2"
|
||||
regex.workspace = true
|
||||
feature_flags.workspace = true
|
||||
project.workspace = true
|
||||
serde.workspace = true
|
||||
rope.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
text.workspace = true
|
||||
theme.workspace = true
|
||||
unindent.workspace = true
|
||||
@@ -1 +0,0 @@
|
||||
../../LICENSE-GPL
|
||||
@@ -66,7 +66,6 @@ thiserror.workspace = true
|
||||
toml.workspace = true
|
||||
util.workspace = true
|
||||
which.workspace = true
|
||||
project_core.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
client = { workspace = true, features = ["test-support"] }
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
pub mod debounced_delay;
|
||||
mod ignore;
|
||||
pub mod lsp_command;
|
||||
pub mod lsp_ext_command;
|
||||
mod prettier_support;
|
||||
pub mod project_settings;
|
||||
pub mod search;
|
||||
mod task_inventory;
|
||||
pub mod terminals;
|
||||
pub mod worktree;
|
||||
|
||||
pub use project_core::*;
|
||||
#[cfg(test)]
|
||||
mod project_tests;
|
||||
#[cfg(test)]
|
||||
@@ -55,7 +57,7 @@ use node_runtime::NodeRuntime;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use postage::watch;
|
||||
use prettier_support::{DefaultPrettier, PrettierInstance};
|
||||
use project_core::project_settings::{LspSettings, ProjectSettings};
|
||||
use project_settings::{LspSettings, ProjectSettings};
|
||||
use rand::prelude::*;
|
||||
|
||||
use rpc::{ErrorCode, ErrorExt as _};
|
||||
@@ -95,6 +97,7 @@ pub use fs::*;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
|
||||
pub use task_inventory::Inventory;
|
||||
pub use worktree::*;
|
||||
|
||||
const MAX_SERVER_REINSTALL_ATTEMPT_COUNT: u64 = 4;
|
||||
const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
@@ -313,6 +316,11 @@ pub struct ProjectPath {
|
||||
pub path: Arc<Path>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
|
||||
pub struct DiagnosticSummary {
|
||||
pub error_count: usize,
|
||||
pub warning_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Location {
|
||||
@@ -431,8 +439,66 @@ impl Hover {
|
||||
#[derive(Default)]
|
||||
pub struct ProjectTransaction(pub HashMap<Model<Buffer>, language::Transaction>);
|
||||
|
||||
impl DiagnosticSummary {
|
||||
fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
|
||||
let mut this = Self {
|
||||
error_count: 0,
|
||||
warning_count: 0,
|
||||
};
|
||||
|
||||
for entry in diagnostics {
|
||||
if entry.diagnostic.is_primary {
|
||||
match entry.diagnostic.severity {
|
||||
DiagnosticSeverity::ERROR => this.error_count += 1,
|
||||
DiagnosticSeverity::WARNING => this.warning_count += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.error_count == 0 && self.warning_count == 0
|
||||
}
|
||||
|
||||
pub fn to_proto(
|
||||
&self,
|
||||
language_server_id: LanguageServerId,
|
||||
path: &Path,
|
||||
) -> proto::DiagnosticSummary {
|
||||
proto::DiagnosticSummary {
|
||||
path: path.to_string_lossy().to_string(),
|
||||
language_server_id: language_server_id.0 as u64,
|
||||
error_count: self.error_count as u32,
|
||||
warning_count: self.warning_count as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ProjectEntryId(usize);
|
||||
|
||||
impl ProjectEntryId {
|
||||
pub const MAX: Self = Self(usize::MAX);
|
||||
|
||||
pub fn new(counter: &AtomicUsize) -> Self {
|
||||
Self(counter.fetch_add(1, SeqCst))
|
||||
}
|
||||
|
||||
pub fn from_proto(id: u64) -> Self {
|
||||
Self(id as usize)
|
||||
}
|
||||
|
||||
pub fn to_proto(&self) -> u64 {
|
||||
self.0 as u64
|
||||
}
|
||||
|
||||
pub fn to_usize(&self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum FormatTrigger {
|
||||
@@ -6722,7 +6788,7 @@ impl Project {
|
||||
cx.observe(worktree, |_, _, cx| cx.notify()).detach();
|
||||
if worktree.read(cx).is_local() {
|
||||
cx.subscribe(worktree, |this, worktree, event, cx| match event {
|
||||
project_core::worktree::Event::UpdatedEntries(changes) => {
|
||||
worktree::Event::UpdatedEntries(changes) => {
|
||||
this.update_local_worktree_buffers(&worktree, changes, cx);
|
||||
this.update_local_worktree_language_servers(&worktree, changes, cx);
|
||||
this.update_local_worktree_settings(&worktree, changes, cx);
|
||||
@@ -6732,7 +6798,7 @@ impl Project {
|
||||
changes.clone(),
|
||||
));
|
||||
}
|
||||
project_core::worktree::Event::UpdatedGitRepositories(updated_repos) => {
|
||||
worktree::Event::UpdatedGitRepositories(updated_repos) => {
|
||||
this.update_local_worktree_buffers_git_repos(worktree, updated_repos, cx)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -251,7 +251,7 @@ struct BackgroundScannerState {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LocalRepositoryEntry {
|
||||
pub(crate) git_dir_scan_id: usize,
|
||||
pub repo_ptr: Arc<Mutex<dyn GitRepository>>,
|
||||
pub(crate) repo_ptr: Arc<Mutex<dyn GitRepository>>,
|
||||
/// Path to the actual .git folder.
|
||||
/// Note: if .git is a file, this points to the folder indicated by the .git file
|
||||
pub(crate) git_dir_path: Arc<Path>,
|
||||
@@ -718,7 +718,7 @@ impl LocalWorktree {
|
||||
path.starts_with(&self.abs_path)
|
||||
}
|
||||
|
||||
pub fn load_buffer(
|
||||
pub(crate) fn load_buffer(
|
||||
&mut self,
|
||||
id: BufferId,
|
||||
path: &Path,
|
||||
@@ -1593,7 +1593,7 @@ impl RemoteWorktree {
|
||||
self.completed_scan_id >= scan_id
|
||||
}
|
||||
|
||||
pub fn wait_for_snapshot(&mut self, scan_id: usize) -> impl Future<Output = Result<()>> {
|
||||
pub(crate) fn wait_for_snapshot(&mut self, scan_id: usize) -> impl Future<Output = Result<()>> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
if self.observed_snapshot(scan_id) {
|
||||
let _ = tx.send(());
|
||||
@@ -1659,7 +1659,7 @@ impl RemoteWorktree {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn delete_entry(
|
||||
pub(crate) fn delete_entry(
|
||||
&mut self,
|
||||
id: ProjectEntryId,
|
||||
scan_id: usize,
|
||||
@@ -2093,7 +2093,7 @@ impl Snapshot {
|
||||
}
|
||||
|
||||
impl LocalSnapshot {
|
||||
pub fn get_local_repo(&self, repo: &RepositoryEntry) -> Option<&LocalRepositoryEntry> {
|
||||
pub(crate) fn get_local_repo(&self, repo: &RepositoryEntry) -> Option<&LocalRepositoryEntry> {
|
||||
self.git_repositories.get(&repo.work_directory.0)
|
||||
}
|
||||
|
||||
@@ -2744,7 +2744,7 @@ impl WorktreeId {
|
||||
Self(handle_id)
|
||||
}
|
||||
|
||||
pub fn from_proto(id: u64) -> Self {
|
||||
pub(crate) fn from_proto(id: u64) -> Self {
|
||||
Self(id as usize)
|
||||
}
|
||||
|
||||
@@ -2829,10 +2829,10 @@ pub struct File {
|
||||
pub worktree: Model<Worktree>,
|
||||
pub path: Arc<Path>,
|
||||
pub mtime: SystemTime,
|
||||
pub entry_id: Option<ProjectEntryId>,
|
||||
pub is_local: bool,
|
||||
pub is_deleted: bool,
|
||||
pub is_private: bool,
|
||||
pub(crate) entry_id: Option<ProjectEntryId>,
|
||||
pub(crate) is_local: bool,
|
||||
pub(crate) is_deleted: bool,
|
||||
pub(crate) is_private: bool,
|
||||
}
|
||||
|
||||
impl language::File for File {
|
||||
@@ -1,35 +0,0 @@
|
||||
[package]
|
||||
name = "project_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
client.workspace = true
|
||||
clock.workspace = true
|
||||
collections.workspace = true
|
||||
fs.workspace = true
|
||||
futures.workspace = true
|
||||
fuzzy.workspace = true
|
||||
git.workspace = true
|
||||
gpui.workspace = true
|
||||
ignore = "0.4.22"
|
||||
itertools = "0.12.1"
|
||||
language.workspace = true
|
||||
log.workspace = true
|
||||
lsp.workspace = true
|
||||
parking_lot.workspace = true
|
||||
postage.workspace = true
|
||||
rpc.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
schemars.workspace = true
|
||||
smol.workspace = true
|
||||
sum_tree.workspace = true
|
||||
text.workspace = true
|
||||
util.workspace = true
|
||||
@@ -1,80 +0,0 @@
|
||||
pub mod worktree;
|
||||
pub use worktree::*;
|
||||
mod ignore;
|
||||
pub mod project_settings;
|
||||
use serde::Serialize;
|
||||
use fs::{copy_recursive, RemoveOptions};
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use rpc::proto;
|
||||
use std::path::Path;
|
||||
use lsp::LanguageServerId;
|
||||
use lsp::DiagnosticSeverity;
|
||||
use language::DiagnosticEntry;
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
|
||||
pub struct DiagnosticSummary {
|
||||
pub error_count: usize,
|
||||
pub warning_count: usize,
|
||||
}
|
||||
|
||||
impl DiagnosticSummary {
|
||||
fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
|
||||
let mut this = Self {
|
||||
error_count: 0,
|
||||
warning_count: 0,
|
||||
};
|
||||
|
||||
for entry in diagnostics {
|
||||
if entry.diagnostic.is_primary {
|
||||
match entry.diagnostic.severity {
|
||||
DiagnosticSeverity::ERROR => this.error_count += 1,
|
||||
DiagnosticSeverity::WARNING => this.warning_count += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.error_count == 0 && self.warning_count == 0
|
||||
}
|
||||
|
||||
pub fn to_proto(
|
||||
&self,
|
||||
language_server_id: LanguageServerId,
|
||||
path: &Path,
|
||||
) -> proto::DiagnosticSummary {
|
||||
proto::DiagnosticSummary {
|
||||
path: path.to_string_lossy().to_string(),
|
||||
language_server_id: language_server_id.0 as u64,
|
||||
error_count: self.error_count as u32,
|
||||
warning_count: self.warning_count as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ProjectEntryId(usize);
|
||||
|
||||
|
||||
impl ProjectEntryId {
|
||||
pub const MAX: Self = Self(usize::MAX);
|
||||
|
||||
pub fn new(counter: &AtomicUsize) -> Self {
|
||||
Self(counter.fetch_add(1, SeqCst))
|
||||
}
|
||||
|
||||
pub fn from_proto(id: u64) -> Self {
|
||||
Self(id as usize)
|
||||
}
|
||||
|
||||
pub fn to_proto(&self) -> u64 {
|
||||
self.0 as u64
|
||||
}
|
||||
|
||||
pub fn to_usize(&self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ path = "src/recent_projects.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
editor.workspace = true
|
||||
futures.workspace = true
|
||||
fuzzy.workspace = true
|
||||
gpui.workspace = true
|
||||
@@ -25,3 +26,6 @@ theme.workspace = true
|
||||
ui.workspace = true
|
||||
util.workspace = true
|
||||
workspace.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
editor = { workspace = true, features = ["test-support"] }
|
||||
|
||||
@@ -8,6 +8,7 @@ license = "GPL-3.0-or-later"
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
db.workspace = true
|
||||
editor.workspace = true
|
||||
fs.workspace = true
|
||||
futures.workspace = true
|
||||
fuzzy.workspace = true
|
||||
|
||||
@@ -133,7 +133,7 @@ impl LayoutRect {
|
||||
)
|
||||
.into();
|
||||
|
||||
cx.paint_quad(fill(Bounds::new(position, size), self.color));
|
||||
cx.paint_quad(fill(Bounds::new(position, size), self.color), None, None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,7 +782,7 @@ impl Element for TerminalElement {
|
||||
) {
|
||||
let mut layout = self.compute_layout(bounds, cx);
|
||||
|
||||
cx.paint_quad(fill(bounds, layout.background_color));
|
||||
cx.paint_quad(fill(bounds, layout.background_color), None, None);
|
||||
let origin = bounds.origin + Point::new(layout.gutter, px(0.));
|
||||
|
||||
let terminal_input_handler = TerminalInputHandler {
|
||||
|
||||
@@ -11,6 +11,7 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
client.workspace = true
|
||||
editor.workspace = true
|
||||
feature_flags.workspace = true
|
||||
fs.workspace = true
|
||||
fuzzy.workspace = true
|
||||
|
||||
@@ -766,7 +766,11 @@ mod element {
|
||||
}
|
||||
|
||||
cx.add_opaque_layer(handle_bounds);
|
||||
cx.paint_quad(gpui::fill(divider_bounds, cx.theme().colors().border));
|
||||
cx.paint_quad(
|
||||
gpui::fill(divider_bounds, cx.theme().colors().border),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
cx.on_mouse_event({
|
||||
let dragged_handle = dragged_handle.clone();
|
||||
|
||||
@@ -113,6 +113,52 @@ theme_selector.workspace = true
|
||||
thiserror.workspace = true
|
||||
tiny_http = "0.8"
|
||||
toml.workspace = true
|
||||
tree-sitter-astro.workspace = true
|
||||
tree-sitter-bash.workspace = true
|
||||
tree-sitter-c-sharp.workspace = true
|
||||
tree-sitter-c.workspace = true
|
||||
tree-sitter-clojure.workspace = true
|
||||
tree-sitter-cpp.workspace = true
|
||||
tree-sitter-css.workspace = true
|
||||
tree-sitter-dockerfile.workspace = true
|
||||
tree-sitter-dart.workspace = true
|
||||
tree-sitter-elixir.workspace = true
|
||||
tree-sitter-elm.workspace = true
|
||||
tree-sitter-embedded-template.workspace = true
|
||||
tree-sitter-erlang.workspace = true
|
||||
tree-sitter-gitcommit.workspace = true
|
||||
tree-sitter-gleam.workspace = true
|
||||
tree-sitter-glsl.workspace = true
|
||||
tree-sitter-go.workspace = true
|
||||
tree-sitter-gomod.workspace = true
|
||||
tree-sitter-gowork.workspace = true
|
||||
tree-sitter-haskell.workspace = true
|
||||
tree-sitter-hcl.workspace = true
|
||||
tree-sitter-heex.workspace = true
|
||||
tree-sitter-html.workspace = true
|
||||
tree-sitter-json.workspace = true
|
||||
tree-sitter-lua.workspace = true
|
||||
tree-sitter-markdown.workspace = true
|
||||
tree-sitter-nix.workspace = true
|
||||
tree-sitter-nu.workspace = true
|
||||
tree-sitter-ocaml.workspace = true
|
||||
tree-sitter-php.workspace = true
|
||||
tree-sitter-prisma-io.workspace = true
|
||||
tree-sitter-proto.workspace = true
|
||||
tree-sitter-purescript.workspace = true
|
||||
tree-sitter-python.workspace = true
|
||||
tree-sitter-racket.workspace = true
|
||||
tree-sitter-ruby.workspace = true
|
||||
tree-sitter-rust.workspace = true
|
||||
tree-sitter-scheme.workspace = true
|
||||
tree-sitter-svelte.workspace = true
|
||||
tree-sitter-toml.workspace = true
|
||||
tree-sitter-typescript.workspace = true
|
||||
tree-sitter-uiua.workspace = true
|
||||
tree-sitter-vue.workspace = true
|
||||
tree-sitter-yaml.workspace = true
|
||||
tree-sitter-zig.workspace = true
|
||||
tree-sitter.workspace = true
|
||||
url.workspace = true
|
||||
urlencoding = "2.1.2"
|
||||
util.workspace = true
|
||||
@@ -121,8 +167,6 @@ vim.workspace = true
|
||||
welcome.workspace = true
|
||||
workspace.workspace = true
|
||||
zed_actions.workspace = true
|
||||
languages = { version = "0.1.0", path = "../languages" }
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
call = { workspace = true, features = ["test-support"] }
|
||||
@@ -131,7 +175,6 @@ gpui = { workspace = true, features = ["test-support"] }
|
||||
language = { workspace = true, features = ["test-support"] }
|
||||
project = { workspace = true, features = ["test-support"] }
|
||||
text = { workspace = true, features = ["test-support"] }
|
||||
tree-sitter-rust.workspace = true
|
||||
unindent.workspace = true
|
||||
workspace = { workspace = true, features = ["test-support"] }
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ mod zig;
|
||||
// 6. If the language has injections add an injections.scm query file
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "src/"]
|
||||
#[folder = "src/languages"]
|
||||
#[exclude = "*.rs"]
|
||||
struct LanguageDir;
|
||||
|
||||
@@ -296,7 +296,7 @@ mod tests {
|
||||
});
|
||||
});
|
||||
});
|
||||
let language = crate::language("c", tree_sitter_c::language(), None).await;
|
||||
let language = crate::languages::language("c", tree_sitter_c::language(), None).await;
|
||||
|
||||
cx.new_model(|cx| {
|
||||
let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "")
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user