Merge remote-tracking branch 'origin/main' into fewer-context-traits

This commit is contained in:
Antonio Scandurra 2023-04-26 09:54:58 +02:00
commit 7ca412ade3
81 changed files with 1578 additions and 654 deletions

26
Cargo.lock generated
View File

@ -148,9 +148,6 @@ name = "anyhow"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
dependencies = [
"backtrace",
]
[[package]]
name = "arrayref"
@ -3612,6 +3609,26 @@ dependencies = [
"url",
]
[[package]]
name = "lsp_log"
version = "0.1.0"
dependencies = [
"anyhow",
"collections",
"editor",
"futures 0.3.25",
"gpui",
"language",
"lsp",
"project",
"serde",
"settings",
"theme",
"unindent",
"util",
"workspace",
]
[[package]]
name = "mach"
version = "0.3.2"
@ -7239,7 +7256,7 @@ dependencies = [
[[package]]
name = "tree-sitter-json"
version = "0.20.0"
source = "git+https://github.com/tree-sitter/tree-sitter-json?rev=137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8#137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8"
source = "git+https://github.com/tree-sitter/tree-sitter-json?rev=40a81c01a40ac48744e0c8ccabbaba1920441199#40a81c01a40ac48744e0c8ccabbaba1920441199"
dependencies = [
"cc",
"tree-sitter",
@ -8571,6 +8588,7 @@ dependencies = [
"libc",
"log",
"lsp",
"lsp_log",
"node_runtime",
"num_cpus",
"outline",

View File

@ -35,6 +35,7 @@ members = [
"crates/live_kit_client",
"crates/live_kit_server",
"crates/lsp",
"crates/lsp_log",
"crates/media",
"crates/menu",
"crates/node_runtime",
@ -71,12 +72,27 @@ default-members = ["crates/zed"]
resolver = "2"
[workspace.dependencies]
anyhow = { version = "1.0.57" }
async-trait = { version = "0.1" }
ctor = { version = "0.1" }
env_logger = { version = "0.9" }
futures = { version = "0.3" }
lazy_static = { version = "1.4.0" }
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
ordered-float = { version = "2.1.1" }
parking_lot = { version = "0.11.1" }
postage = { version = "0.5", features = ["futures-traits"] }
rand = { version = "0.8.5" }
regex = { version = "1.5" }
serde = { version = "1.0", features = ["derive", "rc"] }
serde_derive = { version = "1.0", features = ["deserialize_in_place"] }
serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] }
rand = { version = "0.8" }
postage = { version = "0.5", features = ["futures-traits"] }
smallvec = { version = "1.6", features = ["union"] }
smol = { version = "1.2" }
tempdir = { version = "0.3.7" }
thiserror = { version = "1.0.29" }
time = { version = "0.3", features = ["serde", "serde-well-known"] }
unindent = { version = "0.1.7" }
[patch.crates-io]
tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "c51896d32dcc11a38e41f36e3deb1a6a9c4f4b14" }

View File

@ -17,5 +17,5 @@ project = { path = "../project" }
settings = { path = "../settings" }
util = { path = "../util" }
workspace = { path = "../workspace" }
futures = "0.3"
smallvec = { workspace = true }
futures.workspace = true
smallvec.workspace = true

View File

@ -10,6 +10,5 @@ doctest = false
[dependencies]
gpui = { path = "../gpui" }
anyhow = "1.0.38"
anyhow.workspace = true
rust-embed = { version = "6.3", features = ["include-exclude"] }

View File

@ -18,12 +18,12 @@ settings = { path = "../settings" }
theme = { path = "../theme" }
workspace = { path = "../workspace" }
util = { path = "../util" }
anyhow = "1.0.38"
anyhow.workspace = true
isahc = "1.7"
lazy_static = "1.4"
log = "0.4"
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
smol = "1.2.5"
tempdir = "0.3.7"
lazy_static.workspace = true
log.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
smol.workspace = true
tempdir.workspace = true

View File

@ -22,7 +22,7 @@ test-support = [
client = { path = "../client" }
collections = { path = "../collections" }
gpui = { path = "../gpui" }
log = "0.4"
log.workspace = true
live_kit_client = { path = "../live_kit_client" }
fs = { path = "../fs" }
language = { path = "../language" }
@ -31,10 +31,10 @@ project = { path = "../project" }
settings = { path = "../settings" }
util = { path = "../util" }
anyhow = "1.0.38"
anyhow.workspace = true
async-broadcast = "0.4"
futures = "0.3"
postage = { workspace = true }
futures.workspace = true
postage.workspace = true
[dev-dependencies]
client = { path = "../client", features = ["test-support"] }

View File

@ -13,12 +13,12 @@ name = "cli"
path = "src/main.rs"
[dependencies]
anyhow = "1.0"
anyhow.workspace = true
clap = { version = "3.1", features = ["derive"] }
dirs = "3.0"
ipc-channel = "0.16"
serde = { workspace = true }
serde_derive = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.9"

View File

@ -17,27 +17,28 @@ db = { path = "../db" }
gpui = { path = "../gpui" }
util = { path = "../util" }
rpc = { path = "../rpc" }
settings = { path = "../settings" }
staff_mode = { path = "../staff_mode" }
sum_tree = { path = "../sum_tree" }
anyhow = "1.0.38"
anyhow.workspace = true
async-recursion = "0.3"
async-tungstenite = { version = "0.16", features = ["async-tls"] }
futures = "0.3"
futures.workspace = true
image = "0.23"
lazy_static = "1.4.0"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11.1"
postage = { workspace = true }
rand = "0.8.3"
smol = "1.2.5"
thiserror = "1.0.29"
time = { version = "0.3", features = ["serde", "serde-well-known"] }
lazy_static.workspace = true
log.workspace = true
parking_lot.workspace = true
postage.workspace = true
rand.workspace = true
smol.workspace = true
thiserror.workspace = true
time.workspace = true
tiny_http = "0.8"
uuid = { version = "1.1.2", features = ["v4"] }
url = "2.2"
serde = { workspace = true }
serde_derive = { workspace = true }
settings = { path = "../settings" }
serde.workspace = true
serde_derive.workspace = true
tempfile = "3"
[dev-dependencies]

View File

@ -9,4 +9,4 @@ path = "src/clock.rs"
doctest = false
[dependencies]
smallvec = { workspace = true }
smallvec.workspace = true

View File

@ -19,7 +19,7 @@ live_kit_server = { path = "../live_kit_server" }
rpc = { path = "../rpc" }
util = { path = "../util" }
anyhow = "1.0.40"
anyhow.workspace = true
async-tungstenite = "0.16"
axum = { version = "0.5", features = ["json", "headers", "ws"] }
axum-extra = { version = "0.3", features = ["erased-json"] }
@ -27,26 +27,26 @@ base64 = "0.13"
clap = { version = "3.1", features = ["derive"], optional = true }
dashmap = "5.4"
envy = "0.4.2"
futures = "0.3"
futures.workspace = true
hyper = "0.14"
lazy_static = "1.4"
lazy_static.workspace = true
lipsum = { version = "0.8", optional = true }
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
log.workspace = true
nanoid = "0.4"
parking_lot = "0.11.1"
parking_lot.workspace = true
prometheus = "0.13"
rand = "0.8"
rand.workspace = true
reqwest = { version = "0.11", features = ["json"], optional = true }
scrypt = "0.7"
# Remove fork dependency when a version with https://github.com/SeaQL/sea-orm/pull/1283 is released.
sea-orm = { git = "https://github.com/zed-industries/sea-orm", rev = "18f4c691085712ad014a51792af75a9044bacee6", features = ["sqlx-postgres", "postgres-array", "runtime-tokio-rustls"] }
sea-query = "0.27"
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
sha-1 = "0.9"
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "postgres", "json", "time", "uuid", "any"] }
time = { version = "0.3", features = ["serde", "serde-well-known"] }
time.workspace = true
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.17"
tonic = "0.6"
@ -55,7 +55,6 @@ toml = "0.5.8"
tracing = "0.1.34"
tracing-log = "0.1.3"
tracing-subscriber = { version = "0.3.11", features = ["env-filter", "json"] }
indoc = "1.0.4"
[dev-dependencies]
collections = { path = "../collections", features = ["test-support"] }
@ -75,14 +74,15 @@ settings = { path = "../settings", features = ["test-support"] }
theme = { path = "../theme" }
workspace = { path = "../workspace", features = ["test-support"] }
ctor = "0.1"
env_logger = "0.9"
ctor.workspace = true
env_logger.workspace = true
indoc = "1.0.4"
util = { path = "../util" }
lazy_static = "1.4"
lazy_static.workspace = true
sea-orm = { git = "https://github.com/zed-industries/sea-orm", rev = "18f4c691085712ad014a51792af75a9044bacee6", features = ["sqlx-sqlite"] }
serde_json = { workspace = true }
serde_json.workspace = true
sqlx = { version = "0.6", features = ["sqlite"] }
unindent = "0.1"
unindent.workspace = true
[features]
seed-support = ["clap", "lipsum", "reqwest"]

View File

@ -32,7 +32,10 @@ use std::{
env, future, mem,
path::{Path, PathBuf},
rc::Rc,
sync::Arc,
sync::{
atomic::{AtomicBool, Ordering::SeqCst},
Arc,
},
};
use unindent::Unindent as _;
use workspace::{
@ -3636,6 +3639,141 @@ async fn test_collaborating_with_diagnostics(
});
}
#[gpui::test(iterations = 10)]
async fn test_collaborating_with_lsp_progress_updates_and_diagnostics_ordering(
deterministic: Arc<Deterministic>,
cx_a: &mut TestAppContext,
cx_b: &mut TestAppContext,
) {
deterministic.forbid_parking();
let mut server = TestServer::start(&deterministic).await;
let client_a = server.create_client(cx_a, "user_a").await;
let client_b = server.create_client(cx_b, "user_b").await;
server
.create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
.await;
// Set up a fake language server.
let mut language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
..Default::default()
},
Some(tree_sitter_rust::language()),
);
let mut fake_language_servers = language
.set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
disk_based_diagnostics_progress_token: Some("the-disk-based-token".into()),
disk_based_diagnostics_sources: vec!["the-disk-based-diagnostics-source".into()],
..Default::default()
}))
.await;
client_a.language_registry.add(Arc::new(language));
let file_names = &["one.rs", "two.rs", "three.rs", "four.rs", "five.rs"];
client_a
.fs
.insert_tree(
"/test",
json!({
"one.rs": "const ONE: usize = 1;",
"two.rs": "const TWO: usize = 2;",
"three.rs": "const THREE: usize = 3;",
"four.rs": "const FOUR: usize = 3;",
"five.rs": "const FIVE: usize = 3;",
}),
)
.await;
let (project_a, worktree_id) = client_a.build_local_project("/test", cx_a).await;
// Share a project as client A
let active_call_a = cx_a.read(ActiveCall::global);
let project_id = active_call_a
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
// Join the project as client B and open all three files.
let project_b = client_b.build_remote_project(project_id, cx_b).await;
let guest_buffers = futures::future::try_join_all(file_names.iter().map(|file_name| {
project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, file_name), cx))
}))
.await
.unwrap();
// Simulate a language server reporting errors for a file.
let fake_language_server = fake_language_servers.next().await.unwrap();
fake_language_server
.request::<lsp::request::WorkDoneProgressCreate>(lsp::WorkDoneProgressCreateParams {
token: lsp::NumberOrString::String("the-disk-based-token".to_string()),
})
.await
.unwrap();
fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
token: lsp::NumberOrString::String("the-disk-based-token".to_string()),
value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Begin(
lsp::WorkDoneProgressBegin {
title: "Progress Began".into(),
..Default::default()
},
)),
});
for file_name in file_names {
fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
lsp::PublishDiagnosticsParams {
uri: lsp::Url::from_file_path(Path::new("/test").join(file_name)).unwrap(),
version: None,
diagnostics: vec![lsp::Diagnostic {
severity: Some(lsp::DiagnosticSeverity::WARNING),
source: Some("the-disk-based-diagnostics-source".into()),
range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 0)),
message: "message one".to_string(),
..Default::default()
}],
},
);
}
fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
token: lsp::NumberOrString::String("the-disk-based-token".to_string()),
value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::End(
lsp::WorkDoneProgressEnd { message: None },
)),
});
// When the "disk base diagnostics finished" message is received, the buffers'
// diagnostics are expected to be present.
let disk_based_diagnostics_finished = Arc::new(AtomicBool::new(false));
project_b.update(cx_b, {
let project_b = project_b.clone();
let disk_based_diagnostics_finished = disk_based_diagnostics_finished.clone();
move |_, cx| {
cx.subscribe(&project_b, move |_, _, event, cx| {
if let project::Event::DiskBasedDiagnosticsFinished { .. } = event {
disk_based_diagnostics_finished.store(true, SeqCst);
for buffer in &guest_buffers {
assert_eq!(
buffer
.read(cx)
.snapshot()
.diagnostics_in_range::<_, usize>(0..5, false)
.count(),
1,
"expected a diagnostic for buffer {:?}",
buffer.read(cx).file().unwrap().path(),
);
}
}
})
.detach();
}
});
deterministic.run_until_parked();
assert!(disk_based_diagnostics_finished.load(SeqCst));
}
#[gpui::test(iterations = 10)]
async fn test_collaborating_with_completion(
deterministic: Arc<Deterministic>,

View File

@ -39,12 +39,13 @@ settings = { path = "../settings" }
theme = { path = "../theme" }
util = { path = "../util" }
workspace = { path = "../workspace" }
anyhow = "1.0"
futures = "0.3"
log = "0.4"
postage = { workspace = true }
serde = { workspace = true }
serde_derive = { workspace = true }
anyhow.workspace = true
futures.workspace = true
log.workspace = true
postage.workspace = true
serde.workspace = true
serde_derive.workspace = true
[dev-dependencies]
call = { path = "../call", features = ["test-support"] }

View File

@ -24,7 +24,7 @@ workspace = { path = "../workspace" }
gpui = { path = "../gpui", features = ["test-support"] }
editor = { path = "../editor", features = ["test-support"] }
project = { path = "../project", features = ["test-support"] }
serde_json = { workspace = true }
serde_json.workspace = true
workspace = { path = "../workspace", features = ["test-support"] }
ctor = "0.1"
env_logger = "0.9"
ctor.workspace = true
env_logger.workspace = true

View File

@ -2,7 +2,7 @@ use collections::CommandPaletteFilter;
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
actions, elements::*, keymap_matcher::Keystroke, Action, AppContext, Element, MouseState,
ViewContext,
ViewContext, WindowContext,
};
use picker::{Picker, PickerDelegate, PickerEvent};
use settings::Settings;
@ -45,15 +45,19 @@ fn toggle_command_palette(_: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Wo
let workspace = cx.handle();
let focused_view_id = cx.focused_view_id().unwrap_or_else(|| workspace.id());
cx.defer(move |workspace, cx| {
workspace.toggle_modal(cx, |_, cx| {
cx.add_view(|cx| Picker::new(CommandPaletteDelegate::new(focused_view_id, cx), cx))
});
cx.window_context().defer(move |cx| {
// Build the delegate before the workspace is put on the stack so we can find it when
// computing the actions. We should really not allow available_actions to be called
// if it's not reliable however.
let delegate = CommandPaletteDelegate::new(focused_view_id, cx);
workspace.update(cx, |workspace, cx| {
workspace.toggle_modal(cx, |_, cx| cx.add_view(|cx| Picker::new(delegate, cx)));
})
});
}
impl CommandPaletteDelegate {
pub fn new(focused_view_id: usize, cx: &mut ViewContext<Picker<Self>>) -> Self {
pub fn new(focused_view_id: usize, cx: &mut WindowContext) -> Self {
let actions = cx
.available_actions(focused_view_id)
.filter_map(|(name, action, bindings)| {

View File

@ -13,4 +13,4 @@ gpui = { path = "../gpui" }
menu = { path = "../menu" }
settings = { path = "../settings" }
theme = { path = "../theme" }
smallvec = { workspace = true }
smallvec.workspace = true

View File

@ -30,12 +30,12 @@ node_runtime = { path = "../node_runtime"}
util = { path = "../util" }
async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] }
async-tar = "0.4.2"
anyhow = "1.0"
log = "0.4"
serde = { workspace = true }
serde_derive = { workspace = true }
smol = "1.2.5"
futures = "0.3"
anyhow.workspace = true
log.workspace = true
serde.workspace = true
serde_derive.workspace = true
smol.workspace = true
futures.workspace = true
[dev-dependencies]
clock = { path = "../clock" }

View File

@ -17,6 +17,6 @@ settings = { path = "../settings" }
theme = { path = "../theme" }
util = { path = "../util" }
workspace = { path = "../workspace" }
anyhow = "1.0"
smol = "1.2.5"
futures = "0.3"
anyhow.workspace = true
smol.workspace = true
futures.workspace = true

View File

@ -272,7 +272,7 @@ impl CopilotButton {
let mut menu_options = Vec::with_capacity(2);
menu_options.push(ContextMenuItem::item("Sign In", InitiateSignIn));
menu_options.push(ContextMenuItem::item("Hide Copilot", HideCopilot));
menu_options.push(ContextMenuItem::item("Disable Copilot", HideCopilot));
self.popup_menu.update(cx, |menu, cx| {
menu.show(

View File

@ -17,17 +17,17 @@ gpui = { path = "../gpui" }
sqlez = { path = "../sqlez" }
sqlez_macros = { path = "../sqlez_macros" }
util = { path = "../util" }
anyhow = "1.0.57"
anyhow.workspace = true
indoc = "1.0.4"
async-trait = "0.1"
lazy_static = "1.4.0"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11.1"
serde = { workspace = true }
serde_derive = { workspace = true }
smol = "1.2"
async-trait.workspace = true
lazy_static.workspace = true
log.workspace = true
parking_lot.workspace = true
serde.workspace = true
serde_derive.workspace = true
smol.workspace = true
[dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] }
env_logger = "0.9.1"
tempdir = { version = "0.3.7" }
env_logger.workspace = true
tempdir.workspace = true

View File

@ -9,26 +9,28 @@ path = "src/diagnostics.rs"
doctest = false
[dependencies]
anyhow = "1.0"
smallvec = { workspace = true }
collections = { path = "../collections" }
editor = { path = "../editor" }
gpui = { path = "../gpui" }
language = { path = "../language" }
lsp = { path = "../lsp" }
gpui = { path = "../gpui" }
project = { path = "../project" }
settings = { path = "../settings" }
theme = { path = "../theme" }
util = { path = "../util" }
workspace = { path = "../workspace" }
postage = { workspace = true }
anyhow.workspace = true
smallvec.workspace = true
postage.workspace = true
[dev-dependencies]
unindent = "0.1"
client = { path = "../client", features = ["test-support"] }
editor = { path = "../editor", features = ["test-support"] }
language = { path = "../language", features = ["test-support"] }
lsp = { path = "../lsp", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
workspace = { path = "../workspace", features = ["test-support"] }
serde_json = { workspace = true }
serde_json.workspace = true
unindent.workspace = true

View File

@ -46,20 +46,20 @@ sqlez = { path = "../sqlez" }
workspace = { path = "../workspace" }
aho-corasick = "0.7"
anyhow = "1.0"
futures = "0.3"
anyhow.workspace = true
futures.workspace = true
indoc = "1.0.4"
itertools = "0.10"
lazy_static = "1.4"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
ordered-float = "2.1.1"
parking_lot = "0.11"
postage = { workspace = true }
rand = { version = "0.8.3", optional = true }
serde = { workspace = true }
serde_derive = { workspace = true }
smallvec = { workspace = true }
smol = "1.2"
lazy_static.workspace = true
log.workspace = true
ordered-float.workspace = true
parking_lot.workspace = true
postage.workspace = true
rand = { workspace = true, optional = true }
serde.workspace = true
serde_derive.workspace = true
smallvec.workspace = true
smol.workspace = true
tree-sitter-rust = { version = "*", optional = true }
tree-sitter-html = { version = "*", optional = true }
tree-sitter-javascript = { version = "*", optional = true }
@ -75,10 +75,11 @@ util = { path = "../util", features = ["test-support"] }
project = { path = "../project", features = ["test-support"] }
settings = { path = "../settings", features = ["test-support"] }
workspace = { path = "../workspace", features = ["test-support"] }
ctor = "0.1"
env_logger = "0.9"
rand = "0.8"
unindent = "0.1.7"
ctor.workspace = true
env_logger.workspace = true
rand.workspace = true
unindent.workspace = true
tree-sitter = "0.20"
tree-sitter-rust = "0.20"
tree-sitter-html = "0.19"

View File

@ -511,6 +511,7 @@ pub struct Editor {
workspace_id: Option<WorkspaceId>,
keymap_context_layers: BTreeMap<TypeId, KeymapContext>,
input_enabled: bool,
read_only: bool,
leader_replica_id: Option<u16>,
remote_id: Option<ViewId>,
hover_state: HoverState,
@ -1283,6 +1284,7 @@ impl Editor {
workspace_id: None,
keymap_context_layers: Default::default(),
input_enabled: true,
read_only: false,
leader_replica_id: None,
remote_id: None,
hover_state: Default::default(),
@ -1425,6 +1427,10 @@ impl Editor {
self.input_enabled = input_enabled;
}
pub fn set_read_only(&mut self, read_only: bool) {
self.read_only = read_only;
}
fn selections_did_change(
&mut self,
local: bool,
@ -1533,6 +1539,10 @@ impl Editor {
S: ToOffset,
T: Into<Arc<str>>,
{
if self.read_only {
return;
}
self.buffer
.update(cx, |buffer, cx| buffer.edit(edits, None, cx));
}
@ -1543,6 +1553,10 @@ impl Editor {
S: ToOffset,
T: Into<Arc<str>>,
{
if self.read_only {
return;
}
self.buffer.update(cx, |buffer, cx| {
buffer.edit(edits, Some(AutoindentMode::EachLine), cx)
});
@ -1897,6 +1911,9 @@ impl Editor {
pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
let text: Arc<str> = text.into();
if self.read_only {
return;
}
if !self.input_enabled {
cx.emit(Event::InputIgnored { text });
return;
@ -2282,6 +2299,10 @@ impl Editor {
autoindent_mode: Option<AutoindentMode>,
cx: &mut ViewContext<Self>,
) {
if self.read_only {
return;
}
let text: Arc<str> = text.into();
self.transact(cx, |this, cx| {
let old_selections = this.selections.all_adjusted(cx);

View File

@ -11,21 +11,21 @@ path = "src/feedback.rs"
test-support = []
[dependencies]
anyhow = "1.0.38"
anyhow.workspace = true
client = { path = "../client" }
editor = { path = "../editor" }
language = { path = "../language" }
log = "0.4"
futures = "0.3"
log.workspace = true
futures.workspace = true
gpui = { path = "../gpui" }
human_bytes = "0.4.1"
isahc = "1.7"
lazy_static = "1.4.0"
postage = { workspace = true }
lazy_static.workspace = true
postage.workspace = true
project = { path = "../project" }
search = { path = "../search" }
serde = { workspace = true }
serde_derive = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
settings = { path = "../settings" }
sysinfo = "0.27.1"
theme = { path = "../theme" }

View File

@ -19,11 +19,11 @@ settings = { path = "../settings" }
util = { path = "../util" }
theme = { path = "../theme" }
workspace = { path = "../workspace" }
postage = { workspace = true }
postage.workspace = true
[dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] }
serde_json = { workspace = true }
serde_json.workspace = true
workspace = { path = "../workspace", features = ["test-support"] }
ctor = "0.1"
env_logger = "0.9"
ctor.workspace = true
env_logger.workspace = true

View File

@ -13,20 +13,20 @@ gpui = { path = "../gpui" }
lsp = { path = "../lsp" }
rope = { path = "../rope" }
util = { path = "../util" }
anyhow = "1.0.57"
async-trait = "0.1"
futures = "0.3"
anyhow.workspace = true
async-trait.workspace = true
futures.workspace = true
tempfile = "3"
fsevent = { path = "../fsevent" }
lazy_static = "1.4.0"
parking_lot = "0.11.1"
smol = "1.2.5"
regex = "1.5"
lazy_static.workspace = true
parking_lot.workspace = true
smol.workspace = true
regex.workspace = true
git2 = { version = "0.15", default-features = false }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
log.workspace = true
libc = "0.2"
[features]

View File

@ -12,10 +12,10 @@ doctest = false
[dependencies]
bitflags = "1"
fsevent-sys = "3.0.2"
parking_lot = "0.11.1"
parking_lot.workspace = true
[dev-dependencies]
tempdir = "0.3.7"
tempdir.workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-apple-darwin"]

View File

@ -8,22 +8,22 @@ publish = false
path = "src/git.rs"
[dependencies]
anyhow = "1.0.38"
anyhow.workspace = true
clock = { path = "../clock" }
lazy_static = "1.4.0"
lazy_static.workspace = true
sum_tree = { path = "../sum_tree" }
text = { path = "../text" }
collections = { path = "../collections" }
util = { path = "../util" }
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
smol = "1.2"
parking_lot = "0.11.1"
async-trait = "0.1"
futures = "0.3"
log.workspace = true
smol.workspace = true
parking_lot.workspace = true
async-trait.workspace = true
futures.workspace = true
git2 = { version = "0.15", default-features = false }
[dev-dependencies]
unindent = "0.1.7"
unindent.workspace = true
[features]
test-support = []

View File

@ -15,4 +15,4 @@ menu = { path = "../menu" }
settings = { path = "../settings" }
text = { path = "../text" }
workspace = { path = "../workspace" }
postage = { workspace = true }
postage.workspace = true

View File

@ -21,32 +21,32 @@ sum_tree = { path = "../sum_tree" }
sqlez = { path = "../sqlez" }
async-task = "4.0.3"
backtrace = { version = "0.3", optional = true }
ctor = "0.1"
ctor.workspace = true
dhat = { version = "0.3", optional = true }
env_logger = { version = "0.9", optional = true }
etagere = "0.2"
futures = "0.3"
futures.workspace = true
image = "0.23"
itertools = "0.10"
lazy_static = "1.4.0"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
lazy_static.workspace = true
log.workspace = true
num_cpus = "1.13"
ordered-float = "2.1.1"
ordered-float.workspace = true
parking = "2.0.0"
parking_lot = "0.11.1"
parking_lot.workspace = true
pathfinder_color = "0.5"
pathfinder_geometry = "0.5"
postage = { workspace = true }
rand = "0.8.3"
postage.workspace = true
rand.workspace = true
resvg = "0.14"
schemars = "0.8"
seahash = "4.1"
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
smallvec = { workspace = true }
smol = "1.2"
time = { version = "0.3", features = ["serde", "serde-well-known"] }
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
smallvec.workspace = true
smol.workspace = true
time.workspace = true
tiny-skia = "0.5"
usvg = "0.14"
uuid = { version = "1.1.2", features = ["v4"] }
@ -60,13 +60,13 @@ cc = "1.0.67"
backtrace = "0.3"
collections = { path = "../collections", features = ["test-support"] }
dhat = "0.3"
env_logger = "0.9"
env_logger.workspace = true
png = "0.16"
simplelog = "0.9"
[target.'cfg(target_os = "macos")'.dependencies]
media = { path = "../media" }
anyhow = "1"
anyhow.workspace = true
block = "0.1"
cocoa = "0.24"
core-foundation = { version = "0.9.3", features = ["with-uuid"] }
@ -74,6 +74,6 @@ core-graphics = "0.22.3"
core-text = "19.2"
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "8eaf7a918eafa28b0a37dc759e2e0e7683fa24f1" }
foreign-types = "0.3"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
log.workspace = true
metal = "0.21.0"
objc = "0.2"

View File

@ -419,6 +419,11 @@ impl<'a> WindowContext<'a> {
.map(|action_type| (action_type, depth)),
);
}
} else {
log::error!(
"view {} not found when computing available actions",
view_id
);
}
}

View File

@ -11,8 +11,8 @@ path = "src/install_cli.rs"
test-support = []
[dependencies]
smol = "1.2.5"
anyhow = "1.0.38"
log = "0.4"
smol.workspace = true
anyhow.workspace = true
log.workspace = true
gpui = { path = "../gpui" }
util = { path = "../util" }

View File

@ -13,9 +13,9 @@ editor = { path = "../editor" }
gpui = { path = "../gpui" }
util = { path = "../util" }
workspace = { path = "../workspace" }
anyhow = "1.0"
anyhow.workspace = true
chrono = "0.4"
dirs = "4.0"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
log.workspace = true
settings = { path = "../settings" }
shellexpand = "2.1.0"

View File

@ -36,22 +36,22 @@ sum_tree = { path = "../sum_tree" }
text = { path = "../text" }
theme = { path = "../theme" }
util = { path = "../util" }
anyhow = "1.0.38"
anyhow.workspace = true
async-broadcast = "0.4"
async-trait = "0.1"
futures = "0.3"
lazy_static = "1.4"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11.1"
postage = { workspace = true }
rand = { version = "0.8.3", optional = true }
regex = "1.5"
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
async-trait.workspace = true
futures.workspace = true
lazy_static.workspace = true
log.workspace = true
parking_lot.workspace = true
postage.workspace = true
rand = { workspace = true, optional = true }
regex.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
similar = "1.3"
smallvec = { workspace = true }
smol = "1.2"
smallvec.workspace = true
smol.workspace = true
tree-sitter = "0.20"
tree-sitter-rust = { version = "*", optional = true }
tree-sitter-typescript = { version = "*", optional = true }
@ -65,10 +65,10 @@ lsp = { path = "../lsp", features = ["test-support"] }
text = { path = "../text", features = ["test-support"] }
settings = { path = "../settings", features = ["test-support"] }
util = { path = "../util", features = ["test-support"] }
ctor = "0.1"
env_logger = "0.9"
ctor.workspace = true
env_logger.workspace = true
indoc = "1.0.4"
rand = "0.8.3"
rand.workspace = true
tree-sitter-embedded-template = "*"
tree-sitter-html = "*"
tree-sitter-javascript = "*"
@ -78,4 +78,4 @@ tree-sitter-rust = "*"
tree-sitter-python = "*"
tree-sitter-typescript = "*"
tree-sitter-ruby = "*"
unindent = "0.1.7"
unindent.workspace = true

View File

@ -19,4 +19,4 @@ theme = { path = "../theme" }
settings = { path = "../settings" }
util = { path = "../util" }
workspace = { path = "../workspace" }
anyhow = "1.0"
anyhow.workspace = true

View File

@ -28,17 +28,17 @@ gpui = { path = "../gpui", optional = true }
live_kit_server = { path = "../live_kit_server", optional = true }
media = { path = "../media" }
anyhow = "1.0.38"
anyhow.workspace = true
async-broadcast = "0.4"
core-foundation = "0.9.3"
core-graphics = "0.22.3"
futures = "0.3"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11.1"
postage = { workspace = true }
futures.workspace = true
log.workspace = true
parking_lot.workspace = true
postage.workspace = true
async-trait = { version = "0.1", optional = true }
lazy_static = { version = "1.4", optional = true }
async-trait = { workspace = true, optional = true }
lazy_static = { workspace = true, optional = true }
nanoid = { version ="0.4", optional = true}
[dev-dependencies]
@ -47,8 +47,8 @@ gpui = { path = "../gpui", features = ["test-support"] }
live_kit_server = { path = "../live_kit_server" }
media = { path = "../media" }
anyhow = "1.0.38"
async-trait = "0.1"
anyhow.workspace = true
async-trait.workspace = true
block = "0.1"
bytes = "1.2"
byteorder = "1.4"
@ -56,18 +56,18 @@ cocoa = "0.24"
core-foundation = "0.9.3"
core-graphics = "0.22.3"
foreign-types = "0.3"
futures = "0.3"
futures.workspace = true
hmac = "0.12"
jwt = "0.16"
lazy_static = "1.4"
lazy_static.workspace = true
objc = "0.2"
parking_lot = "0.11.1"
serde = { workspace = true }
serde_derive = { workspace = true }
parking_lot.workspace = true
serde.workspace = true
serde_derive.workspace = true
sha2 = "0.10"
simplelog = "0.9"
[build-dependencies]
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true

View File

@ -10,17 +10,17 @@ path = "src/live_kit_server.rs"
doctest = false
[dependencies]
anyhow = "1.0.38"
async-trait = "0.1"
futures = "0.3"
anyhow.workspace = true
async-trait.workspace = true
futures.workspace = true
hmac = "0.12"
log = "0.4"
log.workspace = true
jwt = "0.16"
prost = "0.8"
prost-types = "0.8"
reqwest = "0.11"
serde = { workspace = true }
serde_derive = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
sha2 = "0.10"
[build-dependencies]

View File

@ -15,22 +15,24 @@ test-support = ["async-pipe"]
collections = { path = "../collections" }
gpui = { path = "../gpui" }
util = { path = "../util" }
anyhow = "1.0"
anyhow.workspace = true
async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "82d00a04211cf4e1236029aa03e6b6ce2a74c553", optional = true }
futures = "0.3"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
futures.workspace = true
log.workspace = true
lsp-types = "0.91"
parking_lot = "0.11"
postage = { workspace = true }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
smol = "1.2"
parking_lot.workspace = true
postage.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
smol.workspace = true
[dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] }
util = { path = "../util", features = ["test-support"] }
async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "82d00a04211cf4e1236029aa03e6b6ce2a74c553" }
ctor = "0.1"
env_logger = "0.9"
unindent = "0.1.7"
ctor.workspace = true
env_logger.workspace = true
unindent.workspace = true

View File

@ -20,10 +20,10 @@ use std::{
future::Future,
io::Write,
path::PathBuf,
str::FromStr,
str::{self, FromStr as _},
sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc,
Arc, Weak,
},
};
use std::{path::Path, process::Stdio};
@ -34,16 +34,18 @@ const CONTENT_LEN_HEADER: &str = "Content-Length: ";
type NotificationHandler = Box<dyn Send + FnMut(Option<usize>, &str, AsyncAppContext)>;
type ResponseHandler = Box<dyn Send + FnOnce(Result<&str, Error>)>;
type IoHandler = Box<dyn Send + FnMut(bool, &str)>;
pub struct LanguageServer {
server_id: LanguageServerId,
next_id: AtomicUsize,
outbound_tx: channel::Sender<Vec<u8>>,
outbound_tx: channel::Sender<String>,
name: String,
capabilities: ServerCapabilities,
code_action_kinds: Option<Vec<CodeActionKind>>,
notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
response_handlers: Arc<Mutex<Option<HashMap<usize, ResponseHandler>>>>,
io_handlers: Arc<Mutex<HashMap<usize, IoHandler>>>,
executor: Arc<executor::Background>,
#[allow(clippy::type_complexity)]
io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
@ -56,9 +58,15 @@ pub struct LanguageServer {
#[repr(transparent)]
pub struct LanguageServerId(pub usize);
pub struct Subscription {
method: &'static str,
notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
pub enum Subscription {
Notification {
method: &'static str,
notification_handlers: Option<Arc<Mutex<HashMap<&'static str, NotificationHandler>>>>,
},
Io {
id: usize,
io_handlers: Option<Weak<Mutex<HashMap<usize, IoHandler>>>>,
},
}
#[derive(Serialize, Deserialize)]
@ -177,33 +185,40 @@ impl LanguageServer {
Stdout: AsyncRead + Unpin + Send + 'static,
F: FnMut(AnyNotification) + 'static + Send,
{
let (outbound_tx, outbound_rx) = channel::unbounded::<Vec<u8>>();
let (outbound_tx, outbound_rx) = channel::unbounded::<String>();
let (output_done_tx, output_done_rx) = barrier::channel();
let notification_handlers =
Arc::new(Mutex::new(HashMap::<_, NotificationHandler>::default()));
let response_handlers =
Arc::new(Mutex::new(Some(HashMap::<_, ResponseHandler>::default())));
let io_handlers = Arc::new(Mutex::new(HashMap::default()));
let input_task = cx.spawn(|cx| {
let notification_handlers = notification_handlers.clone();
let response_handlers = response_handlers.clone();
Self::handle_input(
stdout,
on_unhandled_notification,
notification_handlers,
response_handlers,
notification_handlers.clone(),
response_handlers.clone(),
io_handlers.clone(),
cx,
)
.log_err()
});
let (output_done_tx, output_done_rx) = barrier::channel();
let output_task = cx.background().spawn({
let response_handlers = response_handlers.clone();
Self::handle_output(stdin, outbound_rx, output_done_tx, response_handlers).log_err()
Self::handle_output(
stdin,
outbound_rx,
output_done_tx,
response_handlers.clone(),
io_handlers.clone(),
)
.log_err()
});
Self {
server_id,
notification_handlers,
response_handlers,
io_handlers,
name: Default::default(),
capabilities: Default::default(),
code_action_kinds,
@ -226,6 +241,7 @@ impl LanguageServer {
mut on_unhandled_notification: F,
notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
response_handlers: Arc<Mutex<Option<HashMap<usize, ResponseHandler>>>>,
io_handlers: Arc<Mutex<HashMap<usize, IoHandler>>>,
cx: AsyncAppContext,
) -> anyhow::Result<()>
where
@ -252,7 +268,13 @@ impl LanguageServer {
buffer.resize(message_len, 0);
stdout.read_exact(&mut buffer).await?;
log::trace!("incoming message:{}", String::from_utf8_lossy(&buffer));
if let Ok(message) = str::from_utf8(&buffer) {
log::trace!("incoming message:{}", message);
for handler in io_handlers.lock().values_mut() {
handler(true, message);
}
}
if let Ok(msg) = serde_json::from_slice::<AnyNotification>(&buffer) {
if let Some(handler) = notification_handlers.lock().get_mut(msg.method) {
@ -291,9 +313,10 @@ impl LanguageServer {
async fn handle_output<Stdin>(
stdin: Stdin,
outbound_rx: channel::Receiver<Vec<u8>>,
outbound_rx: channel::Receiver<String>,
output_done_tx: barrier::Sender,
response_handlers: Arc<Mutex<Option<HashMap<usize, ResponseHandler>>>>,
io_handlers: Arc<Mutex<HashMap<usize, IoHandler>>>,
) -> anyhow::Result<()>
where
Stdin: AsyncWrite + Unpin + Send + 'static,
@ -307,13 +330,17 @@ impl LanguageServer {
});
let mut content_len_buffer = Vec::new();
while let Ok(message) = outbound_rx.recv().await {
log::trace!("outgoing message:{}", String::from_utf8_lossy(&message));
log::trace!("outgoing message:{}", message);
for handler in io_handlers.lock().values_mut() {
handler(false, &message);
}
content_len_buffer.clear();
write!(content_len_buffer, "{}", message.len()).unwrap();
stdin.write_all(CONTENT_LEN_HEADER.as_bytes()).await?;
stdin.write_all(&content_len_buffer).await?;
stdin.write_all("\r\n\r\n".as_bytes()).await?;
stdin.write_all(&message).await?;
stdin.write_all(message.as_bytes()).await?;
stdin.flush().await?;
}
drop(output_done_tx);
@ -464,6 +491,19 @@ impl LanguageServer {
self.on_custom_request(T::METHOD, f)
}
#[must_use]
pub fn on_io<F>(&self, f: F) -> Subscription
where
F: 'static + Send + FnMut(bool, &str),
{
let id = self.next_id.fetch_add(1, SeqCst);
self.io_handlers.lock().insert(id, Box::new(f));
Subscription::Io {
id,
io_handlers: Some(Arc::downgrade(&self.io_handlers)),
}
}
pub fn remove_request_handler<T: request::Request>(&self) {
self.notification_handlers.lock().remove(T::METHOD);
}
@ -490,9 +530,9 @@ impl LanguageServer {
prev_handler.is_none(),
"registered multiple handlers for the same LSP method"
);
Subscription {
Subscription::Notification {
method,
notification_handlers: self.notification_handlers.clone(),
notification_handlers: Some(self.notification_handlers.clone()),
}
}
@ -537,7 +577,7 @@ impl LanguageServer {
},
};
if let Some(response) =
serde_json::to_vec(&response).log_err()
serde_json::to_string(&response).log_err()
{
outbound_tx.try_send(response).ok();
}
@ -560,7 +600,7 @@ impl LanguageServer {
message: error.to_string(),
}),
};
if let Some(response) = serde_json::to_vec(&response).log_err() {
if let Some(response) = serde_json::to_string(&response).log_err() {
outbound_tx.try_send(response).ok();
}
}
@ -572,9 +612,9 @@ impl LanguageServer {
prev_handler.is_none(),
"registered multiple handlers for the same LSP method"
);
Subscription {
Subscription::Notification {
method,
notification_handlers: self.notification_handlers.clone(),
notification_handlers: Some(self.notification_handlers.clone()),
}
}
@ -612,14 +652,14 @@ impl LanguageServer {
fn request_internal<T: request::Request>(
next_id: &AtomicUsize,
response_handlers: &Mutex<Option<HashMap<usize, ResponseHandler>>>,
outbound_tx: &channel::Sender<Vec<u8>>,
outbound_tx: &channel::Sender<String>,
params: T::Params,
) -> impl 'static + Future<Output = Result<T::Result>>
where
T::Result: 'static + Send,
{
let id = next_id.fetch_add(1, SeqCst);
let message = serde_json::to_vec(&Request {
let message = serde_json::to_string(&Request {
jsonrpc: JSON_RPC_VERSION,
id,
method: T::METHOD,
@ -662,10 +702,10 @@ impl LanguageServer {
}
fn notify_internal<T: notification::Notification>(
outbound_tx: &channel::Sender<Vec<u8>>,
outbound_tx: &channel::Sender<String>,
params: T::Params,
) -> Result<()> {
let message = serde_json::to_vec(&Notification {
let message = serde_json::to_string(&Notification {
jsonrpc: JSON_RPC_VERSION,
method: T::METHOD,
params,
@ -685,8 +725,14 @@ impl Drop for LanguageServer {
}
impl Subscription {
pub fn detach(mut self) {
self.method = "";
pub fn detach(&mut self) {
match self {
Subscription::Notification {
notification_handlers,
..
} => *notification_handlers = None,
Subscription::Io { io_handlers, .. } => *io_handlers = None,
}
}
}
@ -698,7 +744,21 @@ impl fmt::Display for LanguageServerId {
impl Drop for Subscription {
fn drop(&mut self) {
self.notification_handlers.lock().remove(self.method);
match self {
Subscription::Notification {
method,
notification_handlers,
} => {
if let Some(handlers) = notification_handlers {
handlers.lock().remove(method);
}
}
Subscription::Io { id, io_handlers } => {
if let Some(io_handlers) = io_handlers.as_ref().and_then(|h| h.upgrade()) {
io_handlers.lock().remove(id);
}
}
}
}
}

29
crates/lsp_log/Cargo.toml Normal file
View File

@ -0,0 +1,29 @@
[package]
name = "lsp_log"
version = "0.1.0"
edition = "2021"
publish = false
[lib]
path = "src/lsp_log.rs"
doctest = false
[dependencies]
collections = { path = "../collections" }
editor = { path = "../editor" }
settings = { path = "../settings" }
theme = { path = "../theme" }
language = { path = "../language" }
project = { path = "../project" }
workspace = { path = "../workspace" }
gpui = { path = "../gpui" }
util = { path = "../util" }
lsp = { path = "../lsp" }
futures.workspace = true
serde.workspace = true
anyhow.workspace = true
[dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] }
util = { path = "../util", features = ["test-support"] }
unindent.workspace = true

View File

@ -0,0 +1,523 @@
use collections::{hash_map, HashMap};
use editor::Editor;
use futures::{channel::mpsc, StreamExt};
use gpui::{
actions,
elements::{
AnchorCorner, ChildView, Empty, Flex, Label, MouseEventHandler, Overlay, OverlayFitMode,
ParentElement, Stack,
},
platform::{CursorStyle, MouseButton},
AnyElement, AppContext, Element, Entity, ModelContext, ModelHandle, View, ViewContext,
ViewHandle, WeakModelHandle,
};
use language::{Buffer, LanguageServerId, LanguageServerName};
use project::{Project, WorktreeId};
use settings::Settings;
use std::{borrow::Cow, sync::Arc};
use theme::{ui, Theme};
use workspace::{
item::{Item, ItemHandle},
ToolbarItemLocation, ToolbarItemView, Workspace,
};
const SEND_LINE: &str = "// Send:\n";
const RECEIVE_LINE: &str = "// Receive:\n";
struct LogStore {
projects: HashMap<WeakModelHandle<Project>, LogStoreProject>,
io_tx: mpsc::UnboundedSender<(WeakModelHandle<Project>, LanguageServerId, bool, String)>,
}
struct LogStoreProject {
servers: HashMap<LanguageServerId, LogStoreLanguageServer>,
_subscription: gpui::Subscription,
}
struct LogStoreLanguageServer {
buffer: ModelHandle<Buffer>,
last_message_kind: Option<MessageKind>,
_subscription: lsp::Subscription,
}
pub struct LspLogView {
log_store: ModelHandle<LogStore>,
current_server_id: Option<LanguageServerId>,
editor: Option<ViewHandle<Editor>>,
project: ModelHandle<Project>,
}
pub struct LspLogToolbarItemView {
log_view: Option<ViewHandle<LspLogView>>,
menu_open: bool,
project: ModelHandle<Project>,
}
#[derive(Copy, Clone, PartialEq, Eq)]
enum MessageKind {
Send,
Receive,
}
actions!(log, [OpenLanguageServerLogs]);
pub fn init(cx: &mut AppContext) {
let log_set = cx.add_model(|cx| LogStore::new(cx));
cx.add_action(
move |workspace: &mut Workspace, _: &OpenLanguageServerLogs, cx: _| {
let project = workspace.project().read(cx);
if project.is_local() {
workspace.add_item(
Box::new(cx.add_view(|cx| {
LspLogView::new(workspace.project().clone(), log_set.clone(), cx)
})),
cx,
);
}
},
);
}
impl LogStore {
fn new(cx: &mut ModelContext<Self>) -> Self {
let (io_tx, mut io_rx) = mpsc::unbounded();
let this = Self {
projects: HashMap::default(),
io_tx,
};
cx.spawn_weak(|this, mut cx| async move {
while let Some((project, server_id, is_output, mut message)) = io_rx.next().await {
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
message.push('\n');
this.on_io(project, server_id, is_output, &message, cx);
});
}
}
anyhow::Ok(())
})
.detach();
this
}
pub fn has_enabled_logs_for_language_server(
&self,
project: &ModelHandle<Project>,
server_id: LanguageServerId,
) -> bool {
self.projects
.get(&project.downgrade())
.map_or(false, |store| store.servers.contains_key(&server_id))
}
pub fn enable_logs_for_language_server(
&mut self,
project: &ModelHandle<Project>,
server_id: LanguageServerId,
cx: &mut ModelContext<Self>,
) -> Option<ModelHandle<Buffer>> {
let server = project.read(cx).language_server_for_id(server_id)?;
let weak_project = project.downgrade();
let project_logs = match self.projects.entry(weak_project) {
hash_map::Entry::Occupied(entry) => entry.into_mut(),
hash_map::Entry::Vacant(entry) => entry.insert(LogStoreProject {
servers: HashMap::default(),
_subscription: cx.observe_release(&project, move |this, _, _| {
this.projects.remove(&weak_project);
}),
}),
};
let server_log_state = project_logs.servers.entry(server_id).or_insert_with(|| {
let io_tx = self.io_tx.clone();
let language = project.read(cx).languages().language_for_name("JSON");
let buffer = cx.add_model(|cx| Buffer::new(0, "", cx));
cx.spawn_weak({
let buffer = buffer.clone();
|_, mut cx| async move {
let language = language.await.ok();
buffer.update(&mut cx, |buffer, cx| {
buffer.set_language(language, cx);
});
}
})
.detach();
let project = project.downgrade();
LogStoreLanguageServer {
buffer,
last_message_kind: None,
_subscription: server.on_io(move |is_received, json| {
io_tx
.unbounded_send((project, server_id, is_received, json.to_string()))
.ok();
}),
}
});
Some(server_log_state.buffer.clone())
}
pub fn disable_logs_for_language_server(
&mut self,
project: &ModelHandle<Project>,
server_id: LanguageServerId,
_: &mut ModelContext<Self>,
) {
let project = project.downgrade();
if let Some(store) = self.projects.get_mut(&project) {
store.servers.remove(&server_id);
if store.servers.is_empty() {
self.projects.remove(&project);
}
}
}
fn on_io(
&mut self,
project: WeakModelHandle<Project>,
language_server_id: LanguageServerId,
is_received: bool,
message: &str,
cx: &mut AppContext,
) -> Option<()> {
let state = self
.projects
.get_mut(&project)?
.servers
.get_mut(&language_server_id)?;
state.buffer.update(cx, |buffer, cx| {
let kind = if is_received {
MessageKind::Receive
} else {
MessageKind::Send
};
if state.last_message_kind != Some(kind) {
let len = buffer.len();
let line = match kind {
MessageKind::Send => SEND_LINE,
MessageKind::Receive => RECEIVE_LINE,
};
buffer.edit([(len..len, line)], None, cx);
state.last_message_kind = Some(kind);
}
let len = buffer.len();
buffer.edit([(len..len, message)], None, cx);
});
Some(())
}
}
impl LspLogView {
fn new(
project: ModelHandle<Project>,
log_set: ModelHandle<LogStore>,
_: &mut ViewContext<Self>,
) -> Self {
Self {
project,
log_store: log_set,
editor: None,
current_server_id: None,
}
}
fn show_logs_for_server(&mut self, server_id: LanguageServerId, cx: &mut ViewContext<Self>) {
let buffer = self.log_store.update(cx, |log_set, cx| {
log_set.enable_logs_for_language_server(&self.project, server_id, cx)
});
if let Some(buffer) = buffer {
self.current_server_id = Some(server_id);
self.editor = Some(cx.add_view(|cx| {
let mut editor = Editor::for_buffer(buffer, Some(self.project.clone()), cx);
editor.set_read_only(true);
editor.move_to_end(&Default::default(), cx);
editor
}));
cx.notify();
}
}
fn toggle_logging_for_server(
&mut self,
server_id: LanguageServerId,
enabled: bool,
cx: &mut ViewContext<Self>,
) {
self.log_store.update(cx, |log_store, cx| {
if enabled {
log_store.enable_logs_for_language_server(&self.project, server_id, cx);
} else {
log_store.disable_logs_for_language_server(&self.project, server_id, cx);
}
});
}
}
impl View for LspLogView {
fn ui_name() -> &'static str {
"LspLogView"
}
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
if let Some(editor) = &self.editor {
ChildView::new(&editor, cx).into_any()
} else {
Empty::new().into_any()
}
}
}
impl Item for LspLogView {
fn tab_content<V: View>(
&self,
_: Option<usize>,
style: &theme::Tab,
_: &AppContext,
) -> AnyElement<V> {
Label::new("LSP Logs", style.label.clone()).into_any()
}
}
impl ToolbarItemView for LspLogToolbarItemView {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn ItemHandle>,
_: &mut ViewContext<Self>,
) -> workspace::ToolbarItemLocation {
self.menu_open = false;
if let Some(item) = active_pane_item {
if let Some(log_view) = item.downcast::<LspLogView>() {
self.log_view = Some(log_view.clone());
return ToolbarItemLocation::PrimaryLeft {
flex: Some((1., false)),
};
}
}
self.log_view = None;
ToolbarItemLocation::Hidden
}
}
impl View for LspLogToolbarItemView {
fn ui_name() -> &'static str {
"LspLogView"
}
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
let theme = cx.global::<Settings>().theme.clone();
let Some(log_view) = self.log_view.as_ref() else { return Empty::new().into_any() };
let project = self.project.read(cx);
let log_view = log_view.read(cx);
let log_store = log_view.log_store.read(cx);
let mut language_servers = project
.language_servers()
.map(|(id, name, worktree)| {
(
id,
name,
worktree,
log_store.has_enabled_logs_for_language_server(&self.project, id),
)
})
.collect::<Vec<_>>();
language_servers.sort_by_key(|a| (a.0, a.2));
language_servers.dedup_by_key(|a| a.0);
let current_server_id = log_view.current_server_id;
let current_server = current_server_id.and_then(|current_server_id| {
if let Ok(ix) = language_servers.binary_search_by_key(&current_server_id, |e| e.0) {
Some(language_servers[ix].clone())
} else {
None
}
});
enum Menu {}
Stack::new()
.with_child(Self::render_language_server_menu_header(
current_server,
&self.project,
&theme,
cx,
))
.with_children(if self.menu_open {
Some(
Overlay::new(
MouseEventHandler::<Menu, _>::new(0, cx, move |_, cx| {
Flex::column()
.with_children(language_servers.into_iter().filter_map(
|(id, name, worktree_id, logging_enabled)| {
Self::render_language_server_menu_item(
id,
name,
worktree_id,
logging_enabled,
Some(id) == current_server_id,
&self.project,
&theme,
cx,
)
},
))
.contained()
.with_style(theme.context_menu.container)
.constrained()
.with_width(400.)
.with_height(400.)
})
.on_down_out(MouseButton::Left, |_, this, cx| {
this.menu_open = false;
cx.notify()
}),
)
.with_fit_mode(OverlayFitMode::SwitchAnchor)
.with_anchor_corner(AnchorCorner::TopLeft)
.with_z_index(999)
.aligned()
.bottom()
.left(),
)
} else {
None
})
.aligned()
.left()
.clipped()
.into_any()
}
}
impl LspLogToolbarItemView {
pub fn new(project: ModelHandle<Project>) -> Self {
Self {
menu_open: false,
log_view: None,
project,
}
}
fn toggle_menu(&mut self, cx: &mut ViewContext<Self>) {
self.menu_open = !self.menu_open;
cx.notify();
}
fn toggle_logging_for_server(
&mut self,
id: LanguageServerId,
enabled: bool,
cx: &mut ViewContext<Self>,
) {
if let Some(log_view) = &self.log_view {
log_view.update(cx, |log_view, cx| {
log_view.toggle_logging_for_server(id, enabled, cx);
if !enabled && Some(id) == log_view.current_server_id {
log_view.current_server_id = None;
log_view.editor = None;
cx.notify();
}
});
}
cx.notify();
}
fn show_logs_for_server(&mut self, id: LanguageServerId, cx: &mut ViewContext<Self>) {
if let Some(log_view) = &self.log_view {
log_view.update(cx, |log_view, cx| {
log_view.show_logs_for_server(id, cx);
});
self.menu_open = false;
}
cx.notify();
}
fn render_language_server_menu_header(
current_server: Option<(LanguageServerId, LanguageServerName, WorktreeId, bool)>,
project: &ModelHandle<Project>,
theme: &Arc<Theme>,
cx: &mut ViewContext<Self>,
) -> impl Element<Self> {
enum ToggleMenu {}
MouseEventHandler::<ToggleMenu, Self>::new(0, cx, move |state, cx| {
let project = project.read(cx);
let label: Cow<str> = current_server
.and_then(|(_, server_name, worktree_id, _)| {
let worktree = project.worktree_for_id(worktree_id, cx)?;
let worktree = &worktree.read(cx);
Some(format!("{} - ({})", server_name.0, worktree.root_name()).into())
})
.unwrap_or_else(|| "No server selected".into());
Label::new(
label,
theme
.context_menu
.item
.style_for(state, false)
.label
.clone(),
)
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, view, cx| {
view.toggle_menu(cx);
})
}
fn render_language_server_menu_item(
id: LanguageServerId,
name: LanguageServerName,
worktree_id: WorktreeId,
logging_enabled: bool,
is_selected: bool,
project: &ModelHandle<Project>,
theme: &Arc<Theme>,
cx: &mut ViewContext<Self>,
) -> Option<impl Element<Self>> {
enum ActivateLog {}
let project = project.read(cx);
let worktree = project.worktree_for_id(worktree_id, cx)?;
let worktree = &worktree.read(cx);
if !worktree.is_visible() {
return None;
}
let label = format!("{} - ({})", name.0, worktree.root_name());
Some(
MouseEventHandler::<ActivateLog, _>::new(id.0, cx, move |state, cx| {
let item_style = theme.context_menu.item.style_for(state, is_selected);
Flex::row()
.with_child(ui::checkbox_with_label::<Self, _, Self, _>(
Empty::new(),
&theme.welcome.checkbox,
logging_enabled,
id.0,
cx,
move |this, enabled, cx| {
this.toggle_logging_for_server(id, enabled, cx);
},
))
.with_child(Label::new(label, item_style.label.clone()).aligned().left())
.align_children_center()
.contained()
.with_style(item_style.container)
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, view, cx| {
view.show_logs_for_server(id, cx);
}),
)
}
}
impl Entity for LogStore {
type Event = ();
}
impl Entity for LspLogView {
type Event = ();
}
impl Entity for LspLogToolbarItemView {
type Event = ();
}

View File

@ -9,7 +9,7 @@ path = "src/media.rs"
doctest = false
[dependencies]
anyhow = "1.0"
anyhow.workspace = true
block = "0.1"
bytes = "1.2"
core-foundation = "0.9.3"

View File

@ -13,10 +13,10 @@ gpui = { path = "../gpui" }
util = { path = "../util" }
async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] }
async-tar = "0.4.2"
futures = "0.3"
anyhow = "1.0.38"
parking_lot = "0.11.1"
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
smol = "1.2.5"
futures.workspace = true
anyhow.workspace = true
parking_lot.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
smol.workspace = true

View File

@ -17,6 +17,6 @@ picker = { path = "../picker" }
settings = { path = "../settings" }
text = { path = "../text" }
workspace = { path = "../workspace" }
ordered-float = "2.1.1"
postage = { workspace = true }
smol = "1.2"
ordered-float.workspace = true
postage.workspace = true
smol.workspace = true

View File

@ -17,11 +17,11 @@ util = { path = "../util" }
theme = { path = "../theme" }
workspace = { path = "../workspace" }
parking_lot = "0.11.1"
parking_lot.workspace = true
[dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] }
serde_json = { workspace = true }
serde_json.workspace = true
workspace = { path = "../workspace", features = ["test-support"] }
ctor = "0.1"
env_logger = "0.9"
ctor.workspace = true
env_logger.workspace = true

View File

@ -5,7 +5,7 @@ edition = "2021"
publish = false
[dependencies]
serde = { workspace = true }
serde_derive = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
bincode = "1.3"
plugin_macros = { path = "../plugin_macros" }

View File

@ -11,6 +11,6 @@ proc-macro = true
syn = { version = "1.0", features = ["full", "extra-traits"] }
quote = "1.0"
proc-macro2 = "1.0"
serde = { workspace = true }
serde_derive = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
bincode = "1.3"

View File

@ -8,13 +8,13 @@ publish = false
wasmtime = "0.38"
wasmtime-wasi = "0.38"
wasi-common = "0.38"
anyhow = { version = "1.0", features = ["std"] }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
anyhow.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
bincode = "1.3"
pollster = "0.2.5"
smol = "1.2.5"
smol.workspace = true
[build-dependencies]
wasmtime = { version = "0.38", features = ["all-arch"] }

View File

@ -38,30 +38,30 @@ sum_tree = { path = "../sum_tree" }
terminal = { path = "../terminal" }
util = { path = "../util" }
aho-corasick = "0.7"
anyhow = "1.0.57"
async-trait = "0.1"
anyhow.workspace = true
async-trait.workspace = true
backtrace = "0.3"
futures = "0.3"
futures.workspace = true
ignore = "0.4"
lazy_static = "1.4.0"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11.1"
postage = { workspace = true }
lazy_static.workspace = true
log.workspace = true
parking_lot.workspace = true
postage.workspace = true
pulldown-cmark = { version = "0.9.1", default-features = false }
rand = "0.8.3"
regex = "1.5"
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
rand.workspace = true
regex.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
sha2 = "0.10"
similar = "1.3"
smol = "1.2.5"
thiserror = "1.0.29"
smol.workspace = true
thiserror.workspace = true
toml = "0.5"
[dev-dependencies]
ctor = "0.1"
env_logger = "0.9"
ctor.workspace = true
env_logger.workspace = true
pretty_assertions = "1.3.0"
client = { path = "../client", features = ["test-support"] }
collections = { path = "../collections", features = ["test-support"] }
@ -73,5 +73,5 @@ lsp = { path = "../lsp", features = ["test-support"] }
settings = { path = "../settings", features = ["test-support"] }
util = { path = "../util", features = ["test-support"] }
rpc = { path = "../rpc", features = ["test-support"] }
tempdir = { version = "0.3.7" }
unindent = "0.1.7"
tempdir.workspace = true
unindent.workspace = true

View File

@ -93,7 +93,7 @@ pub trait Item {
pub struct Project {
worktrees: Vec<WorktreeHandle>,
active_entry: Option<ProjectEntryId>,
buffer_changes_tx: mpsc::UnboundedSender<BufferMessage>,
buffer_ordered_messages_tx: mpsc::UnboundedSender<BufferOrderedMessage>,
languages: Arc<LanguageRegistry>,
language_servers: HashMap<LanguageServerId, LanguageServerState>,
language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>,
@ -137,11 +137,16 @@ struct LspBufferSnapshot {
snapshot: TextBufferSnapshot,
}
enum BufferMessage {
/// Message ordered with respect to buffer operations
enum BufferOrderedMessage {
Operation {
buffer_id: u64,
operation: proto::Operation,
},
LanguageServerUpdate {
language_server_id: LanguageServerId,
message: proto::update_language_server::Variant,
},
Resync,
}
@ -185,6 +190,8 @@ pub struct Collaborator {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event {
LanguageServerAdded(LanguageServerId),
LanguageServerRemoved(LanguageServerId),
ActiveEntryChanged(Option<ProjectEntryId>),
WorktreeAdded,
WorktreeRemoved(WorktreeId),
@ -441,11 +448,11 @@ impl Project {
) -> ModelHandle<Self> {
cx.add_model(|cx: &mut ModelContext<Self>| {
let (tx, rx) = mpsc::unbounded();
cx.spawn_weak(|this, cx| Self::send_buffer_messages(this, rx, cx))
cx.spawn_weak(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
.detach();
Self {
worktrees: Default::default(),
buffer_changes_tx: tx,
buffer_ordered_messages_tx: tx,
collaborators: Default::default(),
opened_buffers: Default::default(),
shared_buffers: Default::default(),
@ -509,11 +516,11 @@ impl Project {
}
let (tx, rx) = mpsc::unbounded();
cx.spawn_weak(|this, cx| Self::send_buffer_messages(this, rx, cx))
cx.spawn_weak(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
.detach();
let mut this = Self {
worktrees: Vec::new(),
buffer_changes_tx: tx,
buffer_ordered_messages_tx: tx,
loading_buffers_by_path: Default::default(),
opened_buffer: watch::channel(),
shared_buffers: Default::default(),
@ -1166,8 +1173,8 @@ impl Project {
)
})
.collect();
self.buffer_changes_tx
.unbounded_send(BufferMessage::Resync)
self.buffer_ordered_messages_tx
.unbounded_send(BufferOrderedMessage::Resync)
.unwrap();
cx.notify();
Ok(())
@ -1782,23 +1789,49 @@ impl Project {
}
}
async fn send_buffer_messages(
async fn send_buffer_ordered_messages(
this: WeakModelHandle<Self>,
rx: UnboundedReceiver<BufferMessage>,
rx: UnboundedReceiver<BufferOrderedMessage>,
mut cx: AsyncAppContext,
) -> Option<()> {
const MAX_BATCH_SIZE: usize = 128;
let mut needs_resync_with_host = false;
let mut operations_by_buffer_id = HashMap::default();
async fn flush_operations(
this: &ModelHandle<Project>,
operations_by_buffer_id: &mut HashMap<u64, Vec<proto::Operation>>,
needs_resync_with_host: &mut bool,
is_local: bool,
cx: &AsyncAppContext,
) {
for (buffer_id, operations) in operations_by_buffer_id.drain() {
let request = this.read_with(cx, |this, _| {
let project_id = this.remote_id()?;
Some(this.client.request(proto::UpdateBuffer {
buffer_id,
project_id,
operations,
}))
});
if let Some(request) = request {
if request.await.is_err() && !is_local {
*needs_resync_with_host = true;
break;
}
}
}
}
let mut needs_resync_with_host = false;
let mut changes = rx.ready_chunks(MAX_BATCH_SIZE);
while let Some(changes) = changes.next().await {
let this = this.upgrade(&mut cx)?;
let is_local = this.read_with(&cx, |this, _| this.is_local());
for change in changes {
match change {
BufferMessage::Operation {
BufferOrderedMessage::Operation {
buffer_id,
operation,
} => {
@ -1811,7 +1844,8 @@ impl Project {
.or_insert(Vec::new())
.push(operation);
}
BufferMessage::Resync => {
BufferOrderedMessage::Resync => {
operations_by_buffer_id.clear();
if this
.update(&mut cx, |this, cx| this.synchronize_remote_buffers(cx))
@ -1821,25 +1855,43 @@ impl Project {
needs_resync_with_host = false;
}
}
}
}
for (buffer_id, operations) in operations_by_buffer_id.drain() {
let request = this.read_with(&cx, |this, _| {
let project_id = this.remote_id()?;
Some(this.client.request(proto::UpdateBuffer {
buffer_id,
project_id,
operations,
}))
});
if let Some(request) = request {
if request.await.is_err() && !is_local {
needs_resync_with_host = true;
break;
BufferOrderedMessage::LanguageServerUpdate {
language_server_id,
message,
} => {
flush_operations(
&this,
&mut operations_by_buffer_id,
&mut needs_resync_with_host,
is_local,
&cx,
)
.await;
this.read_with(&cx, |this, _| {
if let Some(project_id) = this.remote_id() {
this.client
.send(proto::UpdateLanguageServer {
project_id,
language_server_id: language_server_id.0 as u64,
variant: Some(message),
})
.log_err();
}
});
}
}
}
flush_operations(
&this,
&mut operations_by_buffer_id,
&mut needs_resync_with_host,
is_local,
&cx,
)
.await;
}
None
@ -1853,8 +1905,8 @@ impl Project {
) -> Option<()> {
match event {
BufferEvent::Operation(operation) => {
self.buffer_changes_tx
.unbounded_send(BufferMessage::Operation {
self.buffer_ordered_messages_tx
.unbounded_send(BufferOrderedMessage::Operation {
buffer_id: buffer.read(cx).remote_id(),
operation: language::proto::serialize_operation(operation),
})
@ -1869,7 +1921,7 @@ impl Project {
let next_snapshot = buffer.text_snapshot();
let language_servers: Vec<_> = self
.language_servers_iter_for_buffer(buffer, cx)
.language_servers_for_buffer(buffer, cx)
.map(|i| i.1.clone())
.collect();
@ -1960,19 +2012,24 @@ impl Project {
Duration::from_secs(1);
let task = cx.spawn_weak(|this, mut cx| async move {
cx.background().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await;
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx | {
this.disk_based_diagnostics_finished(language_server_id, cx);
this.broadcast_language_server_update(
language_server_id,
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
proto::LspDiskBasedDiagnosticsUpdated {},
),
);
});
}
});
cx.background().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await;
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
this.disk_based_diagnostics_finished(
language_server_id,
cx,
);
this.buffer_ordered_messages_tx
.unbounded_send(
BufferOrderedMessage::LanguageServerUpdate {
language_server_id,
message:proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(Default::default())
},
)
.ok();
});
}
});
*simulate_disk_based_diagnostics_completion = Some(task);
}
}
@ -2607,7 +2664,7 @@ impl Project {
fn on_lsp_progress(
&mut self,
progress: lsp::ProgressParams,
server_id: LanguageServerId,
language_server_id: LanguageServerId,
disk_based_diagnostics_progress_token: Option<String>,
cx: &mut ModelContext<Self>,
) {
@ -2620,7 +2677,7 @@ impl Project {
};
let lsp::ProgressParamsValue::WorkDone(progress) = progress.value;
let language_server_status =
if let Some(status) = self.language_server_statuses.get_mut(&server_id) {
if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
status
} else {
return;
@ -2640,16 +2697,16 @@ impl Project {
lsp::WorkDoneProgress::Begin(report) => {
if is_disk_based_diagnostics_progress {
language_server_status.has_pending_diagnostic_updates = true;
self.disk_based_diagnostics_started(server_id, cx);
self.broadcast_language_server_update(
server_id,
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
proto::LspDiskBasedDiagnosticsUpdating {},
),
);
self.disk_based_diagnostics_started(language_server_id, cx);
self.buffer_ordered_messages_tx
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
language_server_id,
message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(Default::default())
})
.ok();
} else {
self.on_lsp_work_start(
server_id,
language_server_id,
token.clone(),
LanguageServerProgress {
message: report.message.clone(),
@ -2658,20 +2715,24 @@ impl Project {
},
cx,
);
self.broadcast_language_server_update(
server_id,
proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
token,
message: report.message,
percentage: report.percentage.map(|p| p as u32),
}),
);
self.buffer_ordered_messages_tx
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
language_server_id,
message: proto::update_language_server::Variant::WorkStart(
proto::LspWorkStart {
token,
message: report.message,
percentage: report.percentage.map(|p| p as u32),
},
),
})
.ok();
}
}
lsp::WorkDoneProgress::Report(report) => {
if !is_disk_based_diagnostics_progress {
self.on_lsp_work_progress(
server_id,
language_server_id,
token.clone(),
LanguageServerProgress {
message: report.message.clone(),
@ -2680,16 +2741,18 @@ impl Project {
},
cx,
);
self.broadcast_language_server_update(
server_id,
proto::update_language_server::Variant::WorkProgress(
proto::LspWorkProgress {
token,
message: report.message,
percentage: report.percentage.map(|p| p as u32),
},
),
);
self.buffer_ordered_messages_tx
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
language_server_id,
message: proto::update_language_server::Variant::WorkProgress(
proto::LspWorkProgress {
token,
message: report.message,
percentage: report.percentage.map(|p| p as u32),
},
),
})
.ok();
}
}
lsp::WorkDoneProgress::End(_) => {
@ -2697,21 +2760,26 @@ impl Project {
if is_disk_based_diagnostics_progress {
language_server_status.has_pending_diagnostic_updates = false;
self.disk_based_diagnostics_finished(server_id, cx);
self.broadcast_language_server_update(
server_id,
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
proto::LspDiskBasedDiagnosticsUpdated {},
),
);
self.disk_based_diagnostics_finished(language_server_id, cx);
self.buffer_ordered_messages_tx
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
language_server_id,
message:
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
Default::default(),
),
})
.ok();
} else {
self.on_lsp_work_end(server_id, token.clone(), cx);
self.broadcast_language_server_update(
server_id,
proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
token,
}),
);
self.on_lsp_work_end(language_server_id, token.clone(), cx);
self.buffer_ordered_messages_tx
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
language_server_id,
message: proto::update_language_server::Variant::WorkEnd(
proto::LspWorkEnd { token },
),
})
.ok();
}
}
}
@ -2820,22 +2888,6 @@ impl Project {
})
}
fn broadcast_language_server_update(
&self,
language_server_id: LanguageServerId,
event: proto::update_language_server::Variant,
) {
if let Some(project_id) = self.remote_id() {
self.client
.send(proto::UpdateLanguageServer {
project_id,
language_server_id: language_server_id.0 as u64,
variant: Some(event),
})
.log_err();
}
}
pub fn language_server_statuses(
&self,
) -> impl DoubleEndedIterator<Item = &LanguageServerStatus> {
@ -4864,8 +4916,8 @@ impl Project {
if is_host {
this.opened_buffers
.retain(|_, buffer| !matches!(buffer, OpenBuffer::Operations(_)));
this.buffer_changes_tx
.unbounded_send(BufferMessage::Resync)
this.buffer_ordered_messages_tx
.unbounded_send(BufferOrderedMessage::Resync)
.unwrap();
}
@ -6279,7 +6331,25 @@ impl Project {
}
}
pub fn language_servers_iter_for_buffer(
pub fn language_servers(
&self,
) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName, WorktreeId)> {
self.language_server_ids
.iter()
.map(|((worktree_id, server_name), server_id)| {
(*server_id, server_name.clone(), *worktree_id)
})
}
pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
if let LanguageServerState::Running { server, .. } = self.language_servers.get(&id)? {
Some(server.clone())
} else {
None
}
}
pub fn language_servers_for_buffer(
&self,
buffer: &Buffer,
cx: &AppContext,
@ -6299,20 +6369,12 @@ impl Project {
})
}
fn language_servers_for_buffer(
&self,
buffer: &Buffer,
cx: &AppContext,
) -> Vec<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
self.language_servers_iter_for_buffer(buffer, cx).collect()
}
fn primary_language_servers_for_buffer(
&self,
buffer: &Buffer,
cx: &AppContext,
) -> Option<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
self.language_servers_iter_for_buffer(buffer, cx).next()
self.language_servers_for_buffer(buffer, cx).next()
}
fn language_server_for_buffer(
@ -6321,7 +6383,7 @@ impl Project {
server_id: LanguageServerId,
cx: &AppContext,
) -> Option<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
self.language_servers_iter_for_buffer(buffer, cx)
self.language_servers_for_buffer(buffer, cx)
.find(|(_, s)| s.server_id() == server_id)
}

View File

@ -19,12 +19,12 @@ settings = { path = "../settings" }
theme = { path = "../theme" }
util = { path = "../util" }
workspace = { path = "../workspace" }
postage = { workspace = true }
futures = "0.3"
postage.workspace = true
futures.workspace = true
unicase = "2.6"
[dev-dependencies]
editor = { path = "../editor", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
workspace = { path = "../workspace", features = ["test-support"] }
serde_json = { workspace = true }
serde_json.workspace = true

View File

@ -18,13 +18,13 @@ text = { path = "../text" }
settings = { path = "../settings" }
workspace = { path = "../workspace" }
util = { path = "../util" }
anyhow = "1.0.38"
ordered-float = "2.1.1"
postage = { workspace = true }
smol = "1.2"
anyhow.workspace = true
ordered-float.workspace = true
postage.workspace = true
smol.workspace = true
[dev-dependencies]
futures = "0.3"
futures.workspace = true
settings = { path = "../settings", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
language = { path = "../language", features = ["test-support"] }

View File

@ -17,8 +17,9 @@ language = { path = "../language" }
picker = { path = "../picker" }
settings = { path = "../settings" }
text = { path = "../text" }
workspace = { path = "../workspace" }
ordered-float = "2.1.1"
postage = { workspace = true }
smol = "1.2"
util = { path = "../util"}
workspace = { path = "../workspace" }
ordered-float.workspace = true
postage.workspace = true
smol.workspace = true

View File

@ -9,13 +9,13 @@ path = "src/rope.rs"
[dependencies]
bromberg_sl2 = { git = "https://github.com/zed-industries/bromberg_sl2", rev = "950bc5482c216c395049ae33ae4501e08975f17f" }
smallvec = { workspace = true }
smallvec.workspace = true
sum_tree = { path = "../sum_tree" }
arrayvec = "0.7.1"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
log.workspace = true
util = { path = "../util" }
[dev-dependencies]
rand = "0.8.3"
rand.workspace = true
util = { path = "../util", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }

View File

@ -17,17 +17,17 @@ clock = { path = "../clock" }
collections = { path = "../collections" }
gpui = { path = "../gpui", optional = true }
util = { path = "../util" }
anyhow = "1.0"
anyhow.workspace = true
async-lock = "2.4"
async-tungstenite = "0.16"
base64 = "0.13"
futures = "0.3"
parking_lot = "0.11.1"
futures.workspace = true
parking_lot.workspace = true
prost = "0.8"
rand = "0.8"
rand.workspace = true
rsa = "0.4"
serde = { workspace = true }
serde_derive = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
smol-timeout = "0.6"
tracing = { version = "0.1.34", features = ["log"] }
zstd = "0.11"
@ -38,7 +38,7 @@ prost-build = "0.9"
[dev-dependencies]
collections = { path = "../collections", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
smol = "1.2.5"
tempdir = "0.3.7"
ctor = "0.1"
env_logger = "0.9"
smol.workspace = true
tempdir.workspace = true
ctor.workspace = true
env_logger.workspace = true

View File

@ -240,13 +240,13 @@ message ParticipantLocation {
UnsharedProject unshared_project = 2;
External external = 3;
}
message SharedProject {
uint64 id = 1;
}
message UnsharedProject {}
message External {}
}

View File

@ -19,18 +19,18 @@ settings = { path = "../settings" }
theme = { path = "../theme" }
util = { path = "../util" }
workspace = { path = "../workspace" }
anyhow = "1.0"
futures = "0.3"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
postage = { workspace = true }
serde = { workspace = true }
serde_derive = { workspace = true }
smallvec = { workspace = true }
smol = "1.2"
anyhow.workspace = true
futures.workspace = true
log.workspace = true
postage.workspace = true
serde.workspace = true
serde_derive.workspace = true
smallvec.workspace = true
smol.workspace = true
[dev-dependencies]
editor = { path = "../editor", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
serde_json = { workspace = true }
serde_json.workspace = true
workspace = { path = "../workspace", features = ["test-support"] }
unindent = "0.1"
unindent.workspace = true

View File

@ -85,6 +85,7 @@ pub struct ProjectSearchView {
query_contains_error: bool,
active_match_index: Option<usize>,
search_id: usize,
query_editor_was_focused: bool,
}
pub struct ProjectSearchBar {
@ -218,7 +219,11 @@ impl View for ProjectSearchView {
});
if cx.is_self_focused() {
self.focus_query_editor(cx);
if self.query_editor_was_focused {
cx.focus(&self.query_editor);
} else {
cx.focus(&self.results_editor);
}
}
}
}
@ -448,6 +453,7 @@ impl ProjectSearchView {
regex,
query_contains_error: false,
active_match_index: None,
query_editor_was_focused: false,
};
this.model_changed(cx);
this
@ -549,10 +555,11 @@ impl ProjectSearchView {
}
}
fn focus_query_editor(&self, cx: &mut ViewContext<Self>) {
fn focus_query_editor(&mut self, cx: &mut ViewContext<Self>) {
self.query_editor.update(cx, |query_editor, cx| {
query_editor.select_all(&SelectAll, cx);
});
self.query_editor_was_focused = true;
cx.focus(&self.query_editor);
}
@ -561,11 +568,12 @@ impl ProjectSearchView {
.update(cx, |query_editor, cx| query_editor.set_text(query, cx));
}
fn focus_results_editor(&self, cx: &mut ViewContext<Self>) {
fn focus_results_editor(&mut self, cx: &mut ViewContext<Self>) {
self.query_editor.update(cx, |query_editor, cx| {
let cursor = query_editor.selections.newest_anchor().head();
query_editor.change_selections(None, cx, |s| s.select_ranges([cursor.clone()..cursor]));
});
self.query_editor_was_focused = false;
cx.focus(&self.results_editor);
}

View File

@ -17,24 +17,26 @@ collections = { path = "../collections" }
gpui = { path = "../gpui" }
sqlez = { path = "../sqlez" }
fs = { path = "../fs" }
anyhow = "1.0.38"
futures = "0.3"
anyhow.workspace = true
futures.workspace = true
theme = { path = "../theme" }
staff_mode = { path = "../staff_mode" }
util = { path = "../util" }
json_comments = "0.2"
postage = { workspace = true }
postage.workspace = true
schemars = "0.8"
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
serde_path_to_error = "0.1.4"
toml = "0.5"
tree-sitter = "*"
tree-sitter-json = "*"
[dev-dependencies]
unindent = "0.1"
gpui = { path = "../gpui", features = ["test-support"] }
fs = { path = "../fs", features = ["test-support"] }
pretty_assertions = "1.3.0"
unindent.workspace = true

View File

@ -9,5 +9,5 @@ path = "src/snippet.rs"
doctest = false
[dependencies]
anyhow = "1.0"
smallvec = { workspace = true }
anyhow.workspace = true
smallvec.workspace = true

View File

@ -4,15 +4,13 @@ version = "0.1.0"
edition = "2021"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = { version = "1.0.38", features = ["backtrace"] }
anyhow.workspace = true
indoc = "1.0.7"
libsqlite3-sys = { version = "0.24", features = ["bundled"] }
smol = "1.2"
smol.workspace = true
thread_local = "1.1.4"
lazy_static = "1.4"
parking_lot = "0.11.1"
futures = "0.3"
uuid = { version = "1.1.2", features = ["v4"] }
lazy_static.workspace = true
parking_lot.workspace = true
futures.workspace = true
uuid = { version = "1.1.2", features = ["v4"] }

View File

@ -13,6 +13,6 @@ doctest = false
syn = "1.0"
quote = "1.0"
proc-macro2 = "1.0"
lazy_static = "1.4"
lazy_static.workspace = true
sqlez = { path = "../sqlez" }
sqlformat = "0.2"
sqlformat = "0.2"

View File

@ -9,4 +9,4 @@ path = "src/staff_mode.rs"
[dependencies]
gpui = { path = "../gpui" }
anyhow = "1.0.38"
anyhow.workspace = true

View File

@ -10,9 +10,9 @@ doctest = false
[dependencies]
arrayvec = "0.7.1"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
log.workspace = true
[dev-dependencies]
ctor = "0.1"
env_logger = "0.9"
rand = "0.8.3"
ctor.workspace = true
env_logger.workspace = true
rand.workspace = true

View File

@ -17,20 +17,20 @@ theme = { path = "../theme" }
util = { path = "../util" }
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "a51dbe25d67e84d6ed4261e640d3954fbdd9be45" }
procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "5cd757e5f2eb039ed0c6bb6512223e69d5efc64d", default-features = false }
smallvec = { workspace = true }
smol = "1.2.5"
smallvec.workspace = true
smol.workspace = true
mio-extras = "2.0.6"
futures = "0.3"
ordered-float = "2.1.1"
futures.workspace = true
ordered-float.workspace = true
itertools = "0.10"
dirs = "4.0.0"
shellexpand = "2.1.0"
libc = "0.2"
anyhow = "1"
thiserror = "1.0"
lazy_static = "1.4.0"
serde = { workspace = true }
serde_derive = { workspace = true }
anyhow.workspace = true
thiserror.workspace = true
lazy_static.workspace = true
serde.workspace = true
serde_derive.workspace = true
[dev-dependencies]
rand = "0.8.5"
rand.workspace = true

View File

@ -31,6 +31,7 @@ use mappings::mouse::{
};
use procinfo::LocalProcessInfo;
use serde::{Deserialize, Serialize};
use settings::{AlternateScroll, Settings, Shell, TerminalBlink};
use util::truncate_and_trailoff;
@ -113,7 +114,7 @@ impl EventListener for ZedListener {
}
}
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct TerminalSize {
pub cell_width: f32,
pub line_height: f32,
@ -441,7 +442,7 @@ impl TerminalBuilder {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct IndexedCell {
pub point: Point,
pub cell: Cell,
@ -664,6 +665,7 @@ impl Terminal {
self.last_content.size,
term.grid().display_offset(),
);
let side = mouse_side(*position, self.last_content.size);
selection.update(point, side);
@ -1024,6 +1026,8 @@ impl Terminal {
self.last_content.size,
self.last_content.display_offset,
);
// Use .opposite so that selection is inclusive of the cell clicked.
let side = mouse_side(position, self.last_content.size);
let selection_type = match e.click_count {
@ -1074,7 +1078,7 @@ impl Terminal {
//Hyperlinks
if self.selection_phase == SelectionPhase::Ended {
let mouse_cell_index = content_index_for_mouse(position, &self.last_content);
let mouse_cell_index = content_index_for_mouse(position, &self.last_content.size);
if let Some(link) = self.last_content.cells[mouse_cell_index].hyperlink() {
cx.platform().open_url(link.uri());
} else {
@ -1254,17 +1258,16 @@ fn all_search_matches<'a, T>(
RegexIter::new(start, end, AlacDirection::Right, term, regex)
}
fn content_index_for_mouse<'a>(pos: Vector2F, content: &'a TerminalContent) -> usize {
let col = min(
(pos.x() / content.size.cell_width()) as usize,
content.size.columns() - 1,
) as usize;
let line = min(
(pos.y() / content.size.line_height()) as usize,
content.size.screen_lines() - 1,
) as usize;
fn content_index_for_mouse(pos: Vector2F, size: &TerminalSize) -> usize {
let col = (pos.x() / size.cell_width()).round() as usize;
line * content.size.columns() + col
let clamped_col = min(col, size.columns() - 1);
let row = (pos.y() / size.line_height()).round() as usize;
let clamped_row = min(row, size.screen_lines() - 1);
clamped_row * size.columns() + clamped_col
}
#[cfg(test)]
@ -1274,17 +1277,19 @@ mod tests {
term::cell::Cell,
};
use gpui::geometry::vector::vec2f;
use rand::{rngs::ThreadRng, thread_rng, Rng};
use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng};
use crate::{content_index_for_mouse, IndexedCell, TerminalContent, TerminalSize};
#[test]
fn test_mouse_to_cell() {
fn test_mouse_to_cell_test() {
let mut rng = thread_rng();
const ITERATIONS: usize = 10;
const PRECISION: usize = 1000;
for _ in 0..10 {
let viewport_cells = rng.gen_range(5..50);
let cell_size = rng.gen_range(5.0..20.0);
for _ in 0..ITERATIONS {
let viewport_cells = rng.gen_range(15..20);
let cell_size = rng.gen_range(5 * PRECISION..20 * PRECISION) as f32 / PRECISION as f32;
let size = crate::TerminalSize {
cell_width: cell_size,
@ -1293,26 +1298,27 @@ mod tests {
width: cell_size * (viewport_cells as f32),
};
let (content, cells) = create_terminal_content(size, &mut rng);
let cells = get_cells(size, &mut rng);
let content = convert_cells_to_content(size, &cells);
for i in 0..(viewport_cells - 1) {
let i = i as usize;
for j in 0..(viewport_cells - 1) {
let j = j as usize;
let min_row = i as f32 * cell_size;
let max_row = (i + 1) as f32 * cell_size;
let min_col = j as f32 * cell_size;
let max_col = (j + 1) as f32 * cell_size;
for row in 0..(viewport_cells - 1) {
let row = row as usize;
for col in 0..(viewport_cells - 1) {
let col = col as usize;
let row_offset = rng.gen_range(0..PRECISION) as f32 / PRECISION as f32;
let col_offset = rng.gen_range(0..PRECISION) as f32 / PRECISION as f32;
let mouse_pos = vec2f(
rng.gen_range(min_row..max_row),
rng.gen_range(min_col..max_col),
col as f32 * cell_size + col_offset,
row as f32 * cell_size + row_offset,
);
assert_eq!(
content.cells[content_index_for_mouse(mouse_pos, &content)].c,
cells[j][i]
);
let content_index = content_index_for_mouse(mouse_pos, &content.size);
let mouse_cell = content.cells[content_index].c;
let real_cell = cells[row][col];
assert_eq!(mouse_cell, real_cell);
}
}
}
@ -1329,29 +1335,40 @@ mod tests {
width: 100.,
};
let (content, cells) = create_terminal_content(size, &mut rng);
let cells = get_cells(size, &mut rng);
let content = convert_cells_to_content(size, &cells);
assert_eq!(
content.cells[content_index_for_mouse(vec2f(-10., -10.), &content)].c,
content.cells[content_index_for_mouse(vec2f(-10., -10.), &content.size)].c,
cells[0][0]
);
assert_eq!(
content.cells[content_index_for_mouse(vec2f(1000., 1000.), &content)].c,
content.cells[content_index_for_mouse(vec2f(1000., 1000.), &content.size)].c,
cells[9][9]
);
}
fn create_terminal_content(
size: TerminalSize,
rng: &mut ThreadRng,
) -> (TerminalContent, Vec<Vec<char>>) {
let mut ic = Vec::new();
fn get_cells(size: TerminalSize, rng: &mut ThreadRng) -> Vec<Vec<char>> {
let mut cells = Vec::new();
for row in 0..((size.height() / size.line_height()) as usize) {
for _ in 0..((size.height() / size.line_height()) as usize) {
let mut row_vec = Vec::new();
for col in 0..((size.width() / size.cell_width()) as usize) {
let cell_char = rng.gen();
for _ in 0..((size.width() / size.cell_width()) as usize) {
let cell_char = rng.sample(Alphanumeric) as char;
row_vec.push(cell_char)
}
cells.push(row_vec)
}
cells
}
fn convert_cells_to_content(size: TerminalSize, cells: &Vec<Vec<char>>) -> TerminalContent {
let mut ic = Vec::new();
for row in 0..cells.len() {
for col in 0..cells[row].len() {
let cell_char = cells[row][col];
ic.push(IndexedCell {
point: Point::new(Line(row as i32), Column(col)),
cell: Cell {
@ -1359,18 +1376,13 @@ mod tests {
..Default::default()
},
});
row_vec.push(cell_char)
}
cells.push(row_vec)
}
(
TerminalContent {
cells: ic,
size,
..Default::default()
},
cells,
)
TerminalContent {
cells: ic,
size,
..Default::default()
}
}
}

View File

@ -21,20 +21,20 @@ workspace = { path = "../workspace" }
db = { path = "../db" }
procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "5cd757e5f2eb039ed0c6bb6512223e69d5efc64d", default-features = false }
terminal = { path = "../terminal" }
smallvec = { workspace = true }
smol = "1.2.5"
smallvec.workspace = true
smol.workspace = true
mio-extras = "2.0.6"
futures = "0.3"
ordered-float = "2.1.1"
futures.workspace = true
ordered-float.workspace = true
itertools = "0.10"
dirs = "4.0.0"
shellexpand = "2.1.0"
libc = "0.2"
anyhow = "1"
thiserror = "1.0"
lazy_static = "1.4.0"
serde = { workspace = true }
serde_derive = { workspace = true }
anyhow.workspace = true
thiserror.workspace = true
lazy_static.workspace = true
serde.workspace = true
serde_derive.workspace = true
@ -43,4 +43,4 @@ gpui = { path = "../gpui", features = ["test-support"] }
client = { path = "../client", features = ["test-support"]}
project = { path = "../project", features = ["test-support"]}
workspace = { path = "../workspace", features = ["test-support"] }
rand = "0.8.5"
rand.workspace = true

View File

@ -46,6 +46,7 @@ pub struct LayoutState {
mode: TermMode,
display_offset: usize,
hyperlink_tooltip: Option<AnyElement<TerminalView>>,
gutter: f32,
}
///Helper struct for converting data between alacritty's cursor points, and displayed cursor points
@ -572,10 +573,14 @@ impl Element<TerminalView> for TerminalElement {
let text_style = TerminalElement::make_text_style(font_cache, settings);
let selection_color = settings.theme.editor.selection.selection;
let match_color = settings.theme.search.match_background;
let gutter;
let dimensions = {
let line_height = text_style.font_size * settings.terminal_line_height();
let cell_width = font_cache.em_advance(text_style.font_id, text_style.font_size);
TerminalSize::new(line_height, cell_width, constraint.max)
gutter = cell_width;
let size = constraint.max - vec2f(gutter, 0.);
TerminalSize::new(line_height, cell_width, size)
};
let search_matches = if let Some(terminal_model) = self.terminal.upgrade(cx) {
@ -713,6 +718,7 @@ impl Element<TerminalView> for TerminalElement {
mode: *mode,
display_offset: *display_offset,
hyperlink_tooltip,
gutter,
},
)
}
@ -732,7 +738,7 @@ impl Element<TerminalView> for TerminalElement {
let clip_bounds = Some(visible_bounds);
scene.paint_layer(clip_bounds, |scene| {
let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.);
let origin = bounds.origin() + vec2f(layout.gutter, 0.);
// Elements are ephemeral, only at paint time do we know what could be clicked by a mouse
self.attach_mouse_handlers(scene, origin, visible_bounds, layout.mode, cx);

View File

@ -17,21 +17,21 @@ collections = { path = "../collections" }
fs = { path = "../fs" }
rope = { path = "../rope" }
sum_tree = { path = "../sum_tree" }
anyhow = "1.0.38"
digest = { version = "0.9", features = ["std"] }
lazy_static = "1.4"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11"
postage = { workspace = true }
rand = { version = "0.8.3", optional = true }
smallvec = { workspace = true }
util = { path = "../util" }
regex = "1.5"
anyhow.workspace = true
digest = { version = "0.9", features = ["std"] }
lazy_static.workspace = true
log.workspace = true
parking_lot.workspace = true
postage.workspace = true
rand = { workspace = true, optional = true }
smallvec.workspace = true
regex.workspace = true
[dev-dependencies]
collections = { path = "../collections", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
ctor = "0.1"
env_logger = "0.9"
rand = "0.8.3"
ctor.workspace = true
env_logger.workspace = true
rand.workspace = true

View File

@ -10,11 +10,11 @@ doctest = false
[dependencies]
gpui = { path = "../gpui" }
anyhow = "1.0.38"
anyhow.workspace = true
indexmap = "1.6.2"
parking_lot = "0.11.1"
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
parking_lot.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
serde_path_to_error = "0.1.4"
toml = "0.5"

View File

@ -27,28 +27,40 @@ pub struct CheckboxStyle {
pub hovered_and_checked: ContainerStyle,
}
pub fn checkbox<Tag: 'static, V: View>(
pub fn checkbox<Tag, V, F>(
label: &'static str,
style: &CheckboxStyle,
checked: bool,
id: usize,
cx: &mut ViewContext<V>,
change: fn(checked: bool, cx: &mut EventContext<V>) -> (),
) -> MouseEventHandler<Tag, V> {
change: F,
) -> MouseEventHandler<Tag, V>
where
Tag: 'static,
V: View,
F: 'static + Fn(&mut V, bool, &mut EventContext<V>),
{
let label = Label::new(label, style.label.text.clone())
.contained()
.with_style(style.label.container);
checkbox_with_label(label, style, checked, cx, change)
checkbox_with_label(label, style, checked, id, cx, change)
}
pub fn checkbox_with_label<Tag: 'static, D: Element<V>, V: View>(
pub fn checkbox_with_label<Tag, D, V, F>(
label: D,
style: &CheckboxStyle,
checked: bool,
id: usize,
cx: &mut ViewContext<V>,
change: fn(checked: bool, cx: &mut EventContext<V>) -> (),
) -> MouseEventHandler<Tag, V> {
MouseEventHandler::new(0, cx, |state, _| {
change: F,
) -> MouseEventHandler<Tag, V>
where
Tag: 'static,
D: Element<V>,
V: View,
F: 'static + Fn(&mut V, bool, &mut EventContext<V>),
{
MouseEventHandler::new(id, cx, |state, _| {
let indicator = if checked {
svg(&style.icon)
} else {
@ -75,8 +87,8 @@ pub fn checkbox_with_label<Tag: 'static, D: Element<V>, V: View>(
.with_child(label)
.align_children_center()
})
.on_click(platform::MouseButton::Left, move |_, _, cx| {
change(!checked, cx)
.on_click(platform::MouseButton::Left, move |_, view, cx| {
change(view, !checked, cx)
})
.with_cursor_style(platform::CursorStyle::PointingHand)
}

View File

@ -18,7 +18,7 @@ settings = { path = "../settings" }
staff_mode = { path = "../staff_mode" }
workspace = { path = "../workspace" }
util = { path = "../util" }
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11.1"
postage = { workspace = true }
smol = "1.2.5"
log.workspace = true
parking_lot.workspace = true
postage.workspace = true
smol.workspace = true

View File

@ -16,4 +16,4 @@ settings = { path = "../settings" }
workspace = { path = "../workspace" }
project = { path = "../project" }
smallvec = { workspace = true }
smallvec.workspace = true

View File

@ -12,21 +12,21 @@ doctest = true
test-support = ["tempdir", "git2"]
[dependencies]
anyhow = "1.0.38"
anyhow.workspace = true
backtrace = "0.3"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
lazy_static = "1.4.0"
futures = "0.3"
log.workspace = true
lazy_static.workspace = true
futures.workspace = true
isahc = "1.7"
smol = "1.2.5"
smol.workspace = true
url = "2.2"
rand = { workspace = true }
tempdir = { version = "0.3.7", optional = true }
serde = { workspace = true }
serde_json = { workspace = true }
rand.workspace = true
tempdir = { workspace = true, optional = true }
serde.workspace = true
serde_json.workspace = true
git2 = { version = "0.15", default-features = false, optional = true }
dirs = "3.0"
[dev-dependencies]
tempdir = { version = "0.3.7" }
tempdir.workspace = true
git2 = { version = "0.15", default-features = false }

View File

@ -12,16 +12,16 @@ doctest = false
neovim = ["nvim-rs", "async-compat", "async-trait", "tokio"]
[dependencies]
serde = { workspace = true }
serde_derive = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
itertools = "0.10"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
log.workspace = true
async-compat = { version = "0.2.1", "optional" = true }
async-trait = { version = "0.1", "optional" = true }
async-trait = { workspace = true, "optional" = true }
nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "master", features = ["use_tokio"], optional = true }
tokio = { version = "1.15", "optional" = true }
serde_json = { workspace = true }
serde_json.workspace = true
assets = { path = "../assets" }
collections = { path = "../collections" }
@ -35,8 +35,8 @@ workspace = { path = "../workspace" }
[dev-dependencies]
indoc = "1.0.4"
parking_lot = "0.11.1"
lazy_static = "1.4"
parking_lot.workspace = true
lazy_static.workspace = true
editor = { path = "../editor", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }

View File

@ -11,8 +11,8 @@ path = "src/welcome.rs"
test-support = []
[dependencies]
anyhow = "1.0.38"
log = "0.4"
anyhow.workspace = true
log.workspace = true
editor = { path = "../editor" }
fuzzy = { path = "../fuzzy" }
gpui = { path = "../gpui" }
@ -24,4 +24,4 @@ theme = { path = "../theme" }
theme_selector = { path = "../theme_selector" }
util = { path = "../util" }
picker = { path = "../picker" }
workspace = { path = "../workspace" }
workspace = { path = "../workspace" }

View File

@ -126,7 +126,7 @@ impl View for WelcomePage {
.with_child(
Flex::column()
.with_child(
theme::ui::checkbox_with_label::<Metrics, _, Self>(
theme::ui::checkbox_with_label::<Metrics, _, Self, _>(
Flex::column()
.with_child(
Label::new(
@ -146,8 +146,9 @@ impl View for WelcomePage {
),
&theme.welcome.checkbox,
metrics,
0,
cx,
|checked, cx| {
|_, checked, cx| {
SettingsFile::update(cx, move |file| {
file.telemetry.set_metrics(checked)
})
@ -157,12 +158,13 @@ impl View for WelcomePage {
.with_style(theme.welcome.checkbox_container),
)
.with_child(
theme::ui::checkbox::<Diagnostics, Self>(
theme::ui::checkbox::<Diagnostics, Self, _>(
"Send crash reports",
&theme.welcome.checkbox,
diagnostics,
0,
cx,
|checked, cx| {
|_, checked, cx| {
SettingsFile::update(cx, move |file| {
file.telemetry.set_diagnostics(checked)
})

View File

@ -35,20 +35,19 @@ settings = { path = "../settings" }
terminal = { path = "../terminal" }
theme = { path = "../theme" }
util = { path = "../util" }
async-recursion = "1.0.0"
bincode = "1.2.1"
anyhow = "1.0.38"
futures = "0.3"
lazy_static = "1.4"
env_logger = "0.9.1"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11.1"
postage = { workspace = true }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
smallvec = { workspace = true }
indoc = "1.0.4"
anyhow.workspace = true
futures.workspace = true
lazy_static.workspace = true
log.workspace = true
parking_lot.workspace = true
postage.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
smallvec.workspace = true
uuid = { version = "1.1.2", features = ["v4"] }
[dev-dependencies]
@ -59,3 +58,6 @@ project = { path = "../project", features = ["test-support"] }
settings = { path = "../settings", features = ["test-support"] }
fs = { path = "../fs", features = ["test-support"] }
db = { path = "../db", features = ["test-support"] }
indoc = "1.0.4"
env_logger.workspace = true

View File

@ -2784,9 +2784,7 @@ fn notify_if_database_failed(workspace: &ViewHandle<Workspace>, cx: &mut AsyncAp
workspace.show_notification_once(0, cx, |cx| {
cx.add_view(|_| {
MessageNotification::new(
indoc::indoc! {"
Failed to load any database file :(
"},
"Failed to load any database file.",
OsOpen::new("https://github.com/zed-industries/community/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml".to_string()),
"Click to let us know about this error"
)
@ -2800,11 +2798,7 @@ fn notify_if_database_failed(workspace: &ViewHandle<Workspace>, cx: &mut AsyncAp
let backup_path = backup_path.to_string_lossy();
MessageNotification::new(
format!(
indoc::indoc! {"
Database file was corrupted :(
Old database backed up to:
{}
"},
"Database file was corrupted. Old database backed up to {}",
backup_path
),
OsOpen::new(backup_path.to_string()),

View File

@ -46,6 +46,7 @@ journal = { path = "../journal" }
language = { path = "../language" }
language_selector = { path = "../language_selector" }
lsp = { path = "../lsp" }
lsp_log = { path = "../lsp_log" }
node_runtime = { path = "../node_runtime" }
outline = { path = "../outline" }
plugin_runtime = { path = "../plugin_runtime" }
@ -66,40 +67,41 @@ util = { path = "../util" }
vim = { path = "../vim" }
workspace = { path = "../workspace" }
welcome = { path = "../welcome" }
anyhow = "1.0.38"
anyhow.workspace = true
async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] }
async-tar = "0.4.2"
async-recursion = "0.3"
async-trait = "0.1"
async-trait.workspace = true
backtrace = "0.3"
chrono = "0.4"
ctor = "0.1.20"
easy-parallel = "3.1.0"
env_logger = "0.9"
futures = "0.3"
env_logger.workspace = true
futures.workspace = true
ignore = "0.4"
image = "0.23"
indexmap = "1.6.2"
isahc = "1.7"
lazy_static = "1.4.0"
lazy_static.workspace = true
libc = "0.2"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
log.workspace = true
num_cpus = "1.13.0"
parking_lot = "0.11.1"
postage = { workspace = true }
rand = "0.8.3"
regex = "1.5"
parking_lot.workspace = true
postage.workspace = true
rand.workspace = true
regex.workspace = true
rsa = "0.4"
rust-embed = { version = "6.3", features = ["include-exclude"] }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
serde_path_to_error = "0.1.4"
simplelog = "0.9"
smallvec = { workspace = true }
smol = "1.2.5"
tempdir = { version = "0.3.7" }
thiserror = "1.0.29"
smallvec.workspace = true
smol.workspace = true
tempdir.workspace = true
thiserror.workspace = true
tiny_http = "0.8"
toml = "0.5"
tree-sitter = "0.20"
@ -109,13 +111,12 @@ tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev
tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "05e3631c6a0701c1fa518b0fee7be95a2ceef5e2" }
tree-sitter-embedded-template = "0.20.0"
tree-sitter-go = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "aeb2f33b366fd78d5789ff104956ce23508b85db" }
tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8" }
tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "40a81c01a40ac48744e0c8ccabbaba1920441199" }
tree-sitter-rust = "0.20.3"
tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" }
tree-sitter-python = "0.20.2"
tree-sitter-toml = { git = "https://github.com/tree-sitter/tree-sitter-toml", rev = "342d9be207c2dba869b9967124c679b5e6fd0ebe" }
tree-sitter-typescript = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "5d20856f34315b068c41edaee2ac8a100081d259" }
tree-sitter-ruby = "0.20.0"
tree-sitter-html = "0.19.0"
tree-sitter-scheme = { git = "https://github.com/6cdh/tree-sitter-scheme", rev = "af0fd1fa452cb2562dc7b5c8a8c55551c39273b9"}
@ -140,9 +141,7 @@ text = { path = "../text", features = ["test-support"] }
util = { path = "../util", features = ["test-support"] }
workspace = { path = "../workspace", features = ["test-support"] }
env_logger = "0.9"
serde_json = { workspace = true }
unindent = "0.1.7"
unindent.workspace = true
[package.metadata.bundle-dev]
icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]

View File

@ -133,7 +133,8 @@ impl LspAdapter for RustLspAdapter {
});
}
Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE)
if completion.detail.is_some() =>
if completion.detail.is_some()
&& completion.insert_text_format != Some(lsp::InsertTextFormat::SNIPPET) =>
{
let detail = completion.detail.as_ref().unwrap();
let name = &completion.label;

View File

@ -262,6 +262,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
);
activity_indicator::init(cx);
copilot_button::init(cx);
lsp_log::init(cx);
call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
settings::KeymapFileContent::load_defaults(cx);
}
@ -273,7 +274,7 @@ pub fn initialize_workspace(
) {
let workspace_handle = cx.handle();
cx.subscribe(&workspace_handle, {
move |_, _, event, cx| {
move |workspace, _, event, cx| {
if let workspace::Event::PaneAdded(pane) = event {
pane.update(cx, |pane, cx| {
pane.toolbar().update(cx, |toolbar, cx| {
@ -287,6 +288,10 @@ pub fn initialize_workspace(
toolbar.add_item(submit_feedback_button, cx);
let feedback_info_text = cx.add_view(|_| FeedbackInfoText::new());
toolbar.add_item(feedback_info_text, cx);
let lsp_log_item = cx.add_view(|_| {
lsp_log::LspLogToolbarItemView::new(workspace.project().clone())
});
toolbar.add_item(lsp_log_item, cx);
})
});
}