mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-26 20:22:30 +00:00
Merge remote-tracking branch 'origin/main' into fewer-context-traits
This commit is contained in:
commit
7ca412ade3
81 changed files with 1578 additions and 654 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -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",
|
||||
|
|
20
Cargo.toml
20
Cargo.toml
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"] }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -9,4 +9,4 @@ path = "src/clock.rs"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
smallvec = { workspace = true }
|
||||
smallvec.workspace = true
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)| {
|
||||
|
|
|
@ -13,4 +13,4 @@ gpui = { path = "../gpui" }
|
|||
menu = { path = "../menu" }
|
||||
settings = { path = "../settings" }
|
||||
theme = { path = "../theme" }
|
||||
smallvec = { workspace = true }
|
||||
smallvec.workspace = true
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -15,4 +15,4 @@ menu = { path = "../menu" }
|
|||
settings = { path = "../settings" }
|
||||
text = { path = "../text" }
|
||||
workspace = { path = "../workspace" }
|
||||
postage = { workspace = true }
|
||||
postage.workspace = true
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -19,4 +19,4 @@ theme = { path = "../theme" }
|
|||
settings = { path = "../settings" }
|
||||
util = { path = "../util" }
|
||||
workspace = { path = "../workspace" }
|
||||
anyhow = "1.0"
|
||||
anyhow.workspace = true
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
29
crates/lsp_log/Cargo.toml
Normal 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
|
523
crates/lsp_log/src/lsp_log.rs
Normal file
523
crates/lsp_log/src/lsp_log.rs
Normal 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(¤t_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 = ();
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -240,13 +240,13 @@ message ParticipantLocation {
|
|||
UnsharedProject unshared_project = 2;
|
||||
External external = 3;
|
||||
}
|
||||
|
||||
|
||||
message SharedProject {
|
||||
uint64 id = 1;
|
||||
}
|
||||
|
||||
|
||||
message UnsharedProject {}
|
||||
|
||||
|
||||
message External {}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,5 +9,5 @@ path = "src/snippet.rs"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
smallvec = { workspace = true }
|
||||
anyhow.workspace = true
|
||||
smallvec.workspace = true
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -9,4 +9,4 @@ path = "src/staff_mode.rs"
|
|||
|
||||
[dependencies]
|
||||
gpui = { path = "../gpui" }
|
||||
anyhow = "1.0.38"
|
||||
anyhow.workspace = true
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -16,4 +16,4 @@ settings = { path = "../settings" }
|
|||
workspace = { path = "../workspace" }
|
||||
project = { path = "../project" }
|
||||
|
||||
smallvec = { workspace = true }
|
||||
smallvec.workspace = true
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue