Merge branch 'main' into collab-panel
This commit is contained in:
commit
c537cf2a57
92 changed files with 2015 additions and 1591 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -1651,6 +1651,15 @@ dependencies = [
|
||||||
"theme",
|
"theme",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert_case"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "copilot"
|
name = "copilot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -2316,6 +2325,7 @@ dependencies = [
|
||||||
"clock",
|
"clock",
|
||||||
"collections",
|
"collections",
|
||||||
"context_menu",
|
"context_menu",
|
||||||
|
"convert_case",
|
||||||
"copilot",
|
"copilot",
|
||||||
"ctor",
|
"ctor",
|
||||||
"db",
|
"db",
|
||||||
|
@ -9817,7 +9827,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed"
|
name = "zed"
|
||||||
version = "0.98.0"
|
version = "0.99.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activity_indicator",
|
"activity_indicator",
|
||||||
"ai",
|
"ai",
|
||||||
|
|
|
@ -570,8 +570,9 @@ impl TestClient {
|
||||||
|
|
||||||
// We use a workspace container so that we don't need to remove the window in order to
|
// We use a workspace container so that we don't need to remove the window in order to
|
||||||
// drop the workspace and we can use a ViewHandle instead.
|
// drop the workspace and we can use a ViewHandle instead.
|
||||||
let (window_id, container) = cx.add_window(|_| WorkspaceContainer { workspace: None });
|
let window = cx.add_window(|_| WorkspaceContainer { workspace: None });
|
||||||
let workspace = cx.add_view(window_id, |cx| {
|
let container = window.root(cx);
|
||||||
|
let workspace = window.add_view(cx, |cx| {
|
||||||
Workspace::new(0, project.clone(), self.app_state.clone(), cx)
|
Workspace::new(0, project.clone(), self.app_state.clone(), cx)
|
||||||
});
|
});
|
||||||
container.update(cx, |container, cx| {
|
container.update(cx, |container, cx| {
|
||||||
|
|
|
@ -7,8 +7,7 @@ use client::{User, RECEIVE_TIMEOUT};
|
||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
use editor::{
|
use editor::{
|
||||||
test::editor_test_context::EditorTestContext, ConfirmCodeAction, ConfirmCompletion,
|
test::editor_test_context::EditorTestContext, ConfirmCodeAction, ConfirmCompletion,
|
||||||
ConfirmRename, Editor, ExcerptRange, MultiBuffer, Redo, Rename, ToOffset, ToggleCodeActions,
|
ConfirmRename, Editor, ExcerptRange, MultiBuffer, Redo, Rename, ToggleCodeActions, Undo,
|
||||||
Undo,
|
|
||||||
};
|
};
|
||||||
use fs::{repository::GitFileStatus, FakeFs, Fs as _, LineEnding, RemoveOptions};
|
use fs::{repository::GitFileStatus, FakeFs, Fs as _, LineEnding, RemoveOptions};
|
||||||
use futures::StreamExt as _;
|
use futures::StreamExt as _;
|
||||||
|
@ -1208,7 +1207,7 @@ async fn test_share_project(
|
||||||
cx_c: &mut TestAppContext,
|
cx_c: &mut TestAppContext,
|
||||||
) {
|
) {
|
||||||
deterministic.forbid_parking();
|
deterministic.forbid_parking();
|
||||||
let (window_b, _) = cx_b.add_window(|_| EmptyView);
|
let window_b = cx_b.add_window(|_| EmptyView);
|
||||||
let mut server = TestServer::start(&deterministic).await;
|
let mut server = TestServer::start(&deterministic).await;
|
||||||
let client_a = server.create_client(cx_a, "user_a").await;
|
let client_a = server.create_client(cx_a, "user_a").await;
|
||||||
let client_b = server.create_client(cx_b, "user_b").await;
|
let client_b = server.create_client(cx_b, "user_b").await;
|
||||||
|
@ -1316,7 +1315,7 @@ async fn test_share_project(
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let editor_b = cx_b.add_view(window_b, |cx| Editor::for_buffer(buffer_b, None, cx));
|
let editor_b = window_b.add_view(cx_b, |cx| Editor::for_buffer(buffer_b, None, cx));
|
||||||
|
|
||||||
// Client A sees client B's selection
|
// Client A sees client B's selection
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
|
@ -1499,8 +1498,9 @@ async fn test_host_disconnect(
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
|
assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
|
||||||
|
|
||||||
let (window_id_b, workspace_b) =
|
let window_b =
|
||||||
cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
|
cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
|
||||||
|
let workspace_b = window_b.root(cx_b);
|
||||||
let editor_b = workspace_b
|
let editor_b = workspace_b
|
||||||
.update(cx_b, |workspace, cx| {
|
.update(cx_b, |workspace, cx| {
|
||||||
workspace.open_path((worktree_id, "b.txt"), None, true, cx)
|
workspace.open_path((worktree_id, "b.txt"), None, true, cx)
|
||||||
|
@ -1509,9 +1509,7 @@ async fn test_host_disconnect(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.downcast::<Editor>()
|
.downcast::<Editor>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(cx_b
|
assert!(window_b.read_with(cx_b, |cx| editor_b.is_focused(cx)));
|
||||||
.read_window(window_id_b, |cx| editor_b.is_focused(cx))
|
|
||||||
.unwrap());
|
|
||||||
editor_b.update(cx_b, |editor, cx| editor.insert("X", cx));
|
editor_b.update(cx_b, |editor, cx| editor.insert("X", cx));
|
||||||
assert!(cx_b.is_window_edited(workspace_b.window_id()));
|
assert!(cx_b.is_window_edited(workspace_b.window_id()));
|
||||||
|
|
||||||
|
@ -1525,7 +1523,7 @@ async fn test_host_disconnect(
|
||||||
assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
|
assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
|
||||||
|
|
||||||
// Ensure client B's edited state is reset and that the whole window is blurred.
|
// Ensure client B's edited state is reset and that the whole window is blurred.
|
||||||
cx_b.read_window(window_id_b, |cx| {
|
window_b.read_with(cx_b, |cx| {
|
||||||
assert_eq!(cx.focused_view_id(), None);
|
assert_eq!(cx.focused_view_id(), None);
|
||||||
});
|
});
|
||||||
assert!(!cx_b.is_window_edited(workspace_b.window_id()));
|
assert!(!cx_b.is_window_edited(workspace_b.window_id()));
|
||||||
|
@ -3440,13 +3438,11 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor(
|
||||||
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
|
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (window_a, _) = cx_a.add_window(|_| EmptyView);
|
let window_a = cx_a.add_window(|_| EmptyView);
|
||||||
let editor_a = cx_a.add_view(window_a, |cx| {
|
let editor_a = window_a.add_view(cx_a, |cx| Editor::for_buffer(buffer_a, Some(project_a), cx));
|
||||||
Editor::for_buffer(buffer_a, Some(project_a), cx)
|
|
||||||
});
|
|
||||||
let mut editor_cx_a = EditorTestContext {
|
let mut editor_cx_a = EditorTestContext {
|
||||||
cx: cx_a,
|
cx: cx_a,
|
||||||
window_id: window_a,
|
window_id: window_a.window_id(),
|
||||||
editor: editor_a,
|
editor: editor_a,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3455,13 +3451,11 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor(
|
||||||
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
|
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (window_b, _) = cx_b.add_window(|_| EmptyView);
|
let window_b = cx_b.add_window(|_| EmptyView);
|
||||||
let editor_b = cx_b.add_view(window_b, |cx| {
|
let editor_b = window_b.add_view(cx_b, |cx| Editor::for_buffer(buffer_b, Some(project_b), cx));
|
||||||
Editor::for_buffer(buffer_b, Some(project_b), cx)
|
|
||||||
});
|
|
||||||
let mut editor_cx_b = EditorTestContext {
|
let mut editor_cx_b = EditorTestContext {
|
||||||
cx: cx_b,
|
cx: cx_b,
|
||||||
window_id: window_b,
|
window_id: window_b.window_id(),
|
||||||
editor: editor_b,
|
editor: editor_b,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4200,8 +4194,8 @@ async fn test_collaborating_with_completion(
|
||||||
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
|
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (window_b, _) = cx_b.add_window(|_| EmptyView);
|
let window_b = cx_b.add_window(|_| EmptyView);
|
||||||
let editor_b = cx_b.add_view(window_b, |cx| {
|
let editor_b = window_b.add_view(cx_b, |cx| {
|
||||||
Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx)
|
Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5312,8 +5306,9 @@ async fn test_collaborating_with_code_actions(
|
||||||
|
|
||||||
// Join the project as client B.
|
// Join the project as client B.
|
||||||
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
||||||
let (_window_b, workspace_b) =
|
let window_b =
|
||||||
cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
|
cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
|
||||||
|
let workspace_b = window_b.root(cx_b);
|
||||||
let editor_b = workspace_b
|
let editor_b = workspace_b
|
||||||
.update(cx_b, |workspace, cx| {
|
.update(cx_b, |workspace, cx| {
|
||||||
workspace.open_path((worktree_id, "main.rs"), None, true, cx)
|
workspace.open_path((worktree_id, "main.rs"), None, true, cx)
|
||||||
|
@ -5537,8 +5532,9 @@ async fn test_collaborating_with_renames(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
||||||
|
|
||||||
let (_window_b, workspace_b) =
|
let window_b =
|
||||||
cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
|
cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
|
||||||
|
let workspace_b = window_b.root(cx_b);
|
||||||
let editor_b = workspace_b
|
let editor_b = workspace_b
|
||||||
.update(cx_b, |workspace, cx| {
|
.update(cx_b, |workspace, cx| {
|
||||||
workspace.open_path((worktree_id, "one.rs"), None, true, cx)
|
workspace.open_path((worktree_id, "one.rs"), None, true, cx)
|
||||||
|
@ -5569,6 +5565,7 @@ async fn test_collaborating_with_renames(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
prepare_rename.await.unwrap();
|
prepare_rename.await.unwrap();
|
||||||
editor_b.update(cx_b, |editor, cx| {
|
editor_b.update(cx_b, |editor, cx| {
|
||||||
|
use editor::ToOffset;
|
||||||
let rename = editor.pending_rename().unwrap();
|
let rename = editor.pending_rename().unwrap();
|
||||||
let buffer = editor.buffer().read(cx).snapshot(cx);
|
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -7599,8 +7596,8 @@ async fn test_on_input_format_from_host_to_guest(
|
||||||
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
|
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (window_a, _) = cx_a.add_window(|_| EmptyView);
|
let window_a = cx_a.add_window(|_| EmptyView);
|
||||||
let editor_a = cx_a.add_view(window_a, |cx| {
|
let editor_a = window_a.add_view(cx_a, |cx| {
|
||||||
Editor::for_buffer(buffer_a, Some(project_a.clone()), cx)
|
Editor::for_buffer(buffer_a, Some(project_a.clone()), cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -7728,8 +7725,8 @@ async fn test_on_input_format_from_guest_to_host(
|
||||||
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
|
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (window_b, _) = cx_b.add_window(|_| EmptyView);
|
let window_b = cx_b.add_window(|_| EmptyView);
|
||||||
let editor_b = cx_b.add_view(window_b, |cx| {
|
let editor_b = window_b.add_view(cx_b, |cx| {
|
||||||
Editor::for_buffer(buffer_b, Some(project_b.clone()), cx)
|
Editor::for_buffer(buffer_b, Some(project_b.clone()), cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
|
||||||
|
|
||||||
for screen in cx.platform().screens() {
|
for screen in cx.platform().screens() {
|
||||||
let screen_bounds = screen.bounds();
|
let screen_bounds = screen.bounds();
|
||||||
let (window_id, _) = cx.add_window(
|
let window = cx.add_window(
|
||||||
WindowOptions {
|
WindowOptions {
|
||||||
bounds: WindowBounds::Fixed(RectF::new(
|
bounds: WindowBounds::Fixed(RectF::new(
|
||||||
screen_bounds.upper_right()
|
screen_bounds.upper_right()
|
||||||
|
@ -49,7 +49,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
|
||||||
|_| IncomingCallNotification::new(incoming_call.clone(), app_state.clone()),
|
|_| IncomingCallNotification::new(incoming_call.clone(), app_state.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
notification_windows.push(window_id);
|
notification_windows.push(window.window_id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
|
||||||
|
|
||||||
for screen in cx.platform().screens() {
|
for screen in cx.platform().screens() {
|
||||||
let screen_bounds = screen.bounds();
|
let screen_bounds = screen.bounds();
|
||||||
let (window_id, _) = cx.add_window(
|
let window = cx.add_window(
|
||||||
WindowOptions {
|
WindowOptions {
|
||||||
bounds: WindowBounds::Fixed(RectF::new(
|
bounds: WindowBounds::Fixed(RectF::new(
|
||||||
screen_bounds.upper_right() - vec2f(PADDING + window_size.x(), PADDING),
|
screen_bounds.upper_right() - vec2f(PADDING + window_size.x(), PADDING),
|
||||||
|
@ -52,7 +52,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
|
||||||
notification_windows
|
notification_windows
|
||||||
.entry(*project_id)
|
.entry(*project_id)
|
||||||
.or_insert(Vec::new())
|
.or_insert(Vec::new())
|
||||||
.push(window_id);
|
.push(window.window_id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
room::Event::RemoteProjectUnshared { project_id } => {
|
room::Event::RemoteProjectUnshared { project_id } => {
|
||||||
|
|
|
@ -295,7 +295,9 @@ mod tests {
|
||||||
let app_state = init_test(cx);
|
let app_state = init_test(cx);
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), [], cx).await;
|
let project = Project::test(app_state.fs.clone(), [], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
let editor = cx.add_view(window_id, |cx| {
|
let editor = cx.add_view(window_id, |cx| {
|
||||||
let mut editor = Editor::single_line(None, cx);
|
let mut editor = Editor::single_line(None, cx);
|
||||||
editor.set_text("abc", cx);
|
editor.set_text("abc", cx);
|
||||||
|
|
|
@ -4,7 +4,7 @@ use gpui::{
|
||||||
geometry::rect::RectF,
|
geometry::rect::RectF,
|
||||||
platform::{WindowBounds, WindowKind, WindowOptions},
|
platform::{WindowBounds, WindowKind, WindowOptions},
|
||||||
AnyElement, AnyViewHandle, AppContext, ClipboardItem, Element, Entity, View, ViewContext,
|
AnyElement, AnyViewHandle, AppContext, ClipboardItem, Element, Entity, View, ViewContext,
|
||||||
ViewHandle,
|
WindowHandle,
|
||||||
};
|
};
|
||||||
use theme::ui::modal;
|
use theme::ui::modal;
|
||||||
|
|
||||||
|
@ -18,43 +18,43 @@ const COPILOT_SIGN_UP_URL: &'static str = "https://github.com/features/copilot";
|
||||||
|
|
||||||
pub fn init(cx: &mut AppContext) {
|
pub fn init(cx: &mut AppContext) {
|
||||||
if let Some(copilot) = Copilot::global(cx) {
|
if let Some(copilot) = Copilot::global(cx) {
|
||||||
let mut code_verification: Option<ViewHandle<CopilotCodeVerification>> = None;
|
let mut verification_window: Option<WindowHandle<CopilotCodeVerification>> = None;
|
||||||
cx.observe(&copilot, move |copilot, cx| {
|
cx.observe(&copilot, move |copilot, cx| {
|
||||||
let status = copilot.read(cx).status();
|
let status = copilot.read(cx).status();
|
||||||
|
|
||||||
match &status {
|
match &status {
|
||||||
crate::Status::SigningIn { prompt } => {
|
crate::Status::SigningIn { prompt } => {
|
||||||
if let Some(code_verification_handle) = code_verification.as_mut() {
|
if let Some(window) = verification_window.as_mut() {
|
||||||
let window_id = code_verification_handle.window_id();
|
let updated = window
|
||||||
let updated = cx.update_window(window_id, |cx| {
|
.root(cx)
|
||||||
code_verification_handle.update(cx, |code_verification, cx| {
|
.map(|root| {
|
||||||
code_verification.set_status(status.clone(), cx)
|
root.update(cx, |verification, cx| {
|
||||||
});
|
verification.set_status(status.clone(), cx);
|
||||||
cx.activate_window();
|
cx.activate_window();
|
||||||
});
|
})
|
||||||
if updated.is_none() {
|
})
|
||||||
code_verification = Some(create_copilot_auth_window(cx, &status));
|
.is_some();
|
||||||
|
if !updated {
|
||||||
|
verification_window = Some(create_copilot_auth_window(cx, &status));
|
||||||
}
|
}
|
||||||
} else if let Some(_prompt) = prompt {
|
} else if let Some(_prompt) = prompt {
|
||||||
code_verification = Some(create_copilot_auth_window(cx, &status));
|
verification_window = Some(create_copilot_auth_window(cx, &status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Status::Authorized | Status::Unauthorized => {
|
Status::Authorized | Status::Unauthorized => {
|
||||||
if let Some(code_verification) = code_verification.as_ref() {
|
if let Some(window) = verification_window.as_ref() {
|
||||||
let window_id = code_verification.window_id();
|
if let Some(verification) = window.root(cx) {
|
||||||
cx.update_window(window_id, |cx| {
|
verification.update(cx, |verification, cx| {
|
||||||
code_verification.update(cx, |code_verification, cx| {
|
verification.set_status(status, cx);
|
||||||
code_verification.set_status(status, cx)
|
cx.platform().activate(true);
|
||||||
|
cx.activate_window();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
cx.platform().activate(true);
|
|
||||||
cx.activate_window();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(code_verification) = code_verification.take() {
|
if let Some(code_verification) = verification_window.take() {
|
||||||
cx.update_window(code_verification.window_id(), |cx| cx.remove_window());
|
code_verification.update(cx, |cx| cx.remove_window());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ pub fn init(cx: &mut AppContext) {
|
||||||
fn create_copilot_auth_window(
|
fn create_copilot_auth_window(
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
status: &Status,
|
status: &Status,
|
||||||
) -> ViewHandle<CopilotCodeVerification> {
|
) -> WindowHandle<CopilotCodeVerification> {
|
||||||
let window_size = theme::current(cx).copilot.modal.dimensions();
|
let window_size = theme::current(cx).copilot.modal.dimensions();
|
||||||
let window_options = WindowOptions {
|
let window_options = WindowOptions {
|
||||||
bounds: WindowBounds::Fixed(RectF::new(Default::default(), window_size)),
|
bounds: WindowBounds::Fixed(RectF::new(Default::default(), window_size)),
|
||||||
|
@ -78,10 +78,9 @@ fn create_copilot_auth_window(
|
||||||
is_movable: true,
|
is_movable: true,
|
||||||
screen: None,
|
screen: None,
|
||||||
};
|
};
|
||||||
let (_, view) = cx.add_window(window_options, |_cx| {
|
cx.add_window(window_options, |_cx| {
|
||||||
CopilotCodeVerification::new(status.clone())
|
CopilotCodeVerification::new(status.clone())
|
||||||
});
|
})
|
||||||
view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CopilotCodeVerification {
|
pub struct CopilotCodeVerification {
|
||||||
|
|
|
@ -855,7 +855,9 @@ mod tests {
|
||||||
|
|
||||||
let language_server_id = LanguageServerId(0);
|
let language_server_id = LanguageServerId(0);
|
||||||
let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
// Create some diagnostics
|
// Create some diagnostics
|
||||||
project.update(cx, |project, cx| {
|
project.update(cx, |project, cx| {
|
||||||
|
@ -1248,7 +1250,9 @@ mod tests {
|
||||||
let server_id_1 = LanguageServerId(100);
|
let server_id_1 = LanguageServerId(100);
|
||||||
let server_id_2 = LanguageServerId(101);
|
let server_id_2 = LanguageServerId(101);
|
||||||
let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
let view = cx.add_view(window_id, |cx| {
|
let view = cx.add_view(window_id, |cx| {
|
||||||
ProjectDiagnosticsEditor::new(project.clone(), workspace.downgrade(), cx)
|
ProjectDiagnosticsEditor::new(project.clone(), workspace.downgrade(), cx)
|
||||||
|
|
|
@ -47,6 +47,7 @@ workspace = { path = "../workspace" }
|
||||||
|
|
||||||
aho-corasick = "0.7"
|
aho-corasick = "0.7"
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
|
convert_case = "0.6.0"
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
indoc = "1.0.4"
|
indoc = "1.0.4"
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
|
@ -56,12 +57,12 @@ ordered-float.workspace = true
|
||||||
parking_lot.workspace = true
|
parking_lot.workspace = true
|
||||||
postage.workspace = true
|
postage.workspace = true
|
||||||
pulldown-cmark = { version = "0.9.2", default-features = false }
|
pulldown-cmark = { version = "0.9.2", default-features = false }
|
||||||
|
rand.workspace = true
|
||||||
schemars.workspace = true
|
schemars.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_derive.workspace = true
|
serde_derive.workspace = true
|
||||||
smallvec.workspace = true
|
smallvec.workspace = true
|
||||||
smol.workspace = true
|
smol.workspace = true
|
||||||
rand.workspace = true
|
|
||||||
|
|
||||||
tree-sitter-rust = { workspace = true, optional = true }
|
tree-sitter-rust = { workspace = true, optional = true }
|
||||||
tree-sitter-html = { workspace = true, optional = true }
|
tree-sitter-html = { workspace = true, optional = true }
|
||||||
|
|
|
@ -28,6 +28,7 @@ use blink_manager::BlinkManager;
|
||||||
use client::{ClickhouseEvent, TelemetrySettings};
|
use client::{ClickhouseEvent, TelemetrySettings};
|
||||||
use clock::{Global, ReplicaId};
|
use clock::{Global, ReplicaId};
|
||||||
use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
|
use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
|
||||||
|
use convert_case::{Case, Casing};
|
||||||
use copilot::Copilot;
|
use copilot::Copilot;
|
||||||
pub use display_map::DisplayPoint;
|
pub use display_map::DisplayPoint;
|
||||||
use display_map::*;
|
use display_map::*;
|
||||||
|
@ -231,6 +232,13 @@ actions!(
|
||||||
SortLinesCaseInsensitive,
|
SortLinesCaseInsensitive,
|
||||||
ReverseLines,
|
ReverseLines,
|
||||||
ShuffleLines,
|
ShuffleLines,
|
||||||
|
ConvertToUpperCase,
|
||||||
|
ConvertToLowerCase,
|
||||||
|
ConvertToTitleCase,
|
||||||
|
ConvertToSnakeCase,
|
||||||
|
ConvertToKebabCase,
|
||||||
|
ConvertToUpperCamelCase,
|
||||||
|
ConvertToLowerCamelCase,
|
||||||
Transpose,
|
Transpose,
|
||||||
Cut,
|
Cut,
|
||||||
Copy,
|
Copy,
|
||||||
|
@ -353,6 +361,13 @@ pub fn init(cx: &mut AppContext) {
|
||||||
cx.add_action(Editor::sort_lines_case_insensitive);
|
cx.add_action(Editor::sort_lines_case_insensitive);
|
||||||
cx.add_action(Editor::reverse_lines);
|
cx.add_action(Editor::reverse_lines);
|
||||||
cx.add_action(Editor::shuffle_lines);
|
cx.add_action(Editor::shuffle_lines);
|
||||||
|
cx.add_action(Editor::convert_to_upper_case);
|
||||||
|
cx.add_action(Editor::convert_to_lower_case);
|
||||||
|
cx.add_action(Editor::convert_to_title_case);
|
||||||
|
cx.add_action(Editor::convert_to_snake_case);
|
||||||
|
cx.add_action(Editor::convert_to_kebab_case);
|
||||||
|
cx.add_action(Editor::convert_to_upper_camel_case);
|
||||||
|
cx.add_action(Editor::convert_to_lower_camel_case);
|
||||||
cx.add_action(Editor::delete_to_previous_word_start);
|
cx.add_action(Editor::delete_to_previous_word_start);
|
||||||
cx.add_action(Editor::delete_to_previous_subword_start);
|
cx.add_action(Editor::delete_to_previous_subword_start);
|
||||||
cx.add_action(Editor::delete_to_next_word_end);
|
cx.add_action(Editor::delete_to_next_word_end);
|
||||||
|
@ -4306,6 +4321,97 @@ impl Editor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
|
||||||
|
self.manipulate_text(cx, |text| text.to_uppercase())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
|
||||||
|
self.manipulate_text(cx, |text| text.to_lowercase())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
|
||||||
|
self.manipulate_text(cx, |text| text.to_case(Case::Title))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
|
||||||
|
self.manipulate_text(cx, |text| text.to_case(Case::Snake))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
|
||||||
|
self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_to_upper_camel_case(
|
||||||
|
&mut self,
|
||||||
|
_: &ConvertToUpperCamelCase,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) {
|
||||||
|
self.manipulate_text(cx, |text| text.to_case(Case::UpperCamel))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_to_lower_camel_case(
|
||||||
|
&mut self,
|
||||||
|
_: &ConvertToLowerCamelCase,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) {
|
||||||
|
self.manipulate_text(cx, |text| text.to_case(Case::Camel))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
|
||||||
|
where
|
||||||
|
Fn: FnMut(&str) -> String,
|
||||||
|
{
|
||||||
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
|
let buffer = self.buffer.read(cx).snapshot(cx);
|
||||||
|
|
||||||
|
let mut new_selections = Vec::new();
|
||||||
|
let mut edits = Vec::new();
|
||||||
|
let mut selection_adjustment = 0i32;
|
||||||
|
|
||||||
|
for selection in self.selections.all::<usize>(cx) {
|
||||||
|
let selection_is_empty = selection.is_empty();
|
||||||
|
|
||||||
|
let (start, end) = if selection_is_empty {
|
||||||
|
let word_range = movement::surrounding_word(
|
||||||
|
&display_map,
|
||||||
|
selection.start.to_display_point(&display_map),
|
||||||
|
);
|
||||||
|
let start = word_range.start.to_offset(&display_map, Bias::Left);
|
||||||
|
let end = word_range.end.to_offset(&display_map, Bias::Left);
|
||||||
|
(start, end)
|
||||||
|
} else {
|
||||||
|
(selection.start, selection.end)
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = buffer.text_for_range(start..end).collect::<String>();
|
||||||
|
let old_length = text.len() as i32;
|
||||||
|
let text = callback(&text);
|
||||||
|
|
||||||
|
new_selections.push(Selection {
|
||||||
|
start: (start as i32 - selection_adjustment) as usize,
|
||||||
|
end: ((start + text.len()) as i32 - selection_adjustment) as usize,
|
||||||
|
goal: SelectionGoal::None,
|
||||||
|
..selection
|
||||||
|
});
|
||||||
|
|
||||||
|
selection_adjustment += old_length - text.len() as i32;
|
||||||
|
|
||||||
|
edits.push((start..end, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.transact(cx, |this, cx| {
|
||||||
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
|
buffer.edit(edits, None, cx);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
|
s.select(new_selections);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.request_autoscroll(Autoscroll::fit(), cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
|
pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
let buffer = &display_map.buffer_snapshot;
|
let buffer = &display_map.buffer_snapshot;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3002,10 +3002,12 @@ mod tests {
|
||||||
fn test_layout_line_numbers(cx: &mut TestAppContext) {
|
fn test_layout_line_numbers(cx: &mut TestAppContext) {
|
||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
|
|
||||||
let (_, editor) = cx.add_window(|cx| {
|
let editor = cx
|
||||||
let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
|
.add_window(|cx| {
|
||||||
Editor::new(EditorMode::Full, buffer, None, None, cx)
|
let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
|
||||||
});
|
Editor::new(EditorMode::Full, buffer, None, None, cx)
|
||||||
|
})
|
||||||
|
.root(cx);
|
||||||
let element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
|
let element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
|
||||||
|
|
||||||
let layouts = editor.update(cx, |editor, cx| {
|
let layouts = editor.update(cx, |editor, cx| {
|
||||||
|
@ -3021,10 +3023,12 @@ mod tests {
|
||||||
fn test_layout_with_placeholder_text_and_blocks(cx: &mut TestAppContext) {
|
fn test_layout_with_placeholder_text_and_blocks(cx: &mut TestAppContext) {
|
||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
|
|
||||||
let (_, editor) = cx.add_window(|cx| {
|
let editor = cx
|
||||||
let buffer = MultiBuffer::build_simple("", cx);
|
.add_window(|cx| {
|
||||||
Editor::new(EditorMode::Full, buffer, None, None, cx)
|
let buffer = MultiBuffer::build_simple("", cx);
|
||||||
});
|
Editor::new(EditorMode::Full, buffer, None, None, cx)
|
||||||
|
})
|
||||||
|
.root(cx);
|
||||||
|
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.set_placeholder_text("hello", cx);
|
editor.set_placeholder_text("hello", cx);
|
||||||
|
@ -3231,10 +3235,12 @@ mod tests {
|
||||||
info!(
|
info!(
|
||||||
"Creating editor with mode {editor_mode:?}, width {editor_width} and text '{input_text}'"
|
"Creating editor with mode {editor_mode:?}, width {editor_width} and text '{input_text}'"
|
||||||
);
|
);
|
||||||
let (_, editor) = cx.add_window(|cx| {
|
let editor = cx
|
||||||
let buffer = MultiBuffer::build_simple(&input_text, cx);
|
.add_window(|cx| {
|
||||||
Editor::new(editor_mode, buffer, None, None, cx)
|
let buffer = MultiBuffer::build_simple(&input_text, cx);
|
||||||
});
|
Editor::new(editor_mode, buffer, None, None, cx)
|
||||||
|
})
|
||||||
|
.root(cx);
|
||||||
|
|
||||||
let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
|
let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
|
||||||
let (_, layout_state) = editor.update(cx, |editor, cx| {
|
let (_, layout_state) = editor.update(cx, |editor, cx| {
|
||||||
|
|
|
@ -1135,7 +1135,9 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let project = Project::test(fs, ["/a".as_ref()], cx).await;
|
let project = Project::test(fs, ["/a".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let worktree_id = workspace.update(cx, |workspace, cx| {
|
let worktree_id = workspace.update(cx, |workspace, cx| {
|
||||||
workspace.project().read_with(cx, |project, cx| {
|
workspace.project().read_with(cx, |project, cx| {
|
||||||
project.worktrees(cx).next().unwrap().read(cx).id()
|
project.worktrees(cx).next().unwrap().read(cx).id()
|
||||||
|
@ -1835,7 +1837,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
let project = Project::test(fs, ["/a".as_ref()], cx).await;
|
let project = Project::test(fs, ["/a".as_ref()], cx).await;
|
||||||
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
|
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let worktree_id = workspace.update(cx, |workspace, cx| {
|
let worktree_id = workspace.update(cx, |workspace, cx| {
|
||||||
workspace.project().read_with(cx, |project, cx| {
|
workspace.project().read_with(cx, |project, cx| {
|
||||||
project.worktrees(cx).next().unwrap().read(cx).id()
|
project.worktrees(cx).next().unwrap().read(cx).id()
|
||||||
|
@ -1988,7 +1992,9 @@ mod tests {
|
||||||
project.update(cx, |project, _| {
|
project.update(cx, |project, _| {
|
||||||
project.languages().add(Arc::clone(&language))
|
project.languages().add(Arc::clone(&language))
|
||||||
});
|
});
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let worktree_id = workspace.update(cx, |workspace, cx| {
|
let worktree_id = workspace.update(cx, |workspace, cx| {
|
||||||
workspace.project().read_with(cx, |project, cx| {
|
workspace.project().read_with(cx, |project, cx| {
|
||||||
project.worktrees(cx).next().unwrap().read(cx).id()
|
project.worktrees(cx).next().unwrap().read(cx).id()
|
||||||
|
@ -2074,8 +2080,9 @@ mod tests {
|
||||||
|
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
let (_, editor) =
|
let editor = cx
|
||||||
cx.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx));
|
.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx))
|
||||||
|
.root(cx);
|
||||||
let editor_edited = Arc::new(AtomicBool::new(false));
|
let editor_edited = Arc::new(AtomicBool::new(false));
|
||||||
let fake_server = fake_servers.next().await.unwrap();
|
let fake_server = fake_servers.next().await.unwrap();
|
||||||
let closure_editor_edited = Arc::clone(&editor_edited);
|
let closure_editor_edited = Arc::clone(&editor_edited);
|
||||||
|
@ -2327,7 +2334,9 @@ all hints should be invalidated and requeried for all of its visible excerpts"
|
||||||
project.update(cx, |project, _| {
|
project.update(cx, |project, _| {
|
||||||
project.languages().add(Arc::clone(&language))
|
project.languages().add(Arc::clone(&language))
|
||||||
});
|
});
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let worktree_id = workspace.update(cx, |workspace, cx| {
|
let worktree_id = workspace.update(cx, |workspace, cx| {
|
||||||
workspace.project().read_with(cx, |project, cx| {
|
workspace.project().read_with(cx, |project, cx| {
|
||||||
project.worktrees(cx).next().unwrap().read(cx).id()
|
project.worktrees(cx).next().unwrap().read(cx).id()
|
||||||
|
@ -2372,8 +2381,9 @@ all hints should be invalidated and requeried for all of its visible excerpts"
|
||||||
|
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
let (_, editor) =
|
let editor = cx
|
||||||
cx.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx));
|
.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx))
|
||||||
|
.root(cx);
|
||||||
let editor_edited = Arc::new(AtomicBool::new(false));
|
let editor_edited = Arc::new(AtomicBool::new(false));
|
||||||
let fake_server = fake_servers.next().await.unwrap();
|
let fake_server = fake_servers.next().await.unwrap();
|
||||||
let closure_editor_edited = Arc::clone(&editor_edited);
|
let closure_editor_edited = Arc::clone(&editor_edited);
|
||||||
|
@ -2561,7 +2571,9 @@ all hints should be invalidated and requeried for all of its visible excerpts"
|
||||||
|
|
||||||
let project = Project::test(fs, ["/a".as_ref()], cx).await;
|
let project = Project::test(fs, ["/a".as_ref()], cx).await;
|
||||||
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
|
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let worktree_id = workspace.update(cx, |workspace, cx| {
|
let worktree_id = workspace.update(cx, |workspace, cx| {
|
||||||
workspace.project().read_with(cx, |project, cx| {
|
workspace.project().read_with(cx, |project, cx| {
|
||||||
project.worktrees(cx).next().unwrap().read(cx).id()
|
project.worktrees(cx).next().unwrap().read(cx).id()
|
||||||
|
|
|
@ -28,7 +28,10 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use text::Selection;
|
use text::Selection;
|
||||||
use util::{paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt};
|
use util::{
|
||||||
|
paths::{PathExt, FILE_ROW_COLUMN_DELIMITER},
|
||||||
|
ResultExt, TryFutureExt,
|
||||||
|
};
|
||||||
use workspace::item::{BreadcrumbText, FollowableItemHandle};
|
use workspace::item::{BreadcrumbText, FollowableItemHandle};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
item::{FollowableItem, Item, ItemEvent, ItemHandle, ProjectItem},
|
item::{FollowableItem, Item, ItemEvent, ItemHandle, ProjectItem},
|
||||||
|
@ -546,9 +549,7 @@ impl Item for Editor {
|
||||||
.and_then(|f| f.as_local())?
|
.and_then(|f| f.as_local())?
|
||||||
.abs_path(cx);
|
.abs_path(cx);
|
||||||
|
|
||||||
let file_path = util::paths::compact(&file_path)
|
let file_path = file_path.compact().to_string_lossy().to_string();
|
||||||
.to_string_lossy()
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
Some(file_path.into())
|
Some(file_path.into())
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,8 @@ impl<'a> EditorLspTestContext<'a> {
|
||||||
.insert_tree("/root", json!({ "dir": { file_name.clone(): "" }}))
|
.insert_tree("/root", json!({ "dir": { file_name.clone(): "" }}))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
project
|
project
|
||||||
.update(cx, |project, cx| {
|
.update(cx, |project, cx| {
|
||||||
project.find_or_create_local_worktree("/root", true, cx)
|
project.find_or_create_local_worktree("/root", true, cx)
|
||||||
|
@ -98,7 +99,7 @@ impl<'a> EditorLspTestContext<'a> {
|
||||||
Self {
|
Self {
|
||||||
cx: EditorTestContext {
|
cx: EditorTestContext {
|
||||||
cx,
|
cx,
|
||||||
window_id,
|
window_id: window.window_id(),
|
||||||
editor,
|
editor,
|
||||||
},
|
},
|
||||||
lsp,
|
lsp,
|
||||||
|
|
|
@ -32,16 +32,14 @@ impl<'a> EditorTestContext<'a> {
|
||||||
let buffer = project
|
let buffer = project
|
||||||
.update(cx, |project, cx| project.create_buffer("", None, cx))
|
.update(cx, |project, cx| project.create_buffer("", None, cx))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (window_id, editor) = cx.update(|cx| {
|
let window = cx.add_window(|cx| {
|
||||||
cx.add_window(Default::default(), |cx| {
|
cx.focus_self();
|
||||||
cx.focus_self();
|
build_editor(MultiBuffer::build_from_buffer(buffer, cx), cx)
|
||||||
build_editor(MultiBuffer::build_from_buffer(buffer, cx), cx)
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
let editor = window.root(cx);
|
||||||
Self {
|
Self {
|
||||||
cx,
|
cx,
|
||||||
window_id,
|
window_id: window.window_id(),
|
||||||
editor,
|
editor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -617,8 +617,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
cx.dispatch_action(window_id, Toggle);
|
let workspace = window.root(cx);
|
||||||
|
cx.dispatch_action(window.window_id(), Toggle);
|
||||||
|
|
||||||
let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
|
let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
|
||||||
finder
|
finder
|
||||||
|
@ -631,8 +632,8 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
|
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
|
||||||
cx.dispatch_action(window_id, SelectNext);
|
cx.dispatch_action(window.window_id(), SelectNext);
|
||||||
cx.dispatch_action(window_id, Confirm);
|
cx.dispatch_action(window.window_id(), Confirm);
|
||||||
active_pane
|
active_pane
|
||||||
.condition(cx, |pane, _| pane.active_item().is_some())
|
.condition(cx, |pane, _| pane.active_item().is_some())
|
||||||
.await;
|
.await;
|
||||||
|
@ -671,8 +672,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
cx.dispatch_action(window_id, Toggle);
|
let workspace = window.root(cx);
|
||||||
|
cx.dispatch_action(window.window_id(), Toggle);
|
||||||
let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
|
let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
|
||||||
|
|
||||||
let file_query = &first_file_name[..3];
|
let file_query = &first_file_name[..3];
|
||||||
|
@ -704,8 +706,8 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
|
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
|
||||||
cx.dispatch_action(window_id, SelectNext);
|
cx.dispatch_action(window.window_id(), SelectNext);
|
||||||
cx.dispatch_action(window_id, Confirm);
|
cx.dispatch_action(window.window_id(), Confirm);
|
||||||
active_pane
|
active_pane
|
||||||
.condition(cx, |pane, _| pane.active_item().is_some())
|
.condition(cx, |pane, _| pane.active_item().is_some())
|
||||||
.await;
|
.await;
|
||||||
|
@ -754,8 +756,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
cx.dispatch_action(window_id, Toggle);
|
let workspace = window.root(cx);
|
||||||
|
cx.dispatch_action(window.window_id(), Toggle);
|
||||||
let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
|
let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
|
||||||
|
|
||||||
let file_query = &first_file_name[..3];
|
let file_query = &first_file_name[..3];
|
||||||
|
@ -787,8 +790,8 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
|
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
|
||||||
cx.dispatch_action(window_id, SelectNext);
|
cx.dispatch_action(window.window_id(), SelectNext);
|
||||||
cx.dispatch_action(window_id, Confirm);
|
cx.dispatch_action(window.window_id(), Confirm);
|
||||||
active_pane
|
active_pane
|
||||||
.condition(cx, |pane, _| pane.active_item().is_some())
|
.condition(cx, |pane, _| pane.active_item().is_some())
|
||||||
.await;
|
.await;
|
||||||
|
@ -837,19 +840,23 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/dir".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/dir".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let workspace = cx
|
||||||
let (_, finder) = cx.add_window(|cx| {
|
.add_window(|cx| Workspace::test_new(project, cx))
|
||||||
Picker::new(
|
.root(cx);
|
||||||
FileFinderDelegate::new(
|
let finder = cx
|
||||||
workspace.downgrade(),
|
.add_window(|cx| {
|
||||||
workspace.read(cx).project().clone(),
|
Picker::new(
|
||||||
None,
|
FileFinderDelegate::new(
|
||||||
Vec::new(),
|
workspace.downgrade(),
|
||||||
|
workspace.read(cx).project().clone(),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
cx,
|
||||||
|
),
|
||||||
cx,
|
cx,
|
||||||
),
|
)
|
||||||
cx,
|
})
|
||||||
)
|
.root(cx);
|
||||||
});
|
|
||||||
|
|
||||||
let query = test_path_like("hi");
|
let query = test_path_like("hi");
|
||||||
finder
|
finder
|
||||||
|
@ -931,19 +938,23 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let workspace = cx
|
||||||
let (_, finder) = cx.add_window(|cx| {
|
.add_window(|cx| Workspace::test_new(project, cx))
|
||||||
Picker::new(
|
.root(cx);
|
||||||
FileFinderDelegate::new(
|
let finder = cx
|
||||||
workspace.downgrade(),
|
.add_window(|cx| {
|
||||||
workspace.read(cx).project().clone(),
|
Picker::new(
|
||||||
None,
|
FileFinderDelegate::new(
|
||||||
Vec::new(),
|
workspace.downgrade(),
|
||||||
|
workspace.read(cx).project().clone(),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
cx,
|
||||||
|
),
|
||||||
cx,
|
cx,
|
||||||
),
|
)
|
||||||
cx,
|
})
|
||||||
)
|
.root(cx);
|
||||||
});
|
|
||||||
finder
|
finder
|
||||||
.update(cx, |f, cx| {
|
.update(cx, |f, cx| {
|
||||||
f.delegate_mut().spawn_search(test_path_like("hi"), cx)
|
f.delegate_mut().spawn_search(test_path_like("hi"), cx)
|
||||||
|
@ -967,19 +978,23 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let workspace = cx
|
||||||
let (_, finder) = cx.add_window(|cx| {
|
.add_window(|cx| Workspace::test_new(project, cx))
|
||||||
Picker::new(
|
.root(cx);
|
||||||
FileFinderDelegate::new(
|
let finder = cx
|
||||||
workspace.downgrade(),
|
.add_window(|cx| {
|
||||||
workspace.read(cx).project().clone(),
|
Picker::new(
|
||||||
None,
|
FileFinderDelegate::new(
|
||||||
Vec::new(),
|
workspace.downgrade(),
|
||||||
|
workspace.read(cx).project().clone(),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
cx,
|
||||||
|
),
|
||||||
cx,
|
cx,
|
||||||
),
|
)
|
||||||
cx,
|
})
|
||||||
)
|
.root(cx);
|
||||||
});
|
|
||||||
|
|
||||||
// Even though there is only one worktree, that worktree's filename
|
// Even though there is only one worktree, that worktree's filename
|
||||||
// is included in the matching, because the worktree is a single file.
|
// is included in the matching, because the worktree is a single file.
|
||||||
|
@ -1015,61 +1030,6 @@ mod tests {
|
||||||
finder.read_with(cx, |f, _| assert_eq!(f.delegate().matches.len(), 0));
|
finder.read_with(cx, |f, _| assert_eq!(f.delegate().matches.len(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
|
||||||
async fn test_multiple_matches_with_same_relative_path(cx: &mut TestAppContext) {
|
|
||||||
let app_state = init_test(cx);
|
|
||||||
app_state
|
|
||||||
.fs
|
|
||||||
.as_fake()
|
|
||||||
.insert_tree(
|
|
||||||
"/root",
|
|
||||||
json!({
|
|
||||||
"dir1": { "a.txt": "" },
|
|
||||||
"dir2": { "a.txt": "" }
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let project = Project::test(
|
|
||||||
app_state.fs.clone(),
|
|
||||||
["/root/dir1".as_ref(), "/root/dir2".as_ref()],
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
|
||||||
|
|
||||||
let (_, finder) = cx.add_window(|cx| {
|
|
||||||
Picker::new(
|
|
||||||
FileFinderDelegate::new(
|
|
||||||
workspace.downgrade(),
|
|
||||||
workspace.read(cx).project().clone(),
|
|
||||||
None,
|
|
||||||
Vec::new(),
|
|
||||||
cx,
|
|
||||||
),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Run a search that matches two files with the same relative path.
|
|
||||||
finder
|
|
||||||
.update(cx, |f, cx| {
|
|
||||||
f.delegate_mut().spawn_search(test_path_like("a.t"), cx)
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
// Can switch between different matches with the same relative path.
|
|
||||||
finder.update(cx, |finder, cx| {
|
|
||||||
let delegate = finder.delegate_mut();
|
|
||||||
assert_eq!(delegate.matches.len(), 2);
|
|
||||||
assert_eq!(delegate.selected_index(), 0);
|
|
||||||
delegate.set_selected_index(1, cx);
|
|
||||||
assert_eq!(delegate.selected_index(), 1);
|
|
||||||
delegate.set_selected_index(0, cx);
|
|
||||||
assert_eq!(delegate.selected_index(), 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_path_distance_ordering(cx: &mut TestAppContext) {
|
async fn test_path_distance_ordering(cx: &mut TestAppContext) {
|
||||||
let app_state = init_test(cx);
|
let app_state = init_test(cx);
|
||||||
|
@ -1089,7 +1049,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project, cx))
|
||||||
|
.root(cx);
|
||||||
let worktree_id = cx.read(|cx| {
|
let worktree_id = cx.read(|cx| {
|
||||||
let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
|
let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
|
||||||
assert_eq!(worktrees.len(), 1);
|
assert_eq!(worktrees.len(), 1);
|
||||||
|
@ -1103,18 +1065,20 @@ mod tests {
|
||||||
worktree_id,
|
worktree_id,
|
||||||
path: Arc::from(Path::new("/root/dir2/b.txt")),
|
path: Arc::from(Path::new("/root/dir2/b.txt")),
|
||||||
}));
|
}));
|
||||||
let (_, finder) = cx.add_window(|cx| {
|
let finder = cx
|
||||||
Picker::new(
|
.add_window(|cx| {
|
||||||
FileFinderDelegate::new(
|
Picker::new(
|
||||||
workspace.downgrade(),
|
FileFinderDelegate::new(
|
||||||
workspace.read(cx).project().clone(),
|
workspace.downgrade(),
|
||||||
b_path,
|
workspace.read(cx).project().clone(),
|
||||||
Vec::new(),
|
b_path,
|
||||||
|
Vec::new(),
|
||||||
|
cx,
|
||||||
|
),
|
||||||
cx,
|
cx,
|
||||||
),
|
)
|
||||||
cx,
|
})
|
||||||
)
|
.root(cx);
|
||||||
});
|
|
||||||
|
|
||||||
finder
|
finder
|
||||||
.update(cx, |f, cx| {
|
.update(cx, |f, cx| {
|
||||||
|
@ -1151,19 +1115,23 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let workspace = cx
|
||||||
let (_, finder) = cx.add_window(|cx| {
|
.add_window(|cx| Workspace::test_new(project, cx))
|
||||||
Picker::new(
|
.root(cx);
|
||||||
FileFinderDelegate::new(
|
let finder = cx
|
||||||
workspace.downgrade(),
|
.add_window(|cx| {
|
||||||
workspace.read(cx).project().clone(),
|
Picker::new(
|
||||||
None,
|
FileFinderDelegate::new(
|
||||||
Vec::new(),
|
workspace.downgrade(),
|
||||||
|
workspace.read(cx).project().clone(),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
cx,
|
||||||
|
),
|
||||||
cx,
|
cx,
|
||||||
),
|
)
|
||||||
cx,
|
})
|
||||||
)
|
.root(cx);
|
||||||
});
|
|
||||||
finder
|
finder
|
||||||
.update(cx, |f, cx| {
|
.update(cx, |f, cx| {
|
||||||
f.delegate_mut().spawn_search(test_path_like("dir"), cx)
|
f.delegate_mut().spawn_search(test_path_like("dir"), cx)
|
||||||
|
@ -1198,7 +1166,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
let worktree_id = cx.read(|cx| {
|
let worktree_id = cx.read(|cx| {
|
||||||
let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
|
let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
|
||||||
assert_eq!(worktrees.len(), 1);
|
assert_eq!(worktrees.len(), 1);
|
||||||
|
@ -1404,7 +1374,9 @@ mod tests {
|
||||||
.detach();
|
.detach();
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
|
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
let worktree_id = cx.read(|cx| {
|
let worktree_id = cx.read(|cx| {
|
||||||
let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
|
let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
|
||||||
assert_eq!(worktrees.len(), 1,);
|
assert_eq!(worktrees.len(), 1,);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
platform::{Event, InputHandler, KeyDownEvent, Platform},
|
platform::{Event, InputHandler, KeyDownEvent, Platform},
|
||||||
Action, AppContext, BorrowAppContext, BorrowWindowContext, Entity, FontCache, Handle,
|
Action, AppContext, BorrowAppContext, BorrowWindowContext, Entity, FontCache, Handle,
|
||||||
ModelContext, ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakHandle,
|
ModelContext, ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakHandle,
|
||||||
WindowContext,
|
WindowContext, WindowHandle,
|
||||||
};
|
};
|
||||||
use collections::BTreeMap;
|
use collections::BTreeMap;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
|
@ -60,7 +60,7 @@ impl TestAppContext {
|
||||||
RefCounts::new(leak_detector),
|
RefCounts::new(leak_detector),
|
||||||
(),
|
(),
|
||||||
);
|
);
|
||||||
cx.next_entity_id = first_entity_id;
|
cx.next_id = first_entity_id;
|
||||||
let cx = TestAppContext {
|
let cx = TestAppContext {
|
||||||
cx: Rc::new(RefCell::new(cx)),
|
cx: Rc::new(RefCell::new(cx)),
|
||||||
foreground_platform,
|
foreground_platform,
|
||||||
|
@ -148,17 +148,18 @@ impl TestAppContext {
|
||||||
self.cx.borrow_mut().add_model(build_model)
|
self.cx.borrow_mut().add_model(build_model)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_window<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
|
pub fn add_window<T, F>(&mut self, build_root_view: F) -> WindowHandle<T>
|
||||||
where
|
where
|
||||||
T: View,
|
T: View,
|
||||||
F: FnOnce(&mut ViewContext<T>) -> T,
|
F: FnOnce(&mut ViewContext<T>) -> T,
|
||||||
{
|
{
|
||||||
let (window_id, view) = self
|
let window = self
|
||||||
.cx
|
.cx
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.add_window(Default::default(), build_root_view);
|
.add_window(Default::default(), build_root_view);
|
||||||
self.simulate_window_activation(Some(window_id));
|
self.simulate_window_activation(Some(window.window_id()));
|
||||||
(window_id, view)
|
|
||||||
|
WindowHandle::new(window.window_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
|
pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
|
||||||
|
@ -405,14 +406,20 @@ impl BorrowAppContext for TestAppContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BorrowWindowContext for TestAppContext {
|
impl BorrowWindowContext for TestAppContext {
|
||||||
fn read_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
|
type Result<T> = T;
|
||||||
|
|
||||||
|
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
|
||||||
self.cx
|
self.cx
|
||||||
.borrow()
|
.borrow()
|
||||||
.read_window(window_id, f)
|
.read_window(window_id, f)
|
||||||
.expect("window was closed")
|
.expect("window was closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update<T, F: FnOnce(&mut WindowContext) -> T>(&mut self, window_id: usize, f: F) -> T {
|
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
|
||||||
|
&mut self,
|
||||||
|
window_id: usize,
|
||||||
|
f: F,
|
||||||
|
) -> T {
|
||||||
self.cx
|
self.cx
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.update_window(window_id, f)
|
.update_window(window_id, f)
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
util::post_inc,
|
util::post_inc,
|
||||||
Action, AnyView, AnyViewHandle, AppContext, BorrowAppContext, BorrowWindowContext, Effect,
|
Action, AnyView, AnyViewHandle, AppContext, BorrowAppContext, BorrowWindowContext, Effect,
|
||||||
Element, Entity, Handle, LayoutContext, MouseRegion, MouseRegionId, SceneBuilder, Subscription,
|
Element, Entity, Handle, LayoutContext, MouseRegion, MouseRegionId, SceneBuilder, Subscription,
|
||||||
View, ViewContext, ViewHandle, WindowInvalidation,
|
View, ViewContext, ViewHandle, WindowHandle, WindowInvalidation,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
|
@ -142,7 +142,9 @@ impl BorrowAppContext for WindowContext<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BorrowWindowContext for WindowContext<'_> {
|
impl BorrowWindowContext for WindowContext<'_> {
|
||||||
fn read_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
|
type Result<T> = T;
|
||||||
|
|
||||||
|
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
|
||||||
if self.window_id == window_id {
|
if self.window_id == window_id {
|
||||||
f(self)
|
f(self)
|
||||||
} else {
|
} else {
|
||||||
|
@ -150,7 +152,11 @@ impl BorrowWindowContext for WindowContext<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update<T, F: FnOnce(&mut WindowContext) -> T>(&mut self, window_id: usize, f: F) -> T {
|
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
|
||||||
|
&mut self,
|
||||||
|
window_id: usize,
|
||||||
|
f: F,
|
||||||
|
) -> T {
|
||||||
if self.window_id == window_id {
|
if self.window_id == window_id {
|
||||||
f(self)
|
f(self)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1151,15 +1157,15 @@ impl<'a> WindowContext<'a> {
|
||||||
self.window.platform_window.prompt(level, msg, answers)
|
self.window.platform_window.prompt(level, msg, answers)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_root_view<V, F>(&mut self, build_root_view: F) -> ViewHandle<V>
|
pub fn replace_root_view<V, F>(&mut self, build_root_view: F) -> WindowHandle<V>
|
||||||
where
|
where
|
||||||
V: View,
|
V: View,
|
||||||
F: FnOnce(&mut ViewContext<V>) -> V,
|
F: FnOnce(&mut ViewContext<V>) -> V,
|
||||||
{
|
{
|
||||||
let root_view = self.add_view(|cx| build_root_view(cx));
|
let root_view = self.add_view(|cx| build_root_view(cx));
|
||||||
self.window.root_view = Some(root_view.clone().into_any());
|
|
||||||
self.window.focused_view_id = Some(root_view.id());
|
self.window.focused_view_id = Some(root_view.id());
|
||||||
root_view
|
self.window.root_view = Some(root_view.into_any());
|
||||||
|
WindowHandle::new(self.window_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_view<T, F>(&mut self, build_view: F) -> ViewHandle<T>
|
pub fn add_view<T, F>(&mut self, build_view: F) -> ViewHandle<T>
|
||||||
|
@ -1176,7 +1182,7 @@ impl<'a> WindowContext<'a> {
|
||||||
F: FnOnce(&mut ViewContext<T>) -> Option<T>,
|
F: FnOnce(&mut ViewContext<T>) -> Option<T>,
|
||||||
{
|
{
|
||||||
let window_id = self.window_id;
|
let window_id = self.window_id;
|
||||||
let view_id = post_inc(&mut self.next_entity_id);
|
let view_id = post_inc(&mut self.next_id);
|
||||||
let mut cx = ViewContext::mutable(self, view_id);
|
let mut cx = ViewContext::mutable(self, view_id);
|
||||||
let handle = if let Some(view) = build_view(&mut cx) {
|
let handle = if let Some(view) = build_view(&mut cx) {
|
||||||
let mut keymap_context = KeymapContext::default();
|
let mut keymap_context = KeymapContext::default();
|
||||||
|
|
|
@ -61,7 +61,9 @@ async fn test_lsp_logs(cx: &mut TestAppContext) {
|
||||||
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let (_, log_view) = cx.add_window(|cx| LspLogView::new(project.clone(), log_store.clone(), cx));
|
let log_view = cx
|
||||||
|
.add_window(|cx| LspLogView::new(project.clone(), log_store.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
|
|
||||||
language_server.notify::<lsp::notification::LogMessage>(lsp::LogMessageParams {
|
language_server.notify::<lsp::notification::LogMessage>(lsp::LogMessageParams {
|
||||||
message: "hello from the server".into(),
|
message: "hello from the server".into(),
|
||||||
|
|
|
@ -4,7 +4,7 @@ use collections::HashMap;
|
||||||
|
|
||||||
use gpui::{AppContext, AssetSource};
|
use gpui::{AppContext, AssetSource};
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
use util::iife;
|
use util::{iife, paths::PathExt};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct TypeConfig {
|
struct TypeConfig {
|
||||||
|
@ -48,14 +48,7 @@ impl FileAssociations {
|
||||||
// FIXME: Associate a type with the languages and have the file's langauge
|
// FIXME: Associate a type with the languages and have the file's langauge
|
||||||
// override these associations
|
// override these associations
|
||||||
iife!({
|
iife!({
|
||||||
let suffix = path
|
let suffix = path.icon_suffix()?;
|
||||||
.file_name()
|
|
||||||
.and_then(|os_str| os_str.to_str())
|
|
||||||
.and_then(|file_name| {
|
|
||||||
file_name
|
|
||||||
.find('.')
|
|
||||||
.and_then(|dot_index| file_name.get(dot_index + 1..))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
this.suffixes
|
this.suffixes
|
||||||
.get(suffix)
|
.get(suffix)
|
||||||
|
|
|
@ -1756,7 +1756,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
visible_entries_as_strings(&panel, 0..50, cx),
|
visible_entries_as_strings(&panel, 0..50, cx),
|
||||||
|
@ -1844,7 +1846,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
||||||
|
|
||||||
select_path(&panel, "root1", cx);
|
select_path(&panel, "root1", cx);
|
||||||
|
@ -2195,7 +2199,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
||||||
|
|
||||||
select_path(&panel, "root1", cx);
|
select_path(&panel, "root1", cx);
|
||||||
|
@ -2295,7 +2301,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), ["/root1".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/root1".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
||||||
|
|
||||||
panel.update(cx, |panel, cx| {
|
panel.update(cx, |panel, cx| {
|
||||||
|
@ -2368,7 +2376,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
||||||
|
|
||||||
toggle_expand_dir(&panel, "src/test", cx);
|
toggle_expand_dir(&panel, "src/test", cx);
|
||||||
|
@ -2457,7 +2467,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
||||||
|
|
||||||
select_path(&panel, "src/", cx);
|
select_path(&panel, "src/", cx);
|
||||||
|
@ -2603,7 +2615,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
||||||
|
|
||||||
let new_search_events_count = Arc::new(AtomicUsize::new(0));
|
let new_search_events_count = Arc::new(AtomicUsize::new(0));
|
||||||
|
@ -2690,7 +2704,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), ["/project_root".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/project_root".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
|
||||||
|
|
||||||
panel.update(cx, |panel, cx| {
|
panel.update(cx, |panel, cx| {
|
||||||
|
|
|
@ -326,7 +326,9 @@ mod tests {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
// Create the project symbols view.
|
// Create the project symbols view.
|
||||||
let symbols = cx.add_view(window_id, |cx| {
|
let symbols = cx.add_view(window_id, |cx| {
|
||||||
|
|
|
@ -5,6 +5,7 @@ use gpui::{
|
||||||
elements::{Label, LabelStyle},
|
elements::{Label, LabelStyle},
|
||||||
AnyElement, Element, View,
|
AnyElement, Element, View,
|
||||||
};
|
};
|
||||||
|
use util::paths::PathExt;
|
||||||
use workspace::WorkspaceLocation;
|
use workspace::WorkspaceLocation;
|
||||||
|
|
||||||
pub struct HighlightedText {
|
pub struct HighlightedText {
|
||||||
|
@ -61,7 +62,7 @@ impl HighlightedWorkspaceLocation {
|
||||||
.paths()
|
.paths()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|path| {
|
.map(|path| {
|
||||||
let path = util::paths::compact(&path);
|
let path = path.compact();
|
||||||
let highlighted_text = Self::highlights_for_path(
|
let highlighted_text = Self::highlights_for_path(
|
||||||
path.as_ref(),
|
path.as_ref(),
|
||||||
&string_match.positions,
|
&string_match.positions,
|
||||||
|
|
|
@ -11,6 +11,7 @@ use highlighted_workspace_location::HighlightedWorkspaceLocation;
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use picker::{Picker, PickerDelegate, PickerEvent};
|
use picker::{Picker, PickerDelegate, PickerEvent};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use util::paths::PathExt;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
notifications::simple_message_notification::MessageNotification, Workspace, WorkspaceLocation,
|
notifications::simple_message_notification::MessageNotification, Workspace, WorkspaceLocation,
|
||||||
WORKSPACE_DB,
|
WORKSPACE_DB,
|
||||||
|
@ -134,7 +135,7 @@ impl PickerDelegate for RecentProjectsDelegate {
|
||||||
let combined_string = location
|
let combined_string = location
|
||||||
.paths()
|
.paths()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|path| util::paths::compact(&path).to_string_lossy().into_owned())
|
.map(|path| path.compact().to_string_lossy().into_owned())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("");
|
.join("");
|
||||||
StringMatchCandidate::new(id, combined_string)
|
StringMatchCandidate::new(id, combined_string)
|
||||||
|
|
|
@ -849,11 +849,13 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let (window_id, _root_view) = cx.add_window(|_| EmptyView);
|
let window = cx.add_window(|_| EmptyView);
|
||||||
|
|
||||||
let editor = cx.add_view(window_id, |cx| Editor::for_buffer(buffer.clone(), None, cx));
|
let editor = cx.add_view(window.window_id(), |cx| {
|
||||||
|
Editor::for_buffer(buffer.clone(), None, cx)
|
||||||
|
});
|
||||||
|
|
||||||
let search_bar = cx.add_view(window_id, |cx| {
|
let search_bar = cx.add_view(window.window_id(), |cx| {
|
||||||
let mut search_bar = BufferSearchBar::new(cx);
|
let mut search_bar = BufferSearchBar::new(cx);
|
||||||
search_bar.set_active_pane_item(Some(&editor), cx);
|
search_bar.set_active_pane_item(Some(&editor), cx);
|
||||||
search_bar.show(cx);
|
search_bar.show(cx);
|
||||||
|
@ -1229,7 +1231,8 @@ mod tests {
|
||||||
"Should pick a query with multiple results"
|
"Should pick a query with multiple results"
|
||||||
);
|
);
|
||||||
let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx));
|
let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx));
|
||||||
let (window_id, _root_view) = cx.add_window(|_| EmptyView);
|
let window = cx.add_window(|_| EmptyView);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
let editor = cx.add_view(window_id, |cx| Editor::for_buffer(buffer.clone(), None, cx));
|
let editor = cx.add_view(window_id, |cx| Editor::for_buffer(buffer.clone(), None, cx));
|
||||||
|
|
||||||
|
@ -1416,11 +1419,13 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
.unindent();
|
.unindent();
|
||||||
let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx));
|
let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx));
|
||||||
let (window_id, _root_view) = cx.add_window(|_| EmptyView);
|
let window = cx.add_window(|_| EmptyView);
|
||||||
|
|
||||||
let editor = cx.add_view(window_id, |cx| Editor::for_buffer(buffer.clone(), None, cx));
|
let editor = cx.add_view(window.window_id(), |cx| {
|
||||||
|
Editor::for_buffer(buffer.clone(), None, cx)
|
||||||
|
});
|
||||||
|
|
||||||
let search_bar = cx.add_view(window_id, |cx| {
|
let search_bar = cx.add_view(window.window_id(), |cx| {
|
||||||
let mut search_bar = BufferSearchBar::new(cx);
|
let mut search_bar = BufferSearchBar::new(cx);
|
||||||
search_bar.set_active_pane_item(Some(&editor), cx);
|
search_bar.set_active_pane_item(Some(&editor), cx);
|
||||||
search_bar.show(cx);
|
search_bar.show(cx);
|
||||||
|
|
|
@ -1447,7 +1447,9 @@ pub mod tests {
|
||||||
.await;
|
.await;
|
||||||
let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
|
||||||
let search = cx.add_model(|cx| ProjectSearch::new(project, cx));
|
let search = cx.add_model(|cx| ProjectSearch::new(project, cx));
|
||||||
let (_, search_view) = cx.add_window(|cx| ProjectSearchView::new(search.clone(), cx));
|
let search_view = cx
|
||||||
|
.add_window(|cx| ProjectSearchView::new(search.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
|
|
||||||
search_view.update(cx, |search_view, cx| {
|
search_view.update(cx, |search_view, cx| {
|
||||||
search_view
|
search_view
|
||||||
|
@ -1564,7 +1566,9 @@ pub mod tests {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
let active_item = cx.read(|cx| {
|
let active_item = cx.read(|cx| {
|
||||||
workspace
|
workspace
|
||||||
|
@ -1748,7 +1752,9 @@ pub mod tests {
|
||||||
let worktree_id = project.read_with(cx, |project, cx| {
|
let worktree_id = project.read_with(cx, |project, cx| {
|
||||||
project.worktrees(cx).next().unwrap().read(cx).id()
|
project.worktrees(cx).next().unwrap().read(cx).id()
|
||||||
});
|
});
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project, cx))
|
||||||
|
.root(cx);
|
||||||
|
|
||||||
let active_item = cx.read(|cx| {
|
let active_item = cx.read(|cx| {
|
||||||
workspace
|
workspace
|
||||||
|
@ -1866,7 +1872,9 @@ pub mod tests {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
|
let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
workspace.update(cx, |workspace, cx| {
|
workspace.update(cx, |workspace, cx| {
|
||||||
ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
|
ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
|
||||||
});
|
});
|
||||||
|
|
|
@ -1070,7 +1070,9 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
let project = Project::test(params.fs.clone(), [], cx).await;
|
let project = Project::test(params.fs.clone(), [], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
|
|
||||||
(project, workspace)
|
(project, workspace)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,49 +30,47 @@ pub mod legacy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compacts a given file path by replacing the user's home directory
|
pub trait PathExt {
|
||||||
/// prefix with a tilde (`~`).
|
fn compact(&self) -> PathBuf;
|
||||||
///
|
fn icon_suffix(&self) -> Option<&str>;
|
||||||
/// # Arguments
|
}
|
||||||
///
|
|
||||||
/// * `path` - A reference to a `Path` representing the file path to compact.
|
impl<T: AsRef<Path>> PathExt for T {
|
||||||
///
|
/// Compacts a given file path by replacing the user's home directory
|
||||||
/// # Examples
|
/// prefix with a tilde (`~`).
|
||||||
///
|
///
|
||||||
/// ```
|
/// # Returns
|
||||||
/// use std::path::{Path, PathBuf};
|
///
|
||||||
/// use util::paths::compact;
|
/// * A `PathBuf` containing the compacted file path. If the input path
|
||||||
/// let path: PathBuf = [
|
/// does not have the user's home directory prefix, or if we are not on
|
||||||
/// util::paths::HOME.to_string_lossy().to_string(),
|
/// Linux or macOS, the original path is returned unchanged.
|
||||||
/// "some_file.txt".to_string(),
|
fn compact(&self) -> PathBuf {
|
||||||
/// ]
|
if cfg!(target_os = "linux") || cfg!(target_os = "macos") {
|
||||||
/// .iter()
|
match self.as_ref().strip_prefix(HOME.as_path()) {
|
||||||
/// .collect();
|
Ok(relative_path) => {
|
||||||
/// if cfg!(target_os = "linux") || cfg!(target_os = "macos") {
|
let mut shortened_path = PathBuf::new();
|
||||||
/// assert_eq!(compact(&path).to_str(), Some("~/some_file.txt"));
|
shortened_path.push("~");
|
||||||
/// } else {
|
shortened_path.push(relative_path);
|
||||||
/// assert_eq!(compact(&path).to_str(), path.to_str());
|
shortened_path
|
||||||
/// }
|
}
|
||||||
/// ```
|
Err(_) => self.as_ref().to_path_buf(),
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// * A `PathBuf` containing the compacted file path. If the input path
|
|
||||||
/// does not have the user's home directory prefix, or if we are not on
|
|
||||||
/// Linux or macOS, the original path is returned unchanged.
|
|
||||||
pub fn compact(path: &Path) -> PathBuf {
|
|
||||||
if cfg!(target_os = "linux") || cfg!(target_os = "macos") {
|
|
||||||
match path.strip_prefix(HOME.as_path()) {
|
|
||||||
Ok(relative_path) => {
|
|
||||||
let mut shortened_path = PathBuf::new();
|
|
||||||
shortened_path.push("~");
|
|
||||||
shortened_path.push(relative_path);
|
|
||||||
shortened_path
|
|
||||||
}
|
}
|
||||||
Err(_) => path.to_path_buf(),
|
} else {
|
||||||
|
self.as_ref().to_path_buf()
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
path.to_path_buf()
|
|
||||||
|
fn icon_suffix(&self) -> Option<&str> {
|
||||||
|
let file_name = self.as_ref().file_name()?.to_str()?;
|
||||||
|
|
||||||
|
if file_name.starts_with(".") {
|
||||||
|
return file_name.strip_prefix(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.as_ref()
|
||||||
|
.extension()
|
||||||
|
.map(|extension| extension.to_str())
|
||||||
|
.flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,4 +277,42 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_path_compact() {
|
||||||
|
let path: PathBuf = [
|
||||||
|
HOME.to_string_lossy().to_string(),
|
||||||
|
"some_file.txt".to_string(),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
|
if cfg!(target_os = "linux") || cfg!(target_os = "macos") {
|
||||||
|
assert_eq!(path.compact().to_str(), Some("~/some_file.txt"));
|
||||||
|
} else {
|
||||||
|
assert_eq!(path.compact().to_str(), path.to_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_path_suffix() {
|
||||||
|
// No dots in name
|
||||||
|
let path = Path::new("/a/b/c/file_name.rs");
|
||||||
|
assert_eq!(path.icon_suffix(), Some("rs"));
|
||||||
|
|
||||||
|
// Single dot in name
|
||||||
|
let path = Path::new("/a/b/c/file.name.rs");
|
||||||
|
assert_eq!(path.icon_suffix(), Some("rs"));
|
||||||
|
|
||||||
|
// Multiple dots in name
|
||||||
|
let path = Path::new("/a/b/c/long.file.name.rs");
|
||||||
|
assert_eq!(path.icon_suffix(), Some("rs"));
|
||||||
|
|
||||||
|
// Hidden file, no extension
|
||||||
|
let path = Path::new("/a/b/c/.gitignore");
|
||||||
|
assert_eq!(path.icon_suffix(), Some("gitignore"));
|
||||||
|
|
||||||
|
// Hidden file, with extension
|
||||||
|
let path = Path::new("/a/b/c/.eslintrc.js");
|
||||||
|
assert_eq!(path.icon_suffix(), Some("eslintrc.js"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,8 @@ pub trait Panel: View {
|
||||||
fn is_zoomed(&self, _cx: &WindowContext) -> bool {
|
fn is_zoomed(&self, _cx: &WindowContext) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
fn set_zoomed(&mut self, _zoomed: bool, _cx: &mut ViewContext<Self>) {
|
fn set_zoomed(&mut self, _zoomed: bool, _cx: &mut ViewContext<Self>) {}
|
||||||
|
fn set_active(&mut self, _active: bool, _cx: &mut ViewContext<Self>) {}
|
||||||
}
|
|
||||||
fn set_active(&mut self, _active: bool, _cx: &mut ViewContext<Self>) {
|
|
||||||
|
|
||||||
}
|
|
||||||
fn should_activate_on_event(_: &Self::Event) -> bool {
|
fn should_activate_on_event(_: &Self::Event) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1972,7 +1972,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
pane.update(cx, |pane, cx| {
|
pane.update(cx, |pane, cx| {
|
||||||
|
@ -1987,7 +1988,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
// 1. Add with a destination index
|
// 1. Add with a destination index
|
||||||
|
@ -2065,7 +2067,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
// 1. Add with a destination index
|
// 1. Add with a destination index
|
||||||
|
@ -2141,7 +2144,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
// singleton view
|
// singleton view
|
||||||
|
@ -2209,7 +2213,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
add_labeled_item(&pane, "A", false, cx);
|
add_labeled_item(&pane, "A", false, cx);
|
||||||
|
@ -2256,7 +2261,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
||||||
|
@ -2276,7 +2282,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
add_labeled_item(&pane, "A", true, cx);
|
add_labeled_item(&pane, "A", true, cx);
|
||||||
|
@ -2299,7 +2306,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
||||||
|
@ -2319,7 +2327,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
||||||
|
@ -2339,7 +2348,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
add_labeled_item(&pane, "A", false, cx);
|
add_labeled_item(&pane, "A", false, cx);
|
||||||
|
|
|
@ -797,67 +797,59 @@ impl Workspace {
|
||||||
DB.next_id().await.unwrap_or(0)
|
DB.next_id().await.unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
let workspace = requesting_window_id
|
let window = requesting_window_id.and_then(|window_id| {
|
||||||
.and_then(|window_id| {
|
cx.update(|cx| {
|
||||||
cx.update(|cx| {
|
cx.replace_root_view(window_id, |cx| {
|
||||||
cx.replace_root_view(window_id, |cx| {
|
Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
|
||||||
Workspace::new(
|
|
||||||
workspace_id,
|
|
||||||
project_handle.clone(),
|
|
||||||
app_state.clone(),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
});
|
||||||
let window_bounds_override = window_bounds_env_override(&cx);
|
let window = window.unwrap_or_else(|| {
|
||||||
let (bounds, display) = if let Some(bounds) = window_bounds_override {
|
let window_bounds_override = window_bounds_env_override(&cx);
|
||||||
(Some(bounds), None)
|
let (bounds, display) = if let Some(bounds) = window_bounds_override {
|
||||||
} else {
|
(Some(bounds), None)
|
||||||
serialized_workspace
|
} else {
|
||||||
.as_ref()
|
serialized_workspace
|
||||||
.and_then(|serialized_workspace| {
|
.as_ref()
|
||||||
let display = serialized_workspace.display?;
|
.and_then(|serialized_workspace| {
|
||||||
let mut bounds = serialized_workspace.bounds?;
|
let display = serialized_workspace.display?;
|
||||||
|
let mut bounds = serialized_workspace.bounds?;
|
||||||
|
|
||||||
// Stored bounds are relative to the containing display.
|
// Stored bounds are relative to the containing display.
|
||||||
// So convert back to global coordinates if that screen still exists
|
// So convert back to global coordinates if that screen still exists
|
||||||
if let WindowBounds::Fixed(mut window_bounds) = bounds {
|
if let WindowBounds::Fixed(mut window_bounds) = bounds {
|
||||||
if let Some(screen) = cx.platform().screen_by_id(display) {
|
if let Some(screen) = cx.platform().screen_by_id(display) {
|
||||||
let screen_bounds = screen.bounds();
|
let screen_bounds = screen.bounds();
|
||||||
window_bounds.set_origin_x(
|
window_bounds.set_origin_x(
|
||||||
window_bounds.origin_x() + screen_bounds.origin_x(),
|
window_bounds.origin_x() + screen_bounds.origin_x(),
|
||||||
);
|
);
|
||||||
window_bounds.set_origin_y(
|
window_bounds.set_origin_y(
|
||||||
window_bounds.origin_y() + screen_bounds.origin_y(),
|
window_bounds.origin_y() + screen_bounds.origin_y(),
|
||||||
);
|
);
|
||||||
bounds = WindowBounds::Fixed(window_bounds);
|
bounds = WindowBounds::Fixed(window_bounds);
|
||||||
} else {
|
} else {
|
||||||
// Screen no longer exists. Return none here.
|
// Screen no longer exists. Return none here.
|
||||||
return None;
|
return None;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Some((bounds, display))
|
Some((bounds, display))
|
||||||
})
|
})
|
||||||
.unzip()
|
.unzip()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use the serialized workspace to construct the new window
|
// Use the serialized workspace to construct the new window
|
||||||
cx.add_window(
|
cx.add_window(
|
||||||
(app_state.build_window_options)(bounds, display, cx.platform().as_ref()),
|
(app_state.build_window_options)(bounds, display, cx.platform().as_ref()),
|
||||||
|cx| {
|
|cx| {
|
||||||
Workspace::new(
|
Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
|
||||||
workspace_id,
|
},
|
||||||
project_handle.clone(),
|
)
|
||||||
app_state.clone(),
|
});
|
||||||
cx,
|
|
||||||
)
|
// We haven't yielded the main thread since obtaining the window handle,
|
||||||
},
|
// so the window exists.
|
||||||
)
|
let workspace = window.root(&cx).unwrap();
|
||||||
.1
|
|
||||||
});
|
|
||||||
|
|
||||||
(app_state.initialize_workspace)(
|
(app_state.initialize_workspace)(
|
||||||
workspace.downgrade(),
|
workspace.downgrade(),
|
||||||
|
@ -868,7 +860,7 @@ impl Workspace {
|
||||||
.await
|
.await
|
||||||
.log_err();
|
.log_err();
|
||||||
|
|
||||||
cx.update_window(workspace.window_id(), |cx| cx.activate_window());
|
window.update(&mut cx, |cx| cx.activate_window());
|
||||||
|
|
||||||
let workspace = workspace.downgrade();
|
let workspace = workspace.downgrade();
|
||||||
notify_if_database_failed(&workspace, &mut cx);
|
notify_if_database_failed(&workspace, &mut cx);
|
||||||
|
@ -3987,7 +3979,7 @@ pub fn join_remote_project(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let window_bounds_override = window_bounds_env_override(&cx);
|
let window_bounds_override = window_bounds_env_override(&cx);
|
||||||
let (_, workspace) = cx.add_window(
|
let window = cx.add_window(
|
||||||
(app_state.build_window_options)(
|
(app_state.build_window_options)(
|
||||||
window_bounds_override,
|
window_bounds_override,
|
||||||
None,
|
None,
|
||||||
|
@ -3995,6 +3987,7 @@ pub fn join_remote_project(
|
||||||
),
|
),
|
||||||
|cx| Workspace::new(0, project, app_state.clone(), cx),
|
|cx| Workspace::new(0, project, app_state.clone(), cx),
|
||||||
);
|
);
|
||||||
|
let workspace = window.root(&cx).unwrap();
|
||||||
(app_state.initialize_workspace)(
|
(app_state.initialize_workspace)(
|
||||||
workspace.downgrade(),
|
workspace.downgrade(),
|
||||||
false,
|
false,
|
||||||
|
@ -4123,10 +4116,11 @@ mod tests {
|
||||||
|
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
let project = Project::test(fs, [], cx).await;
|
let project = Project::test(fs, [], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
|
||||||
// Adding an item with no ambiguity renders the tab without detail.
|
// Adding an item with no ambiguity renders the tab without detail.
|
||||||
let item1 = cx.add_view(window_id, |_| {
|
let item1 = window.add_view(cx, |_| {
|
||||||
let mut item = TestItem::new();
|
let mut item = TestItem::new();
|
||||||
item.tab_descriptions = Some(vec!["c", "b1/c", "a/b1/c"]);
|
item.tab_descriptions = Some(vec!["c", "b1/c", "a/b1/c"]);
|
||||||
item
|
item
|
||||||
|
@ -4138,7 +4132,7 @@ mod tests {
|
||||||
|
|
||||||
// Adding an item that creates ambiguity increases the level of detail on
|
// Adding an item that creates ambiguity increases the level of detail on
|
||||||
// both tabs.
|
// both tabs.
|
||||||
let item2 = cx.add_view(window_id, |_| {
|
let item2 = window.add_view(cx, |_| {
|
||||||
let mut item = TestItem::new();
|
let mut item = TestItem::new();
|
||||||
item.tab_descriptions = Some(vec!["c", "b2/c", "a/b2/c"]);
|
item.tab_descriptions = Some(vec!["c", "b2/c", "a/b2/c"]);
|
||||||
item
|
item
|
||||||
|
@ -4152,7 +4146,7 @@ mod tests {
|
||||||
// Adding an item that creates ambiguity increases the level of detail only
|
// Adding an item that creates ambiguity increases the level of detail only
|
||||||
// on the ambiguous tabs. In this case, the ambiguity can't be resolved so
|
// on the ambiguous tabs. In this case, the ambiguity can't be resolved so
|
||||||
// we stop at the highest detail available.
|
// we stop at the highest detail available.
|
||||||
let item3 = cx.add_view(window_id, |_| {
|
let item3 = window.add_view(cx, |_| {
|
||||||
let mut item = TestItem::new();
|
let mut item = TestItem::new();
|
||||||
item.tab_descriptions = Some(vec!["c", "b2/c", "a/b2/c"]);
|
item.tab_descriptions = Some(vec!["c", "b2/c", "a/b2/c"]);
|
||||||
item
|
item
|
||||||
|
@ -4187,16 +4181,17 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs, ["root1".as_ref()], cx).await;
|
let project = Project::test(fs, ["root1".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
let worktree_id = project.read_with(cx, |project, cx| {
|
let worktree_id = project.read_with(cx, |project, cx| {
|
||||||
project.worktrees(cx).next().unwrap().read(cx).id()
|
project.worktrees(cx).next().unwrap().read(cx).id()
|
||||||
});
|
});
|
||||||
|
|
||||||
let item1 = cx.add_view(window_id, |cx| {
|
let item1 = window.add_view(cx, |cx| {
|
||||||
TestItem::new().with_project_items(&[TestProjectItem::new(1, "one.txt", cx)])
|
TestItem::new().with_project_items(&[TestProjectItem::new(1, "one.txt", cx)])
|
||||||
});
|
});
|
||||||
let item2 = cx.add_view(window_id, |cx| {
|
let item2 = window.add_view(cx, |cx| {
|
||||||
TestItem::new().with_project_items(&[TestProjectItem::new(2, "two.txt", cx)])
|
TestItem::new().with_project_items(&[TestProjectItem::new(2, "two.txt", cx)])
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4211,14 +4206,14 @@ mod tests {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.current_window_title(window_id).as_deref(),
|
cx.current_window_title(window.window_id()).as_deref(),
|
||||||
Some("one.txt — root1")
|
Some("one.txt — root1")
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add a second item to a non-empty pane
|
// Add a second item to a non-empty pane
|
||||||
workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item2), cx));
|
workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item2), cx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.current_window_title(window_id).as_deref(),
|
cx.current_window_title(window.window_id()).as_deref(),
|
||||||
Some("two.txt — root1")
|
Some("two.txt — root1")
|
||||||
);
|
);
|
||||||
project.read_with(cx, |project, cx| {
|
project.read_with(cx, |project, cx| {
|
||||||
|
@ -4237,7 +4232,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.current_window_title(window_id).as_deref(),
|
cx.current_window_title(window.window_id()).as_deref(),
|
||||||
Some("one.txt — root1")
|
Some("one.txt — root1")
|
||||||
);
|
);
|
||||||
project.read_with(cx, |project, cx| {
|
project.read_with(cx, |project, cx| {
|
||||||
|
@ -4257,14 +4252,14 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.current_window_title(window_id).as_deref(),
|
cx.current_window_title(window.window_id()).as_deref(),
|
||||||
Some("one.txt — root1, root2")
|
Some("one.txt — root1, root2")
|
||||||
);
|
);
|
||||||
|
|
||||||
// Remove a project folder
|
// Remove a project folder
|
||||||
project.update(cx, |project, cx| project.remove_worktree(worktree_id, cx));
|
project.update(cx, |project, cx| project.remove_worktree(worktree_id, cx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.current_window_title(window_id).as_deref(),
|
cx.current_window_title(window.window_id()).as_deref(),
|
||||||
Some("one.txt — root2")
|
Some("one.txt — root2")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4277,18 +4272,19 @@ mod tests {
|
||||||
fs.insert_tree("/root", json!({ "one": "" })).await;
|
fs.insert_tree("/root", json!({ "one": "" })).await;
|
||||||
|
|
||||||
let project = Project::test(fs, ["root".as_ref()], cx).await;
|
let project = Project::test(fs, ["root".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
|
||||||
// When there are no dirty items, there's nothing to do.
|
// When there are no dirty items, there's nothing to do.
|
||||||
let item1 = cx.add_view(window_id, |_| TestItem::new());
|
let item1 = window.add_view(cx, |_| TestItem::new());
|
||||||
workspace.update(cx, |w, cx| w.add_item(Box::new(item1.clone()), cx));
|
workspace.update(cx, |w, cx| w.add_item(Box::new(item1.clone()), cx));
|
||||||
let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx));
|
let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx));
|
||||||
assert!(task.await.unwrap());
|
assert!(task.await.unwrap());
|
||||||
|
|
||||||
// When there are dirty untitled items, prompt to save each one. If the user
|
// When there are dirty untitled items, prompt to save each one. If the user
|
||||||
// cancels any prompt, then abort.
|
// cancels any prompt, then abort.
|
||||||
let item2 = cx.add_view(window_id, |_| TestItem::new().with_dirty(true));
|
let item2 = window.add_view(cx, |_| TestItem::new().with_dirty(true));
|
||||||
let item3 = cx.add_view(window_id, |cx| {
|
let item3 = window.add_view(cx, |cx| {
|
||||||
TestItem::new()
|
TestItem::new()
|
||||||
.with_dirty(true)
|
.with_dirty(true)
|
||||||
.with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
|
.with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
|
||||||
|
@ -4299,9 +4295,9 @@ mod tests {
|
||||||
});
|
});
|
||||||
let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx));
|
let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx));
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
cx.simulate_prompt_answer(window_id, 2 /* cancel */);
|
cx.simulate_prompt_answer(window.window_id(), 2 /* cancel */);
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
assert!(!cx.has_pending_prompt(window_id));
|
assert!(!cx.has_pending_prompt(window.window_id()));
|
||||||
assert!(!task.await.unwrap());
|
assert!(!task.await.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4312,26 +4308,27 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, None, cx).await;
|
let project = Project::test(fs, None, cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
|
||||||
let item1 = cx.add_view(window_id, |cx| {
|
let item1 = window.add_view(cx, |cx| {
|
||||||
TestItem::new()
|
TestItem::new()
|
||||||
.with_dirty(true)
|
.with_dirty(true)
|
||||||
.with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
|
.with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
|
||||||
});
|
});
|
||||||
let item2 = cx.add_view(window_id, |cx| {
|
let item2 = window.add_view(cx, |cx| {
|
||||||
TestItem::new()
|
TestItem::new()
|
||||||
.with_dirty(true)
|
.with_dirty(true)
|
||||||
.with_conflict(true)
|
.with_conflict(true)
|
||||||
.with_project_items(&[TestProjectItem::new(2, "2.txt", cx)])
|
.with_project_items(&[TestProjectItem::new(2, "2.txt", cx)])
|
||||||
});
|
});
|
||||||
let item3 = cx.add_view(window_id, |cx| {
|
let item3 = window.add_view(cx, |cx| {
|
||||||
TestItem::new()
|
TestItem::new()
|
||||||
.with_dirty(true)
|
.with_dirty(true)
|
||||||
.with_conflict(true)
|
.with_conflict(true)
|
||||||
.with_project_items(&[TestProjectItem::new(3, "3.txt", cx)])
|
.with_project_items(&[TestProjectItem::new(3, "3.txt", cx)])
|
||||||
});
|
});
|
||||||
let item4 = cx.add_view(window_id, |cx| {
|
let item4 = window.add_view(cx, |cx| {
|
||||||
TestItem::new()
|
TestItem::new()
|
||||||
.with_dirty(true)
|
.with_dirty(true)
|
||||||
.with_project_items(&[TestProjectItem::new_untitled(cx)])
|
.with_project_items(&[TestProjectItem::new_untitled(cx)])
|
||||||
|
@ -4359,10 +4356,10 @@ mod tests {
|
||||||
assert_eq!(pane.items_len(), 4);
|
assert_eq!(pane.items_len(), 4);
|
||||||
assert_eq!(pane.active_item().unwrap().id(), item1.id());
|
assert_eq!(pane.active_item().unwrap().id(), item1.id());
|
||||||
});
|
});
|
||||||
assert!(cx.has_pending_prompt(window_id));
|
assert!(cx.has_pending_prompt(window.window_id()));
|
||||||
|
|
||||||
// Confirm saving item 1.
|
// Confirm saving item 1.
|
||||||
cx.simulate_prompt_answer(window_id, 0);
|
cx.simulate_prompt_answer(window.window_id(), 0);
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
|
|
||||||
// Item 1 is saved. There's a prompt to save item 3.
|
// Item 1 is saved. There's a prompt to save item 3.
|
||||||
|
@ -4373,10 +4370,10 @@ mod tests {
|
||||||
assert_eq!(pane.items_len(), 3);
|
assert_eq!(pane.items_len(), 3);
|
||||||
assert_eq!(pane.active_item().unwrap().id(), item3.id());
|
assert_eq!(pane.active_item().unwrap().id(), item3.id());
|
||||||
});
|
});
|
||||||
assert!(cx.has_pending_prompt(window_id));
|
assert!(cx.has_pending_prompt(window.window_id()));
|
||||||
|
|
||||||
// Cancel saving item 3.
|
// Cancel saving item 3.
|
||||||
cx.simulate_prompt_answer(window_id, 1);
|
cx.simulate_prompt_answer(window.window_id(), 1);
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
|
|
||||||
// Item 3 is reloaded. There's a prompt to save item 4.
|
// Item 3 is reloaded. There's a prompt to save item 4.
|
||||||
|
@ -4387,10 +4384,10 @@ mod tests {
|
||||||
assert_eq!(pane.items_len(), 2);
|
assert_eq!(pane.items_len(), 2);
|
||||||
assert_eq!(pane.active_item().unwrap().id(), item4.id());
|
assert_eq!(pane.active_item().unwrap().id(), item4.id());
|
||||||
});
|
});
|
||||||
assert!(cx.has_pending_prompt(window_id));
|
assert!(cx.has_pending_prompt(window.window_id()));
|
||||||
|
|
||||||
// Confirm saving item 4.
|
// Confirm saving item 4.
|
||||||
cx.simulate_prompt_answer(window_id, 0);
|
cx.simulate_prompt_answer(window.window_id(), 0);
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
|
|
||||||
// There's a prompt for a path for item 4.
|
// There's a prompt for a path for item 4.
|
||||||
|
@ -4414,13 +4411,14 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, [], cx).await;
|
let project = Project::test(fs, [], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
|
||||||
// Create several workspace items with single project entries, and two
|
// Create several workspace items with single project entries, and two
|
||||||
// workspace items with multiple project entries.
|
// workspace items with multiple project entries.
|
||||||
let single_entry_items = (0..=4)
|
let single_entry_items = (0..=4)
|
||||||
.map(|project_entry_id| {
|
.map(|project_entry_id| {
|
||||||
cx.add_view(window_id, |cx| {
|
window.add_view(cx, |cx| {
|
||||||
TestItem::new()
|
TestItem::new()
|
||||||
.with_dirty(true)
|
.with_dirty(true)
|
||||||
.with_project_items(&[TestProjectItem::new(
|
.with_project_items(&[TestProjectItem::new(
|
||||||
|
@ -4431,7 +4429,7 @@ mod tests {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let item_2_3 = cx.add_view(window_id, |cx| {
|
let item_2_3 = window.add_view(cx, |cx| {
|
||||||
TestItem::new()
|
TestItem::new()
|
||||||
.with_dirty(true)
|
.with_dirty(true)
|
||||||
.with_singleton(false)
|
.with_singleton(false)
|
||||||
|
@ -4440,7 +4438,7 @@ mod tests {
|
||||||
single_entry_items[3].read(cx).project_items[0].clone(),
|
single_entry_items[3].read(cx).project_items[0].clone(),
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
let item_3_4 = cx.add_view(window_id, |cx| {
|
let item_3_4 = window.add_view(cx, |cx| {
|
||||||
TestItem::new()
|
TestItem::new()
|
||||||
.with_dirty(true)
|
.with_dirty(true)
|
||||||
.with_singleton(false)
|
.with_singleton(false)
|
||||||
|
@ -4492,7 +4490,7 @@ mod tests {
|
||||||
&[ProjectEntryId::from_proto(0)]
|
&[ProjectEntryId::from_proto(0)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
cx.simulate_prompt_answer(window_id, 0);
|
cx.simulate_prompt_answer(window.window_id(), 0);
|
||||||
|
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
left_pane.read_with(cx, |pane, cx| {
|
left_pane.read_with(cx, |pane, cx| {
|
||||||
|
@ -4501,7 +4499,7 @@ mod tests {
|
||||||
&[ProjectEntryId::from_proto(2)]
|
&[ProjectEntryId::from_proto(2)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
cx.simulate_prompt_answer(window_id, 0);
|
cx.simulate_prompt_answer(window.window_id(), 0);
|
||||||
|
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
close.await.unwrap();
|
close.await.unwrap();
|
||||||
|
@ -4517,10 +4515,11 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, [], cx).await;
|
let project = Project::test(fs, [], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
let item = cx.add_view(window_id, |cx| {
|
let item = window.add_view(cx, |cx| {
|
||||||
TestItem::new().with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
|
TestItem::new().with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
|
||||||
});
|
});
|
||||||
let item_id = item.id();
|
let item_id = item.id();
|
||||||
|
@ -4560,7 +4559,7 @@ mod tests {
|
||||||
item.read_with(cx, |item, _| assert_eq!(item.save_count, 2));
|
item.read_with(cx, |item, _| assert_eq!(item.save_count, 2));
|
||||||
|
|
||||||
// Deactivating the window still saves the file.
|
// Deactivating the window still saves the file.
|
||||||
cx.simulate_window_activation(Some(window_id));
|
cx.simulate_window_activation(Some(window.window_id()));
|
||||||
item.update(cx, |item, cx| {
|
item.update(cx, |item, cx| {
|
||||||
cx.focus_self();
|
cx.focus_self();
|
||||||
item.is_dirty = true;
|
item.is_dirty = true;
|
||||||
|
@ -4602,7 +4601,7 @@ mod tests {
|
||||||
pane.update(cx, |pane, cx| pane.close_items(cx, move |id| id == item_id))
|
pane.update(cx, |pane, cx| pane.close_items(cx, move |id| id == item_id))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(!cx.has_pending_prompt(window_id));
|
assert!(!cx.has_pending_prompt(window.window_id()));
|
||||||
item.read_with(cx, |item, _| assert_eq!(item.save_count, 5));
|
item.read_with(cx, |item, _| assert_eq!(item.save_count, 5));
|
||||||
|
|
||||||
// Add the item again, ensuring autosave is prevented if the underlying file has been deleted.
|
// Add the item again, ensuring autosave is prevented if the underlying file has been deleted.
|
||||||
|
@ -4623,7 +4622,7 @@ mod tests {
|
||||||
let _close_items =
|
let _close_items =
|
||||||
pane.update(cx, |pane, cx| pane.close_items(cx, move |id| id == item_id));
|
pane.update(cx, |pane, cx| pane.close_items(cx, move |id| id == item_id));
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
assert!(cx.has_pending_prompt(window_id));
|
assert!(cx.has_pending_prompt(window.window_id()));
|
||||||
item.read_with(cx, |item, _| assert_eq!(item.save_count, 5));
|
item.read_with(cx, |item, _| assert_eq!(item.save_count, 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4634,9 +4633,10 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, [], cx).await;
|
let project = Project::test(fs, [], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
|
||||||
let item = cx.add_view(window_id, |cx| {
|
let item = window.add_view(cx, |cx| {
|
||||||
TestItem::new().with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
|
TestItem::new().with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
|
||||||
});
|
});
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
@ -4687,7 +4687,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, [], cx).await;
|
let project = Project::test(fs, [], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
|
||||||
let panel = workspace.update(cx, |workspace, cx| {
|
let panel = workspace.update(cx, |workspace, cx| {
|
||||||
let panel = cx.add_view(|_| TestPanel::new(DockPosition::Right));
|
let panel = cx.add_view(|_| TestPanel::new(DockPosition::Right));
|
||||||
|
@ -4834,7 +4835,8 @@ mod tests {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
|
||||||
let project = Project::test(fs, [], cx).await;
|
let project = Project::test(fs, [], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
|
||||||
let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| {
|
let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| {
|
||||||
// Add panel_1 on the left, panel_2 on the right.
|
// Add panel_1 on the left, panel_2 on the right.
|
||||||
|
@ -4989,7 +4991,7 @@ mod tests {
|
||||||
|
|
||||||
// If focus is transferred to another view that's not a panel or another pane, we still show
|
// If focus is transferred to another view that's not a panel or another pane, we still show
|
||||||
// the panel as zoomed.
|
// the panel as zoomed.
|
||||||
let focus_receiver = cx.add_view(window_id, |_| EmptyView);
|
let focus_receiver = window.add_view(cx, |_| EmptyView);
|
||||||
focus_receiver.update(cx, |_, cx| cx.focus_self());
|
focus_receiver.update(cx, |_, cx| cx.focus_self());
|
||||||
workspace.read_with(cx, |workspace, _| {
|
workspace.read_with(cx, |workspace, _| {
|
||||||
assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
|
assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
|
||||||
|
|
|
@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
|
||||||
description = "The fast, collaborative code editor."
|
description = "The fast, collaborative code editor."
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
name = "zed"
|
name = "zed"
|
||||||
version = "0.98.0"
|
version = "0.99.0"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
name = "Shell Script"
|
name = "Shell Script"
|
||||||
path_suffixes = [".sh", ".bash", ".bashrc", ".bash_profile", ".bash_aliases", ".bash_logout", ".profile", ".zsh", ".zshrc", ".zshenv", ".zsh_profile", ".zsh_aliases", ".zsh_histfile", ".zlogin"]
|
path_suffixes = ["sh", "bash", "bashrc", "bash_profile", "bash_aliases", "bash_logout", "profile", "zsh", "zshrc", "zshenv", "zsh_profile", "zsh_aliases", "zsh_histfile", "zlogin"]
|
||||||
|
line_comment = "# "
|
||||||
first_line_pattern = "^#!.*\\b(?:ba|z)?sh\\b"
|
first_line_pattern = "^#!.*\\b(?:ba|z)?sh\\b"
|
||||||
brackets = [
|
brackets = [
|
||||||
{ start = "[", end = "]", close = true, newline = false },
|
{ start = "[", end = "]", close = true, newline = false },
|
||||||
|
|
|
@ -54,5 +54,5 @@
|
||||||
|
|
||||||
(
|
(
|
||||||
(command (_) @constant)
|
(command (_) @constant)
|
||||||
(.match? @constant "^-")
|
(#match? @constant "^-")
|
||||||
)
|
)
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
(identifier) @variable
|
(identifier) @variable
|
||||||
|
|
||||||
((identifier) @constant
|
((identifier) @constant
|
||||||
(.match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
||||||
|
|
||||||
(call_expression
|
(call_expression
|
||||||
function: (identifier) @function)
|
function: (identifier) @function)
|
||||||
|
@ -106,3 +106,4 @@
|
||||||
(primitive_type)
|
(primitive_type)
|
||||||
(sized_type_specifier)
|
(sized_type_specifier)
|
||||||
] @type
|
] @type
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(preproc_def
|
(preproc_def
|
||||||
value: (preproc_arg) @content
|
value: (preproc_arg) @content
|
||||||
(.set! "language" "c"))
|
(#set! "language" "c"))
|
||||||
|
|
||||||
(preproc_function_def
|
(preproc_function_def
|
||||||
value: (preproc_arg) @content
|
value: (preproc_arg) @content
|
||||||
(.set! "language" "c"))
|
(#set! "language" "c"))
|
|
@ -31,13 +31,13 @@
|
||||||
declarator: (field_identifier) @function)
|
declarator: (field_identifier) @function)
|
||||||
|
|
||||||
((namespace_identifier) @type
|
((namespace_identifier) @type
|
||||||
(.match? @type "^[A-Z]"))
|
(#match? @type "^[A-Z]"))
|
||||||
|
|
||||||
(auto) @type
|
(auto) @type
|
||||||
(type_identifier) @type
|
(type_identifier) @type
|
||||||
|
|
||||||
((identifier) @constant
|
((identifier) @constant
|
||||||
(.match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
||||||
|
|
||||||
(field_identifier) @property
|
(field_identifier) @property
|
||||||
(statement_identifier) @label
|
(statement_identifier) @label
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(preproc_def
|
(preproc_def
|
||||||
value: (preproc_arg) @content
|
value: (preproc_arg) @content
|
||||||
(.set! "language" "c++"))
|
(#set! "language" "c++"))
|
||||||
|
|
||||||
(preproc_function_def
|
(preproc_function_def
|
||||||
value: (preproc_arg) @content
|
value: (preproc_arg) @content
|
||||||
(.set! "language" "c++"))
|
(#set! "language" "c++"))
|
|
@ -46,7 +46,7 @@
|
||||||
(property_name)
|
(property_name)
|
||||||
(plain_value)
|
(plain_value)
|
||||||
] @variable.special
|
] @variable.special
|
||||||
(.match? @variable.special "^--")
|
(#match? @variable.special "^--")
|
||||||
)
|
)
|
||||||
|
|
||||||
[
|
[
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
operator: "@"
|
operator: "@"
|
||||||
operand: (call
|
operand: (call
|
||||||
target: (identifier) @unary
|
target: (identifier) @unary
|
||||||
(.match? @unary "^(doc)$"))
|
(#match? @unary "^(doc)$"))
|
||||||
) @context
|
) @context
|
||||||
.
|
.
|
||||||
(call
|
(call
|
||||||
|
@ -18,10 +18,10 @@
|
||||||
target: (identifier) @name)
|
target: (identifier) @name)
|
||||||
operator: "when")
|
operator: "when")
|
||||||
])
|
])
|
||||||
(.match? @name "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
|
(#match? @name "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
|
||||||
)
|
)
|
||||||
|
|
||||||
(call
|
(call
|
||||||
target: (identifier) @name
|
target: (identifier) @name
|
||||||
(arguments (alias) @name)
|
(arguments (alias) @name)
|
||||||
(.match? @name "^(defmodule|defprotocol)$")) @item
|
(#match? @name "^(defmodule|defprotocol)$")) @item
|
||||||
|
|
|
@ -54,13 +54,13 @@
|
||||||
(sigil_name) @__name__
|
(sigil_name) @__name__
|
||||||
quoted_start: _ @string
|
quoted_start: _ @string
|
||||||
quoted_end: _ @string
|
quoted_end: _ @string
|
||||||
(.match? @__name__ "^[sS]$")) @string
|
(#match? @__name__ "^[sS]$")) @string
|
||||||
|
|
||||||
(sigil
|
(sigil
|
||||||
(sigil_name) @__name__
|
(sigil_name) @__name__
|
||||||
quoted_start: _ @string.regex
|
quoted_start: _ @string.regex
|
||||||
quoted_end: _ @string.regex
|
quoted_end: _ @string.regex
|
||||||
(.match? @__name__ "^[rR]$")) @string.regex
|
(#match? @__name__ "^[rR]$")) @string.regex
|
||||||
|
|
||||||
(sigil
|
(sigil
|
||||||
(sigil_name) @__name__
|
(sigil_name) @__name__
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
|
|
||||||
(
|
(
|
||||||
(identifier) @comment.unused
|
(identifier) @comment.unused
|
||||||
(.match? @comment.unused "^_")
|
(#match? @comment.unused "^_")
|
||||||
)
|
)
|
||||||
|
|
||||||
(call
|
(call
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
operator: "|>"
|
operator: "|>"
|
||||||
right: (identifier))
|
right: (identifier))
|
||||||
])
|
])
|
||||||
(.match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
|
(#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
|
||||||
|
|
||||||
(binary_operator
|
(binary_operator
|
||||||
operator: "|>"
|
operator: "|>"
|
||||||
|
@ -99,15 +99,15 @@
|
||||||
|
|
||||||
(call
|
(call
|
||||||
target: (identifier) @keyword
|
target: (identifier) @keyword
|
||||||
(.match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$"))
|
(#match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$"))
|
||||||
|
|
||||||
(call
|
(call
|
||||||
target: (identifier) @keyword
|
target: (identifier) @keyword
|
||||||
(.match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
|
(#match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
|
||||||
|
|
||||||
(
|
(
|
||||||
(identifier) @constant.builtin
|
(identifier) @constant.builtin
|
||||||
(.match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$")
|
(#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$")
|
||||||
)
|
)
|
||||||
|
|
||||||
(unary_operator
|
(unary_operator
|
||||||
|
@ -121,7 +121,7 @@
|
||||||
(sigil)
|
(sigil)
|
||||||
(boolean)
|
(boolean)
|
||||||
] @comment.doc))
|
] @comment.doc))
|
||||||
(.match? @__attribute__ "^(moduledoc|typedoc|doc)$"))
|
(#match? @__attribute__ "^(moduledoc|typedoc|doc)$"))
|
||||||
|
|
||||||
(comment) @comment
|
(comment) @comment
|
||||||
|
|
||||||
|
@ -150,4 +150,4 @@
|
||||||
((sigil
|
((sigil
|
||||||
(sigil_name) @_sigil_name
|
(sigil_name) @_sigil_name
|
||||||
(quoted_content) @embedded)
|
(quoted_content) @embedded)
|
||||||
(.eq? @_sigil_name "H"))
|
(#eq? @_sigil_name "H"))
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
((sigil
|
((sigil
|
||||||
(sigil_name) @_sigil_name
|
(sigil_name) @_sigil_name
|
||||||
(quoted_content) @content)
|
(quoted_content) @content)
|
||||||
(.eq? @_sigil_name "H")
|
(#eq? @_sigil_name "H")
|
||||||
(.set! language "heex"))
|
(#set! language "heex"))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(call
|
(call
|
||||||
target: (identifier) @context
|
target: (identifier) @context
|
||||||
(arguments (alias) @name)
|
(arguments (alias) @name)
|
||||||
(.match? @context "^(defmodule|defprotocol)$")) @item
|
(#match? @context "^(defmodule|defprotocol)$")) @item
|
||||||
|
|
||||||
(call
|
(call
|
||||||
target: (identifier) @context
|
target: (identifier) @context
|
||||||
|
@ -23,4 +23,4 @@
|
||||||
")" @context.extra))
|
")" @context.extra))
|
||||||
operator: "when")
|
operator: "when")
|
||||||
])
|
])
|
||||||
(.match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
|
(#match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
((glsl_content) @content
|
((glsl_content) @content
|
||||||
(.set! "language" "glsl"))
|
(#set! "language" "glsl"))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
((code) @content
|
((code) @content
|
||||||
(.set! "language" "ruby")
|
(#set! "language" "ruby")
|
||||||
(.set! "combined"))
|
(#set! "combined"))
|
||||||
|
|
||||||
((content) @content
|
((content) @content
|
||||||
(.set! "language" "html")
|
(#set! "language" "html")
|
||||||
(.set! "combined"))
|
(#set! "combined"))
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
(sized_type_specifier) @type
|
(sized_type_specifier) @type
|
||||||
|
|
||||||
((identifier) @constant
|
((identifier) @constant
|
||||||
(.match? @constant "^[A-Z][A-Z\\d_]*$"))
|
(#match? @constant "^[A-Z][A-Z\\d_]*$"))
|
||||||
|
|
||||||
(identifier) @variable
|
(identifier) @variable
|
||||||
|
|
||||||
|
@ -114,5 +114,5 @@
|
||||||
|
|
||||||
(
|
(
|
||||||
(identifier) @variable.builtin
|
(identifier) @variable.builtin
|
||||||
(.match? @variable.builtin "^gl_")
|
(#match? @variable.builtin "^gl_")
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
(expression_value)
|
(expression_value)
|
||||||
(ending_expression_value)
|
(ending_expression_value)
|
||||||
] @content)
|
] @content)
|
||||||
(.set! language "elixir")
|
(#set! language "elixir")
|
||||||
(.set! combined)
|
(#set! combined)
|
||||||
)
|
)
|
||||||
|
|
||||||
((expression (expression_value) @content)
|
((expression (expression_value) @content)
|
||||||
(.set! language "elixir"))
|
(#set! language "elixir"))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(script_element
|
(script_element
|
||||||
(raw_text) @content
|
(raw_text) @content
|
||||||
(.set! "language" "javascript"))
|
(#set! "language" "javascript"))
|
||||||
|
|
||||||
(style_element
|
(style_element
|
||||||
(raw_text) @content
|
(raw_text) @content
|
||||||
(.set! "language" "css"))
|
(#set! "language" "css"))
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
; Special identifiers
|
; Special identifiers
|
||||||
|
|
||||||
((identifier) @type
|
((identifier) @type
|
||||||
(.match? @type "^[A-Z]"))
|
(#match? @type "^[A-Z]"))
|
||||||
(type_identifier) @type
|
(type_identifier) @type
|
||||||
(predefined_type) @type.builtin
|
(predefined_type) @type.builtin
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
(shorthand_property_identifier)
|
(shorthand_property_identifier)
|
||||||
(shorthand_property_identifier_pattern)
|
(shorthand_property_identifier_pattern)
|
||||||
] @constant
|
] @constant
|
||||||
(.match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
|
(#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
|
||||||
|
|
||||||
; Literals
|
; Literals
|
||||||
|
|
||||||
|
@ -214,4 +214,4 @@
|
||||||
"type"
|
"type"
|
||||||
"readonly"
|
"readonly"
|
||||||
"override"
|
"override"
|
||||||
] @keyword
|
] @keyword
|
|
@ -127,7 +127,7 @@
|
||||||
(identifier) @variable
|
(identifier) @variable
|
||||||
|
|
||||||
((identifier) @variable.special
|
((identifier) @variable.special
|
||||||
(.eq? @variable.special "self"))
|
(#eq? @variable.special "self"))
|
||||||
|
|
||||||
(variable_list
|
(variable_list
|
||||||
attribute: (attribute
|
attribute: (attribute
|
||||||
|
@ -137,7 +137,7 @@
|
||||||
;; Constants
|
;; Constants
|
||||||
|
|
||||||
((identifier) @constant
|
((identifier) @constant
|
||||||
(.match? @constant "^[A-Z][A-Z_0-9]*$"))
|
(#match? @constant "^[A-Z][A-Z_0-9]*$"))
|
||||||
|
|
||||||
(vararg_expression) @constant
|
(vararg_expression) @constant
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@
|
||||||
[
|
[
|
||||||
"{"
|
"{"
|
||||||
"}"
|
"}"
|
||||||
] @method.constructor)
|
] @constructor)
|
||||||
|
|
||||||
;; Functions
|
;; Functions
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@
|
||||||
|
|
||||||
(function_call
|
(function_call
|
||||||
(identifier) @function.builtin
|
(identifier) @function.builtin
|
||||||
(.any-of? @function.builtin
|
(#any-of? @function.builtin
|
||||||
;; built-in functions in Lua 5.1
|
;; built-in functions in Lua 5.1
|
||||||
"assert" "collectgarbage" "dofile" "error" "getfenv" "getmetatable" "ipairs"
|
"assert" "collectgarbage" "dofile" "error" "getfenv" "getmetatable" "ipairs"
|
||||||
"load" "loadfile" "loadstring" "module" "next" "pairs" "pcall" "print"
|
"load" "loadfile" "loadstring" "module" "next" "pairs" "pcall" "print"
|
||||||
|
@ -195,4 +195,4 @@
|
||||||
|
|
||||||
(number) @number
|
(number) @number
|
||||||
|
|
||||||
(string) @string
|
(string) @string
|
|
@ -43,15 +43,15 @@
|
||||||
(relative_scope) @variable.builtin
|
(relative_scope) @variable.builtin
|
||||||
|
|
||||||
((name) @constant
|
((name) @constant
|
||||||
(.match? @constant "^_?[A-Z][A-Z\\d_]+$"))
|
(#match? @constant "^_?[A-Z][A-Z\\d_]+$"))
|
||||||
((name) @constant.builtin
|
((name) @constant.builtin
|
||||||
(.match? @constant.builtin "^__[A-Z][A-Z\d_]+__$"))
|
(#match? @constant.builtin "^__[A-Z][A-Z\d_]+__$"))
|
||||||
|
|
||||||
((name) @method.constructor
|
((name) @constructor
|
||||||
(.match? @method.constructor "^[A-Z]"))
|
(#match? @constructor "^[A-Z]"))
|
||||||
|
|
||||||
((name) @variable.builtin
|
((name) @variable.builtin
|
||||||
(.eq? @variable.builtin "this"))
|
(#eq? @variable.builtin "this"))
|
||||||
|
|
||||||
(variable_name) @variable
|
(variable_name) @variable
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
((text) @content
|
((text) @content
|
||||||
(.set! "language" "html")
|
(#set! "language" "html")
|
||||||
(.set! "combined"))
|
(#set! "combined"))
|
||||||
|
|
|
@ -18,16 +18,16 @@
|
||||||
; Identifier naming conventions
|
; Identifier naming conventions
|
||||||
|
|
||||||
((identifier) @type
|
((identifier) @type
|
||||||
(.match? @type "^[A-Z]"))
|
(#match? @type "^[A-Z]"))
|
||||||
|
|
||||||
((identifier) @constant
|
((identifier) @constant
|
||||||
(.match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
||||||
|
|
||||||
; Builtin functions
|
; Builtin functions
|
||||||
|
|
||||||
((call
|
((call
|
||||||
function: (identifier) @function.builtin)
|
function: (identifier) @function.builtin)
|
||||||
(.match?
|
(#match?
|
||||||
@function.builtin
|
@function.builtin
|
||||||
"^(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|exec|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|__import__)$"))
|
"^(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|exec|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|__import__)$"))
|
||||||
|
|
||||||
|
@ -122,4 +122,4 @@
|
||||||
"yield"
|
"yield"
|
||||||
"match"
|
"match"
|
||||||
"case"
|
"case"
|
||||||
] @keyword
|
] @keyword
|
File diff suppressed because one or more lines are too long
|
@ -6,5 +6,5 @@
|
||||||
(symbol) @name
|
(symbol) @name
|
||||||
(list . (symbol) @name)
|
(list . (symbol) @name)
|
||||||
]
|
]
|
||||||
(.match? @start-symbol "^define")
|
(#match? @start-symbol "^define")
|
||||||
) @item
|
) @item
|
|
@ -11,4 +11,4 @@
|
||||||
(begin "begin" @open "end" @close)
|
(begin "begin" @open "end" @close)
|
||||||
(module "module" @open "end" @close)
|
(module "module" @open "end" @close)
|
||||||
(_ . "def" @open "end" @close)
|
(_ . "def" @open "end" @close)
|
||||||
(_ . "class" @open "end" @close)
|
(_ . "class" @open "end" @close)
|
|
@ -33,12 +33,12 @@
|
||||||
(identifier) @variable
|
(identifier) @variable
|
||||||
|
|
||||||
((identifier) @keyword
|
((identifier) @keyword
|
||||||
(.match? @keyword "^(private|protected|public)$"))
|
(#match? @keyword "^(private|protected|public)$"))
|
||||||
|
|
||||||
; Function calls
|
; Function calls
|
||||||
|
|
||||||
((identifier) @function.method.builtin
|
((identifier) @function.method.builtin
|
||||||
(.eq? @function.method.builtin "require"))
|
(#eq? @function.method.builtin "require"))
|
||||||
|
|
||||||
"defined?" @function.method.builtin
|
"defined?" @function.method.builtin
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
] @property
|
] @property
|
||||||
|
|
||||||
((identifier) @constant.builtin
|
((identifier) @constant.builtin
|
||||||
(.match? @constant.builtin "^__(FILE|LINE|ENCODING)__$"))
|
(#match? @constant.builtin "^__(FILE|LINE|ENCODING)__$"))
|
||||||
|
|
||||||
(file) @constant.builtin
|
(file) @constant.builtin
|
||||||
(line) @constant.builtin
|
(line) @constant.builtin
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
) @constant.builtin
|
) @constant.builtin
|
||||||
|
|
||||||
((constant) @constant
|
((constant) @constant
|
||||||
(.match? @constant "^[A-Z\\d_]+$"))
|
(#match? @constant "^[A-Z\\d_]+$"))
|
||||||
|
|
||||||
(constant) @type
|
(constant) @type
|
||||||
|
|
||||||
|
|
|
@ -38,11 +38,11 @@
|
||||||
|
|
||||||
; Assume uppercase names are types/enum-constructors
|
; Assume uppercase names are types/enum-constructors
|
||||||
((identifier) @type
|
((identifier) @type
|
||||||
(.match? @type "^[A-Z]"))
|
(#match? @type "^[A-Z]"))
|
||||||
|
|
||||||
; Assume all-caps names are constants
|
; Assume all-caps names are constants
|
||||||
((identifier) @constant
|
((identifier) @constant
|
||||||
(.match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
||||||
|
|
||||||
[
|
[
|
||||||
"("
|
"("
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(macro_invocation
|
(macro_invocation
|
||||||
(token_tree) @content
|
(token_tree) @content
|
||||||
(.set! "language" "rust"))
|
(#set! "language" "rust"))
|
||||||
|
|
||||||
(macro_rule
|
(macro_rule
|
||||||
(token_tree) @content
|
(token_tree) @content
|
||||||
(.set! "language" "rust"))
|
(#set! "language" "rust"))
|
|
@ -14,7 +14,7 @@
|
||||||
(directive)] @comment
|
(directive)] @comment
|
||||||
|
|
||||||
((symbol) @operator
|
((symbol) @operator
|
||||||
(.match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$"))
|
(#match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$"))
|
||||||
|
|
||||||
(list
|
(list
|
||||||
.
|
.
|
||||||
|
@ -23,6 +23,6 @@
|
||||||
(list
|
(list
|
||||||
.
|
.
|
||||||
(symbol) @keyword
|
(symbol) @keyword
|
||||||
(.match? @keyword
|
(#match? @keyword
|
||||||
"^(define-syntax|let\\*|lambda|λ|case|=>|quote-splicing|unquote-splicing|set!|let|letrec|letrec-syntax|let-values|let\\*-values|do|else|define|cond|syntax-rules|unquote|begin|quote|let-syntax|and|if|quasiquote|letrec|delay|or|when|unless|identifier-syntax|assert|library|export|import|rename|only|except|prefix)$"
|
"^(define-syntax|let\\*|lambda|λ|case|=>|quote-splicing|unquote-splicing|set!|let|letrec|letrec-syntax|let-values|let\\*-values|do|else|define|cond|syntax-rules|unquote|begin|quote|let-syntax|and|if|quasiquote|letrec|delay|or|when|unless|identifier-syntax|assert|library|export|import|rename|only|except|prefix)$"
|
||||||
))
|
))
|
||||||
|
|
|
@ -6,5 +6,5 @@
|
||||||
(symbol) @name
|
(symbol) @name
|
||||||
(list . (symbol) @name)
|
(list . (symbol) @name)
|
||||||
]
|
]
|
||||||
(.match? @start-symbol "^define")
|
(#match? @start-symbol "^define")
|
||||||
) @item
|
) @item
|
|
@ -2,27 +2,27 @@
|
||||||
; --------------
|
; --------------
|
||||||
(script_element
|
(script_element
|
||||||
(raw_text) @content
|
(raw_text) @content
|
||||||
(.set! "language" "javascript"))
|
(#set! "language" "javascript"))
|
||||||
|
|
||||||
((script_element
|
((script_element
|
||||||
(start_tag
|
(start_tag
|
||||||
(attribute
|
(attribute
|
||||||
(quoted_attribute_value (attribute_value) @_language)))
|
(quoted_attribute_value (attribute_value) @_language)))
|
||||||
(raw_text) @content)
|
(raw_text) @content)
|
||||||
(.eq? @_language "ts")
|
(#eq? @_language "ts")
|
||||||
(.set! "language" "typescript"))
|
(#set! "language" "typescript"))
|
||||||
|
|
||||||
((script_element
|
((script_element
|
||||||
(start_tag
|
(start_tag
|
||||||
(attribute
|
(attribute
|
||||||
(quoted_attribute_value (attribute_value) @_language)))
|
(quoted_attribute_value (attribute_value) @_language)))
|
||||||
(raw_text) @content)
|
(raw_text) @content)
|
||||||
(.eq? @_language "typescript")
|
(#eq? @_language "typescript")
|
||||||
(.set! "language" "typescript"))
|
(#set! "language" "typescript"))
|
||||||
|
|
||||||
(style_element
|
(style_element
|
||||||
(raw_text) @content
|
(raw_text) @content
|
||||||
(.set! "language" "css"))
|
(#set! "language" "css"))
|
||||||
|
|
||||||
((raw_text_expr) @content
|
((raw_text_expr) @content
|
||||||
(.set! "language" "javascript"))
|
(#set! "language" "javascript"))
|
||||||
|
|
|
@ -43,11 +43,11 @@
|
||||||
|
|
||||||
; Special identifiers
|
; Special identifiers
|
||||||
|
|
||||||
((identifier) @method.constructor
|
((identifier) @constructor
|
||||||
(.match? @method.constructor "^[A-Z]"))
|
(#match? @constructor "^[A-Z]"))
|
||||||
|
|
||||||
((identifier) @type
|
((identifier) @type
|
||||||
(.match? @type "^[A-Z]"))
|
(#match? @type "^[A-Z]"))
|
||||||
(type_identifier) @type
|
(type_identifier) @type
|
||||||
(predefined_type) @type.builtin
|
(predefined_type) @type.builtin
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
(shorthand_property_identifier)
|
(shorthand_property_identifier)
|
||||||
(shorthand_property_identifier_pattern)
|
(shorthand_property_identifier_pattern)
|
||||||
] @constant
|
] @constant
|
||||||
(.match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
|
(#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
|
||||||
|
|
||||||
; Literals
|
; Literals
|
||||||
|
|
||||||
|
@ -218,4 +218,4 @@
|
||||||
"type"
|
"type"
|
||||||
"readonly"
|
"readonly"
|
||||||
"override"
|
"override"
|
||||||
] @keyword
|
] @keyword
|
|
@ -981,7 +981,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project, cx))
|
||||||
|
.root(cx);
|
||||||
|
|
||||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||||
let file1 = entries[0].clone();
|
let file1 = entries[0].clone();
|
||||||
|
@ -1293,7 +1295,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
// Open a file within an existing worktree.
|
// Open a file within an existing worktree.
|
||||||
workspace
|
workspace
|
||||||
|
@ -1334,7 +1338,9 @@ mod tests {
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||||
project.update(cx, |project, _| project.languages().add(rust_lang()));
|
project.update(cx, |project, _| project.languages().add(rust_lang()));
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap());
|
let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap());
|
||||||
|
|
||||||
// Create a new untitled buffer
|
// Create a new untitled buffer
|
||||||
|
@ -1427,7 +1433,9 @@ mod tests {
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), [], cx).await;
|
let project = Project::test(app_state.fs.clone(), [], cx).await;
|
||||||
project.update(cx, |project, _| project.languages().add(rust_lang()));
|
project.update(cx, |project, _| project.languages().add(rust_lang()));
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
// Create a new untitled buffer
|
// Create a new untitled buffer
|
||||||
cx.dispatch_action(window_id, NewFile);
|
cx.dispatch_action(window_id, NewFile);
|
||||||
|
@ -1478,7 +1486,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||||
|
let workspace = window.root(cx);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||||
let file1 = entries[0].clone();
|
let file1 = entries[0].clone();
|
||||||
|
@ -1552,7 +1562,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project.clone(), cx))
|
||||||
|
.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||||
|
@ -1829,7 +1841,9 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
let workspace = cx
|
||||||
|
.add_window(|cx| Workspace::test_new(project, cx))
|
||||||
|
.root(cx);
|
||||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||||
|
|
||||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||||
|
@ -2071,7 +2085,8 @@ mod tests {
|
||||||
|
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
|
|
||||||
let (window_id, _view) = cx.add_window(|_| TestView);
|
let window = cx.add_window(|_| TestView);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
// Test loading the keymap base at all
|
// Test loading the keymap base at all
|
||||||
assert_key_bindings_for(
|
assert_key_bindings_for(
|
||||||
|
@ -2241,7 +2256,8 @@ mod tests {
|
||||||
|
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
|
|
||||||
let (window_id, _view) = cx.add_window(|_| TestView);
|
let window = cx.add_window(|_| TestView);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
|
||||||
// Test loading the keymap base at all
|
// Test loading the keymap base at all
|
||||||
assert_key_bindings_for(
|
assert_key_bindings_for(
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
"build-licenses": "ts-node ./src/build_licenses.ts",
|
"build-licenses": "ts-node ./src/build_licenses.ts",
|
||||||
"build-tokens": "ts-node ./src/build_tokens.ts",
|
"build-tokens": "ts-node ./src/build_tokens.ts",
|
||||||
"build-types": "ts-node ./src/build_types.ts",
|
"build-types": "ts-node ./src/build_types.ts",
|
||||||
"generate-syntax": "ts-node ./src/types/extract_syntax_types.ts",
|
|
||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
},
|
},
|
||||||
"author": "Zed Industries (https://github.com/zed-industries/)",
|
"author": "Zed Industries (https://github.com/zed-industries/)",
|
||||||
|
|
|
@ -21,7 +21,9 @@ function clear_themes(theme_directory: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const all_themes: Theme[] = themes.map((theme) => create_theme(theme))
|
const all_themes: Theme[] = themes.map((theme) =>
|
||||||
|
create_theme(theme)
|
||||||
|
)
|
||||||
|
|
||||||
function write_themes(themes: Theme[], output_directory: string) {
|
function write_themes(themes: Theme[], output_directory: string) {
|
||||||
clear_themes(output_directory)
|
clear_themes(output_directory)
|
||||||
|
@ -32,7 +34,10 @@ function write_themes(themes: Theme[], output_directory: string) {
|
||||||
const style_tree = app()
|
const style_tree = app()
|
||||||
const style_tree_json = JSON.stringify(style_tree, null, 2)
|
const style_tree_json = JSON.stringify(style_tree, null, 2)
|
||||||
const temp_path = path.join(temp_directory, `${theme.name}.json`)
|
const temp_path = path.join(temp_directory, `${theme.name}.json`)
|
||||||
const out_path = path.join(output_directory, `${theme.name}.json`)
|
const out_path = path.join(
|
||||||
|
output_directory,
|
||||||
|
`${theme.name}.json`
|
||||||
|
)
|
||||||
fs.writeFileSync(temp_path, style_tree_json)
|
fs.writeFileSync(temp_path, style_tree_json)
|
||||||
fs.renameSync(temp_path, out_path)
|
fs.renameSync(temp_path, out_path)
|
||||||
console.log(`- ${out_path} created`)
|
console.log(`- ${out_path} created`)
|
||||||
|
|
|
@ -83,6 +83,8 @@ function write_tokens(themes: Theme[], tokens_directory: string) {
|
||||||
console.log(`- ${METADATA_FILE} created`)
|
console.log(`- ${METADATA_FILE} created`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const all_themes: Theme[] = themes.map((theme) => create_theme(theme))
|
const all_themes: Theme[] = themes.map((theme) =>
|
||||||
|
create_theme(theme)
|
||||||
|
)
|
||||||
|
|
||||||
write_tokens(all_themes, TOKENS_DIRECTORY)
|
write_tokens(all_themes, TOKENS_DIRECTORY)
|
||||||
|
|
|
@ -10,7 +10,10 @@ export type Margin = {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IconButtonOptions {
|
interface IconButtonOptions {
|
||||||
layer?: Theme["lowest"] | Theme["middle"] | Theme["highest"]
|
layer?:
|
||||||
|
| Theme["lowest"]
|
||||||
|
| Theme["middle"]
|
||||||
|
| Theme["highest"]
|
||||||
color?: keyof Theme["lowest"]
|
color?: keyof Theme["lowest"]
|
||||||
margin?: Partial<Margin>
|
margin?: Partial<Margin>
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,47 +12,44 @@ type TabBarButtonProps = TabBarButtonOptions & {
|
||||||
state?: Partial<Record<InteractiveState, Partial<TabBarButtonOptions>>>
|
state?: Partial<Record<InteractiveState, Partial<TabBarButtonOptions>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tab_bar_button(
|
export function tab_bar_button(theme: Theme, { icon, color = "base" }: TabBarButtonProps) {
|
||||||
theme: Theme,
|
|
||||||
{ icon, color = "base" }: TabBarButtonProps
|
|
||||||
) {
|
|
||||||
const button_spacing = 8
|
const button_spacing = 8
|
||||||
|
|
||||||
return interactive({
|
return (
|
||||||
base: {
|
interactive({
|
||||||
icon: {
|
base: {
|
||||||
color: foreground(theme.middle, color),
|
icon: {
|
||||||
asset: icon,
|
color: foreground(theme.middle, color),
|
||||||
dimensions: {
|
asset: icon,
|
||||||
width: 15,
|
dimensions: {
|
||||||
height: 15,
|
width: 15,
|
||||||
|
height: 15,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
container: {
|
|
||||||
corner_radius: 4,
|
|
||||||
padding: {
|
|
||||||
top: 4,
|
|
||||||
bottom: 4,
|
|
||||||
left: 4,
|
|
||||||
right: 4,
|
|
||||||
},
|
|
||||||
margin: {
|
|
||||||
left: button_spacing / 2,
|
|
||||||
right: button_spacing / 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
hovered: {
|
|
||||||
container: {
|
container: {
|
||||||
background: background(theme.middle, color, "hovered"),
|
corner_radius: 4,
|
||||||
|
padding: {
|
||||||
|
top: 4, bottom: 4, left: 4, right: 4
|
||||||
|
},
|
||||||
|
margin: {
|
||||||
|
left: button_spacing / 2,
|
||||||
|
right: button_spacing / 2,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
clicked: {
|
state: {
|
||||||
container: {
|
hovered: {
|
||||||
background: background(theme.middle, color, "pressed"),
|
container: {
|
||||||
|
background: background(theme.middle, color, "hovered"),
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clicked: {
|
||||||
|
container: {
|
||||||
|
background: background(theme.middle, color, "pressed"),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,10 @@ import { useTheme, Theme } from "../theme"
|
||||||
import { Margin } from "./icon_button"
|
import { Margin } from "./icon_button"
|
||||||
|
|
||||||
interface TextButtonOptions {
|
interface TextButtonOptions {
|
||||||
layer?: Theme["lowest"] | Theme["middle"] | Theme["highest"]
|
layer?:
|
||||||
|
| Theme["lowest"]
|
||||||
|
| Theme["middle"]
|
||||||
|
| Theme["highest"]
|
||||||
color?: keyof Theme["lowest"]
|
color?: keyof Theme["lowest"]
|
||||||
margin?: Partial<Margin>
|
margin?: Partial<Margin>
|
||||||
text_properties?: TextProperties
|
text_properties?: TextProperties
|
||||||
|
|
|
@ -55,6 +55,6 @@ export default function app(): any {
|
||||||
tooltip: tooltip(),
|
tooltip: tooltip(),
|
||||||
terminal: terminal(),
|
terminal: terminal(),
|
||||||
assistant: assistant(),
|
assistant: assistant(),
|
||||||
feedback: feedback(),
|
feedback: feedback()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,48 +8,50 @@ type RoleCycleButton = TextStyle & {
|
||||||
}
|
}
|
||||||
// TODO: Replace these with zed types
|
// TODO: Replace these with zed types
|
||||||
type RemainingTokens = TextStyle & {
|
type RemainingTokens = TextStyle & {
|
||||||
background: string
|
background: string,
|
||||||
margin: { top: number; right: number }
|
margin: { top: number, right: number },
|
||||||
padding: {
|
padding: {
|
||||||
right: number
|
right: number,
|
||||||
left: number
|
left: number,
|
||||||
top: number
|
top: number,
|
||||||
bottom: number
|
bottom: number,
|
||||||
}
|
},
|
||||||
corner_radius: number
|
corner_radius: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function assistant(): any {
|
export default function assistant(): any {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
|
||||||
const interactive_role = (
|
const interactive_role = (color: StyleSets): Interactive<RoleCycleButton> => {
|
||||||
color: StyleSets
|
return (
|
||||||
): Interactive<RoleCycleButton> => {
|
interactive({
|
||||||
return interactive({
|
base: {
|
||||||
base: {
|
|
||||||
...text(theme.highest, "sans", color, { size: "sm" }),
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
hovered: {
|
|
||||||
...text(theme.highest, "sans", color, { size: "sm" }),
|
...text(theme.highest, "sans", color, { size: "sm" }),
|
||||||
background: background(theme.highest, color, "hovered"),
|
|
||||||
},
|
},
|
||||||
clicked: {
|
state: {
|
||||||
...text(theme.highest, "sans", color, { size: "sm" }),
|
hovered: {
|
||||||
background: background(theme.highest, color, "pressed"),
|
...text(theme.highest, "sans", color, { size: "sm" }),
|
||||||
|
background: background(theme.highest, color, "hovered"),
|
||||||
|
},
|
||||||
|
clicked: {
|
||||||
|
...text(theme.highest, "sans", color, { size: "sm" }),
|
||||||
|
background: background(theme.highest, color, "pressed"),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokens_remaining = (color: StyleSets): RemainingTokens => {
|
const tokens_remaining = (color: StyleSets): RemainingTokens => {
|
||||||
return {
|
return (
|
||||||
...text(theme.highest, "mono", color, { size: "xs" }),
|
{
|
||||||
background: background(theme.highest, "on", "default"),
|
...text(theme.highest, "mono", color, { size: "xs" }),
|
||||||
margin: { top: 12, right: 20 },
|
background: background(theme.highest, "on", "default"),
|
||||||
padding: { right: 4, left: 4, top: 1, bottom: 1 },
|
margin: { top: 12, right: 20 },
|
||||||
corner_radius: 6,
|
padding: { right: 4, left: 4, top: 1, bottom: 1 },
|
||||||
}
|
corner_radius: 6,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -91,10 +93,7 @@ export default function assistant(): any {
|
||||||
base: {
|
base: {
|
||||||
background: background(theme.middle),
|
background: background(theme.middle),
|
||||||
padding: { top: 4, bottom: 4 },
|
padding: { top: 4, bottom: 4 },
|
||||||
border: border(theme.middle, "default", {
|
border: border(theme.middle, "default", { top: true, overlay: true }),
|
||||||
top: true,
|
|
||||||
overlay: true,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
hovered: {
|
hovered: {
|
||||||
|
@ -102,7 +101,7 @@ export default function assistant(): any {
|
||||||
},
|
},
|
||||||
clicked: {
|
clicked: {
|
||||||
background: background(theme.middle, "pressed"),
|
background: background(theme.middle, "pressed"),
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
saved_at: {
|
saved_at: {
|
||||||
|
|
|
@ -9,9 +9,9 @@ import {
|
||||||
} from "./components"
|
} from "./components"
|
||||||
import hover_popover from "./hover_popover"
|
import hover_popover from "./hover_popover"
|
||||||
|
|
||||||
|
import { build_syntax } from "../theme/syntax"
|
||||||
import { interactive, toggleable } from "../element"
|
import { interactive, toggleable } from "../element"
|
||||||
import { useTheme } from "../theme"
|
import { useTheme } from "../theme"
|
||||||
import chroma from "chroma-js"
|
|
||||||
|
|
||||||
export default function editor(): any {
|
export default function editor(): any {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
@ -48,28 +48,16 @@ export default function editor(): any {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const syntax = build_syntax()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
text_color: theme.syntax.primary.color,
|
text_color: syntax.primary.color,
|
||||||
background: background(layer),
|
background: background(layer),
|
||||||
active_line_background: with_opacity(background(layer, "on"), 0.75),
|
active_line_background: with_opacity(background(layer, "on"), 0.75),
|
||||||
highlighted_line_background: background(layer, "on"),
|
highlighted_line_background: background(layer, "on"),
|
||||||
// Inline autocomplete suggestions, Co-pilot suggestions, etc.
|
// Inline autocomplete suggestions, Co-pilot suggestions, etc.
|
||||||
hint: chroma
|
hint: syntax.hint,
|
||||||
.mix(
|
suggestion: syntax.predictive,
|
||||||
theme.ramps.neutral(0.6).hex(),
|
|
||||||
theme.ramps.blue(0.4).hex(),
|
|
||||||
0.45,
|
|
||||||
"lch"
|
|
||||||
)
|
|
||||||
.hex(),
|
|
||||||
suggestion: chroma
|
|
||||||
.mix(
|
|
||||||
theme.ramps.neutral(0.4).hex(),
|
|
||||||
theme.ramps.blue(0.4).hex(),
|
|
||||||
0.45,
|
|
||||||
"lch"
|
|
||||||
)
|
|
||||||
.hex(),
|
|
||||||
code_actions: {
|
code_actions: {
|
||||||
indicator: toggleable({
|
indicator: toggleable({
|
||||||
base: interactive({
|
base: interactive({
|
||||||
|
@ -267,8 +255,8 @@ export default function editor(): any {
|
||||||
invalid_warning_diagnostic: diagnostic(theme.middle, "base"),
|
invalid_warning_diagnostic: diagnostic(theme.middle, "base"),
|
||||||
hover_popover: hover_popover(),
|
hover_popover: hover_popover(),
|
||||||
link_definition: {
|
link_definition: {
|
||||||
color: theme.syntax.link_uri.color,
|
color: syntax.link_uri.color,
|
||||||
underline: theme.syntax.link_uri.underline,
|
underline: syntax.link_uri.underline,
|
||||||
},
|
},
|
||||||
jump_icon: interactive({
|
jump_icon: interactive({
|
||||||
base: {
|
base: {
|
||||||
|
@ -318,7 +306,7 @@ export default function editor(): any {
|
||||||
? with_opacity(theme.ramps.green(0.5).hex(), 0.8)
|
? with_opacity(theme.ramps.green(0.5).hex(), 0.8)
|
||||||
: with_opacity(theme.ramps.green(0.4).hex(), 0.8),
|
: with_opacity(theme.ramps.green(0.4).hex(), 0.8),
|
||||||
},
|
},
|
||||||
selections: foreground(layer, "accent"),
|
selections: foreground(layer, "accent")
|
||||||
},
|
},
|
||||||
composition_mark: {
|
composition_mark: {
|
||||||
underline: {
|
underline: {
|
||||||
|
@ -326,6 +314,6 @@ export default function editor(): any {
|
||||||
color: border_color(layer),
|
color: border_color(layer),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
syntax: theme.syntax,
|
syntax,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default function feedback(): any {
|
||||||
...text(theme.highest, "mono", "on", "disabled"),
|
...text(theme.highest, "mono", "on", "disabled"),
|
||||||
background: background(theme.highest, "on", "disabled"),
|
background: background(theme.highest, "on", "disabled"),
|
||||||
border: border(theme.highest, "on", "disabled"),
|
border: border(theme.highest, "on", "disabled"),
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
button_margin: 8,
|
button_margin: 8,
|
||||||
|
|
|
@ -152,7 +152,7 @@ export default function picker(): any {
|
||||||
0.5
|
0.5
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,17 +64,17 @@ export default function project_panel(): any {
|
||||||
const unselected_default_style = merge(
|
const unselected_default_style = merge(
|
||||||
base_properties,
|
base_properties,
|
||||||
unselected?.default ?? {},
|
unselected?.default ?? {},
|
||||||
{}
|
{},
|
||||||
)
|
)
|
||||||
const unselected_hovered_style = merge(
|
const unselected_hovered_style = merge(
|
||||||
base_properties,
|
base_properties,
|
||||||
{ background: background(theme.middle, "hovered") },
|
{ background: background(theme.middle, "hovered") },
|
||||||
unselected?.hovered ?? {}
|
unselected?.hovered ?? {},
|
||||||
)
|
)
|
||||||
const unselected_clicked_style = merge(
|
const unselected_clicked_style = merge(
|
||||||
base_properties,
|
base_properties,
|
||||||
{ background: background(theme.middle, "pressed") },
|
{ background: background(theme.middle, "pressed") },
|
||||||
unselected?.clicked ?? {}
|
unselected?.clicked ?? {},
|
||||||
)
|
)
|
||||||
const selected_default_style = merge(
|
const selected_default_style = merge(
|
||||||
base_properties,
|
base_properties,
|
||||||
|
@ -82,7 +82,7 @@ export default function project_panel(): any {
|
||||||
background: background(theme.lowest),
|
background: background(theme.lowest),
|
||||||
text: text(theme.lowest, "sans", { size: "sm" }),
|
text: text(theme.lowest, "sans", { size: "sm" }),
|
||||||
},
|
},
|
||||||
selected_style?.default ?? {}
|
selected_style?.default ?? {},
|
||||||
)
|
)
|
||||||
const selected_hovered_style = merge(
|
const selected_hovered_style = merge(
|
||||||
base_properties,
|
base_properties,
|
||||||
|
@ -90,7 +90,7 @@ export default function project_panel(): any {
|
||||||
background: background(theme.lowest, "hovered"),
|
background: background(theme.lowest, "hovered"),
|
||||||
text: text(theme.lowest, "sans", { size: "sm" }),
|
text: text(theme.lowest, "sans", { size: "sm" }),
|
||||||
},
|
},
|
||||||
selected_style?.hovered ?? {}
|
selected_style?.hovered ?? {},
|
||||||
)
|
)
|
||||||
const selected_clicked_style = merge(
|
const selected_clicked_style = merge(
|
||||||
base_properties,
|
base_properties,
|
||||||
|
@ -98,7 +98,7 @@ export default function project_panel(): any {
|
||||||
background: background(theme.lowest, "pressed"),
|
background: background(theme.lowest, "pressed"),
|
||||||
text: text(theme.lowest, "sans", { size: "sm" }),
|
text: text(theme.lowest, "sans", { size: "sm" }),
|
||||||
},
|
},
|
||||||
selected_style?.clicked ?? {}
|
selected_style?.clicked ?? {},
|
||||||
)
|
)
|
||||||
|
|
||||||
return toggleable({
|
return toggleable({
|
||||||
|
@ -175,7 +175,7 @@ export default function project_panel(): any {
|
||||||
default: {
|
default: {
|
||||||
icon_color: foreground(theme.middle, "variant"),
|
icon_color: foreground(theme.middle, "variant"),
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
cut_entry: entry(
|
cut_entry: entry(
|
||||||
{
|
{
|
||||||
|
@ -190,7 +190,7 @@ export default function project_panel(): any {
|
||||||
size: "sm",
|
size: "sm",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
filename_editor: {
|
filename_editor: {
|
||||||
background: background(theme.middle, "on"),
|
background: background(theme.middle, "on"),
|
||||||
|
|
|
@ -34,14 +34,10 @@ export default function status_bar(): any {
|
||||||
...text(layer, "mono", "variant", { size: "xs" }),
|
...text(layer, "mono", "variant", { size: "xs" }),
|
||||||
},
|
},
|
||||||
active_language: text_button({
|
active_language: text_button({
|
||||||
color: "variant",
|
color: "variant"
|
||||||
}),
|
|
||||||
auto_update_progress_message: text(layer, "sans", "variant", {
|
|
||||||
size: "xs",
|
|
||||||
}),
|
|
||||||
auto_update_done_message: text(layer, "sans", "variant", {
|
|
||||||
size: "xs",
|
|
||||||
}),
|
}),
|
||||||
|
auto_update_progress_message: text(layer, "sans", "variant", { size: "xs" }),
|
||||||
|
auto_update_done_message: text(layer, "sans", "variant", { size: "xs" }),
|
||||||
lsp_status: interactive({
|
lsp_status: interactive({
|
||||||
base: {
|
base: {
|
||||||
...diagnostic_status_container,
|
...diagnostic_status_container,
|
||||||
|
@ -53,7 +49,7 @@ export default function status_bar(): any {
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
hovered: {
|
hovered: {
|
||||||
message: text(layer, "sans"),
|
message: text(layer, "sans", { size: "xs" }),
|
||||||
icon_color: foreground(layer),
|
icon_color: foreground(layer),
|
||||||
background: background(layer, "hovered"),
|
background: background(layer, "hovered"),
|
||||||
},
|
},
|
||||||
|
|
|
@ -187,10 +187,10 @@ export function titlebar(): any {
|
||||||
project_name_divider: text(theme.lowest, "sans", "variant"),
|
project_name_divider: text(theme.lowest, "sans", "variant"),
|
||||||
|
|
||||||
project_menu_button: toggleable_text_button(theme, {
|
project_menu_button: toggleable_text_button(theme, {
|
||||||
color: "base",
|
color: 'base',
|
||||||
}),
|
}),
|
||||||
git_menu_button: toggleable_text_button(theme, {
|
git_menu_button: toggleable_text_button(theme, {
|
||||||
color: "variant",
|
color: 'variant',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// Collaborators
|
// Collaborators
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
import { Scale, Color } from "chroma-js"
|
import { Scale, Color } from "chroma-js"
|
||||||
|
import { Syntax, ThemeSyntax, SyntaxHighlightStyle } from "./syntax"
|
||||||
|
export { Syntax, ThemeSyntax, SyntaxHighlightStyle }
|
||||||
import {
|
import {
|
||||||
ThemeConfig,
|
ThemeConfig,
|
||||||
ThemeAppearance,
|
ThemeAppearance,
|
||||||
ThemeConfigInputColors,
|
ThemeConfigInputColors,
|
||||||
} from "./theme_config"
|
} from "./theme_config"
|
||||||
import { get_ramps } from "./ramps"
|
import { get_ramps } from "./ramps"
|
||||||
import { syntaxStyle } from "./syntax"
|
|
||||||
import { Syntax } from "../types/syntax"
|
|
||||||
|
|
||||||
export interface Theme {
|
export interface Theme {
|
||||||
name: string
|
name: string
|
||||||
is_light: boolean
|
is_light: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* App background, other elements that should sit directly on top of the background.
|
* App background, other elements that should sit directly on top of the background.
|
||||||
*/
|
*/
|
||||||
lowest: Layer
|
lowest: Layer
|
||||||
/**
|
/**
|
||||||
* Panels, tabs, other UI surfaces that sit on top of the background.
|
* Panels, tabs, other UI surfaces that sit on top of the background.
|
||||||
*/
|
*/
|
||||||
middle: Layer
|
middle: Layer
|
||||||
/**
|
/**
|
||||||
* Editors like code buffers, conversation editors, etc.
|
* Editors like code buffers, conversation editors, etc.
|
||||||
*/
|
*/
|
||||||
highest: Layer
|
highest: Layer
|
||||||
|
|
||||||
ramps: RampSet
|
ramps: RampSet
|
||||||
|
@ -31,7 +31,7 @@ export interface Theme {
|
||||||
modal_shadow: Shadow
|
modal_shadow: Shadow
|
||||||
|
|
||||||
players: Players
|
players: Players
|
||||||
syntax: Syntax
|
syntax?: Partial<ThemeSyntax>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Meta {
|
export interface Meta {
|
||||||
|
@ -115,7 +115,12 @@ export interface Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function create_theme(theme: ThemeConfig): Theme {
|
export function create_theme(theme: ThemeConfig): Theme {
|
||||||
const { name, appearance, input_color } = theme
|
const {
|
||||||
|
name,
|
||||||
|
appearance,
|
||||||
|
input_color,
|
||||||
|
override: { syntax },
|
||||||
|
} = theme
|
||||||
|
|
||||||
const is_light = appearance === ThemeAppearance.Light
|
const is_light = appearance === ThemeAppearance.Light
|
||||||
const color_ramps: ThemeConfigInputColors = input_color
|
const color_ramps: ThemeConfigInputColors = input_color
|
||||||
|
@ -157,11 +162,6 @@ export function create_theme(theme: ThemeConfig): Theme {
|
||||||
"7": player(ramps.yellow),
|
"7": player(ramps.yellow),
|
||||||
}
|
}
|
||||||
|
|
||||||
const syntax = syntaxStyle(
|
|
||||||
ramps,
|
|
||||||
theme.override.syntax ? theme.override.syntax : {}
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
is_light,
|
is_light,
|
||||||
|
|
|
@ -1,45 +1,325 @@
|
||||||
import deepmerge from "deepmerge"
|
import deepmerge from "deepmerge"
|
||||||
import { font_weights, ThemeConfigInputSyntax, RampSet } from "../common"
|
import { FontWeight, font_weights, useTheme } from "../common"
|
||||||
import { Syntax, SyntaxHighlightStyle, allSyntaxKeys } from "../types/syntax"
|
import chroma from "chroma-js"
|
||||||
|
|
||||||
// Apply defaults to any missing syntax properties that are not defined manually
|
export interface SyntaxHighlightStyle {
|
||||||
function apply_defaults(
|
color?: string
|
||||||
ramps: RampSet,
|
weight?: FontWeight
|
||||||
syntax_highlights: Partial<Syntax>
|
underline?: boolean
|
||||||
): Syntax {
|
italic?: boolean
|
||||||
const restKeys: (keyof Syntax)[] = allSyntaxKeys.filter(
|
}
|
||||||
(key) => !syntax_highlights[key]
|
|
||||||
)
|
|
||||||
|
|
||||||
const completeSyntax: Syntax = {} as Syntax
|
export interface Syntax {
|
||||||
|
// == Text Styles ====== /
|
||||||
|
comment: SyntaxHighlightStyle
|
||||||
|
// elixir: doc comment
|
||||||
|
"comment.doc": SyntaxHighlightStyle
|
||||||
|
primary: SyntaxHighlightStyle
|
||||||
|
predictive: SyntaxHighlightStyle
|
||||||
|
hint: SyntaxHighlightStyle
|
||||||
|
|
||||||
const defaults: SyntaxHighlightStyle = {
|
// === Formatted Text ====== /
|
||||||
color: ramps.neutral(1).hex(),
|
emphasis: SyntaxHighlightStyle
|
||||||
}
|
"emphasis.strong": SyntaxHighlightStyle
|
||||||
|
title: SyntaxHighlightStyle
|
||||||
|
link_uri: SyntaxHighlightStyle
|
||||||
|
link_text: SyntaxHighlightStyle
|
||||||
|
/** md: indented_code_block, fenced_code_block, code_span */
|
||||||
|
"text.literal": SyntaxHighlightStyle
|
||||||
|
|
||||||
for (const key of restKeys) {
|
// == Punctuation ====== /
|
||||||
{
|
punctuation: SyntaxHighlightStyle
|
||||||
completeSyntax[key] = {
|
/** Example: `(`, `[`, `{`...*/
|
||||||
...defaults,
|
"punctuation.bracket": SyntaxHighlightStyle
|
||||||
}
|
/**., ;*/
|
||||||
|
"punctuation.delimiter": SyntaxHighlightStyle
|
||||||
|
// js, ts: ${, } in a template literal
|
||||||
|
// yaml: *, &, ---, ...
|
||||||
|
"punctuation.special": SyntaxHighlightStyle
|
||||||
|
// md: list_marker_plus, list_marker_dot, etc
|
||||||
|
"punctuation.list_marker": SyntaxHighlightStyle
|
||||||
|
|
||||||
|
// == Strings ====== /
|
||||||
|
|
||||||
|
string: SyntaxHighlightStyle
|
||||||
|
// css: color_value
|
||||||
|
// js: this, super
|
||||||
|
// toml: offset_date_time, local_date_time...
|
||||||
|
"string.special": SyntaxHighlightStyle
|
||||||
|
// elixir: atom, quoted_atom, keyword, quoted_keyword
|
||||||
|
// ruby: simple_symbol, delimited_symbol...
|
||||||
|
"string.special.symbol"?: SyntaxHighlightStyle
|
||||||
|
// elixir, python, yaml...: escape_sequence
|
||||||
|
"string.escape"?: SyntaxHighlightStyle
|
||||||
|
// Regular expressions
|
||||||
|
"string.regex"?: SyntaxHighlightStyle
|
||||||
|
|
||||||
|
// == Types ====== /
|
||||||
|
// We allow Function here because all JS objects literals have this property
|
||||||
|
constructor: SyntaxHighlightStyle | Function // eslint-disable-line @typescript-eslint/ban-types
|
||||||
|
variant: SyntaxHighlightStyle
|
||||||
|
type: SyntaxHighlightStyle
|
||||||
|
// js: predefined_type
|
||||||
|
"type.builtin"?: SyntaxHighlightStyle
|
||||||
|
|
||||||
|
// == Values
|
||||||
|
variable: SyntaxHighlightStyle
|
||||||
|
// this, ...
|
||||||
|
// css: -- (var(--foo))
|
||||||
|
// lua: self
|
||||||
|
"variable.special"?: SyntaxHighlightStyle
|
||||||
|
// c: statement_identifier,
|
||||||
|
label: SyntaxHighlightStyle
|
||||||
|
// css: tag_name, nesting_selector, universal_selector...
|
||||||
|
tag: SyntaxHighlightStyle
|
||||||
|
// css: attribute, pseudo_element_selector (tag_name),
|
||||||
|
attribute: SyntaxHighlightStyle
|
||||||
|
// css: class_name, property_name, namespace_name...
|
||||||
|
property: SyntaxHighlightStyle
|
||||||
|
// true, false, null, nullptr
|
||||||
|
constant: SyntaxHighlightStyle
|
||||||
|
// css: @media, @import, @supports...
|
||||||
|
// js: declare, implements, interface, keyof, public...
|
||||||
|
keyword: SyntaxHighlightStyle
|
||||||
|
// note: js enum is currently defined as a keyword
|
||||||
|
enum: SyntaxHighlightStyle
|
||||||
|
// -, --, ->, !=, &&, ||, <=...
|
||||||
|
operator: SyntaxHighlightStyle
|
||||||
|
number: SyntaxHighlightStyle
|
||||||
|
boolean: SyntaxHighlightStyle
|
||||||
|
// elixir: __MODULE__, __DIR__, __ENV__, etc
|
||||||
|
// go: nil, iota
|
||||||
|
"constant.builtin"?: SyntaxHighlightStyle
|
||||||
|
|
||||||
|
// == Functions ====== /
|
||||||
|
|
||||||
|
function: SyntaxHighlightStyle
|
||||||
|
// lua: assert, error, loadfile, tostring, unpack...
|
||||||
|
"function.builtin"?: SyntaxHighlightStyle
|
||||||
|
// go: call_expression, method_declaration
|
||||||
|
// js: call_expression, method_definition, pair (key, arrow function)
|
||||||
|
// rust: function_item name: (identifier)
|
||||||
|
"function.definition"?: SyntaxHighlightStyle
|
||||||
|
// rust: macro_definition name: (identifier)
|
||||||
|
"function.special.definition"?: SyntaxHighlightStyle
|
||||||
|
"function.method"?: SyntaxHighlightStyle
|
||||||
|
// ruby: identifier/"defined?" // Nate note: I don't fully understand this one.
|
||||||
|
"function.method.builtin"?: SyntaxHighlightStyle
|
||||||
|
|
||||||
|
// == Unsorted ====== /
|
||||||
|
// lua: hash_bang_line
|
||||||
|
preproc: SyntaxHighlightStyle
|
||||||
|
// elixir, python: interpolation (ex: foo in ${foo})
|
||||||
|
// js: template_substitution
|
||||||
|
embedded: SyntaxHighlightStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ThemeSyntax = Partial<Syntax>
|
||||||
|
|
||||||
|
const default_syntax_highlight_style: Omit<SyntaxHighlightStyle, "color"> = {
|
||||||
|
weight: "normal",
|
||||||
|
underline: false,
|
||||||
|
italic: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
function build_default_syntax(): Syntax {
|
||||||
|
const theme = useTheme()
|
||||||
|
|
||||||
|
// Make a temporary object that is allowed to be missing
|
||||||
|
// the "color" property for each style
|
||||||
|
const syntax: {
|
||||||
|
[key: string]: Omit<SyntaxHighlightStyle, "color">
|
||||||
|
} = {}
|
||||||
|
|
||||||
|
// then spread the default to each style
|
||||||
|
for (const key of Object.keys({} as Syntax)) {
|
||||||
|
syntax[key as keyof Syntax] = {
|
||||||
|
...default_syntax_highlight_style,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mergedBaseSyntax = Object.assign(completeSyntax, syntax_highlights)
|
// Mix the neutral and blue colors to get a
|
||||||
|
// predictive color distinct from any other color in the theme
|
||||||
|
const predictive = chroma
|
||||||
|
.mix(
|
||||||
|
theme.ramps.neutral(0.4).hex(),
|
||||||
|
theme.ramps.blue(0.4).hex(),
|
||||||
|
0.45,
|
||||||
|
"lch"
|
||||||
|
)
|
||||||
|
.hex()
|
||||||
|
// Mix the neutral and green colors to get a
|
||||||
|
// hint color distinct from any other color in the theme
|
||||||
|
const hint = chroma
|
||||||
|
.mix(
|
||||||
|
theme.ramps.neutral(0.6).hex(),
|
||||||
|
theme.ramps.blue(0.4).hex(),
|
||||||
|
0.45,
|
||||||
|
"lch"
|
||||||
|
)
|
||||||
|
.hex()
|
||||||
|
|
||||||
return mergedBaseSyntax
|
const color = {
|
||||||
|
primary: theme.ramps.neutral(1).hex(),
|
||||||
|
comment: theme.ramps.neutral(0.71).hex(),
|
||||||
|
punctuation: theme.ramps.neutral(0.86).hex(),
|
||||||
|
predictive: predictive,
|
||||||
|
hint: hint,
|
||||||
|
emphasis: theme.ramps.blue(0.5).hex(),
|
||||||
|
string: theme.ramps.orange(0.5).hex(),
|
||||||
|
function: theme.ramps.yellow(0.5).hex(),
|
||||||
|
type: theme.ramps.cyan(0.5).hex(),
|
||||||
|
constructor: theme.ramps.blue(0.5).hex(),
|
||||||
|
variant: theme.ramps.blue(0.5).hex(),
|
||||||
|
property: theme.ramps.blue(0.5).hex(),
|
||||||
|
enum: theme.ramps.orange(0.5).hex(),
|
||||||
|
operator: theme.ramps.orange(0.5).hex(),
|
||||||
|
number: theme.ramps.green(0.5).hex(),
|
||||||
|
boolean: theme.ramps.green(0.5).hex(),
|
||||||
|
constant: theme.ramps.green(0.5).hex(),
|
||||||
|
keyword: theme.ramps.blue(0.5).hex(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then assign colors and use Syntax to enforce each style getting it's own color
|
||||||
|
const default_syntax: Syntax = {
|
||||||
|
...syntax,
|
||||||
|
comment: {
|
||||||
|
color: color.comment,
|
||||||
|
},
|
||||||
|
"comment.doc": {
|
||||||
|
color: color.comment,
|
||||||
|
},
|
||||||
|
primary: {
|
||||||
|
color: color.primary,
|
||||||
|
},
|
||||||
|
predictive: {
|
||||||
|
color: color.predictive,
|
||||||
|
italic: true,
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
|
color: color.hint,
|
||||||
|
weight: font_weights.bold,
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
color: color.emphasis,
|
||||||
|
},
|
||||||
|
"emphasis.strong": {
|
||||||
|
color: color.emphasis,
|
||||||
|
weight: font_weights.bold,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: color.primary,
|
||||||
|
weight: font_weights.bold,
|
||||||
|
},
|
||||||
|
link_uri: {
|
||||||
|
color: theme.ramps.green(0.5).hex(),
|
||||||
|
underline: true,
|
||||||
|
},
|
||||||
|
link_text: {
|
||||||
|
color: theme.ramps.orange(0.5).hex(),
|
||||||
|
italic: true,
|
||||||
|
},
|
||||||
|
"text.literal": {
|
||||||
|
color: color.string,
|
||||||
|
},
|
||||||
|
punctuation: {
|
||||||
|
color: color.punctuation,
|
||||||
|
},
|
||||||
|
"punctuation.bracket": {
|
||||||
|
color: color.punctuation,
|
||||||
|
},
|
||||||
|
"punctuation.delimiter": {
|
||||||
|
color: color.punctuation,
|
||||||
|
},
|
||||||
|
"punctuation.special": {
|
||||||
|
color: theme.ramps.neutral(0.86).hex(),
|
||||||
|
},
|
||||||
|
"punctuation.list_marker": {
|
||||||
|
color: color.punctuation,
|
||||||
|
},
|
||||||
|
string: {
|
||||||
|
color: color.string,
|
||||||
|
},
|
||||||
|
"string.special": {
|
||||||
|
color: color.string,
|
||||||
|
},
|
||||||
|
"string.special.symbol": {
|
||||||
|
color: color.string,
|
||||||
|
},
|
||||||
|
"string.escape": {
|
||||||
|
color: color.comment,
|
||||||
|
},
|
||||||
|
"string.regex": {
|
||||||
|
color: color.string,
|
||||||
|
},
|
||||||
|
constructor: {
|
||||||
|
color: theme.ramps.blue(0.5).hex(),
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
color: theme.ramps.blue(0.5).hex(),
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
color: color.type,
|
||||||
|
},
|
||||||
|
variable: {
|
||||||
|
color: color.primary,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
color: theme.ramps.blue(0.5).hex(),
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
color: theme.ramps.blue(0.5).hex(),
|
||||||
|
},
|
||||||
|
attribute: {
|
||||||
|
color: theme.ramps.blue(0.5).hex(),
|
||||||
|
},
|
||||||
|
property: {
|
||||||
|
color: theme.ramps.blue(0.5).hex(),
|
||||||
|
},
|
||||||
|
constant: {
|
||||||
|
color: color.constant,
|
||||||
|
},
|
||||||
|
keyword: {
|
||||||
|
color: color.keyword,
|
||||||
|
},
|
||||||
|
enum: {
|
||||||
|
color: color.enum,
|
||||||
|
},
|
||||||
|
operator: {
|
||||||
|
color: color.operator,
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
color: color.number,
|
||||||
|
},
|
||||||
|
boolean: {
|
||||||
|
color: color.boolean,
|
||||||
|
},
|
||||||
|
function: {
|
||||||
|
color: color.function,
|
||||||
|
},
|
||||||
|
preproc: {
|
||||||
|
color: color.primary,
|
||||||
|
},
|
||||||
|
embedded: {
|
||||||
|
color: color.primary,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return default_syntax
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge the base syntax with the theme syntax overrides
|
export function build_syntax(): Syntax {
|
||||||
// This is a deep merge, so any nested properties will be merged as well
|
const theme = useTheme()
|
||||||
// This allows for a theme to only override a single property of a syntax highlight style
|
|
||||||
const merge_syntax = (
|
const default_syntax: Syntax = build_default_syntax()
|
||||||
baseSyntax: Syntax,
|
|
||||||
theme_syntax_overrides: ThemeConfigInputSyntax
|
if (!theme.syntax) {
|
||||||
): Syntax => {
|
return default_syntax
|
||||||
return deepmerge<Syntax, ThemeConfigInputSyntax>(
|
}
|
||||||
baseSyntax,
|
|
||||||
theme_syntax_overrides,
|
const syntax = deepmerge<Syntax, Partial<ThemeSyntax>>(
|
||||||
|
default_syntax,
|
||||||
|
theme.syntax,
|
||||||
{
|
{
|
||||||
arrayMerge: (destinationArray, sourceArray) => [
|
arrayMerge: (destinationArray, sourceArray) => [
|
||||||
...destinationArray,
|
...destinationArray,
|
||||||
|
@ -47,49 +327,6 @@ const merge_syntax = (
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a complete Syntax object of the combined styles of a theme's syntax overrides and the default syntax styles */
|
return syntax
|
||||||
export const syntaxStyle = (
|
|
||||||
ramps: RampSet,
|
|
||||||
theme_syntax_overrides: ThemeConfigInputSyntax
|
|
||||||
): Syntax => {
|
|
||||||
const syntax_highlights: Partial<Syntax> = {
|
|
||||||
comment: { color: ramps.neutral(0.71).hex() },
|
|
||||||
"comment.doc": { color: ramps.neutral(0.71).hex() },
|
|
||||||
primary: { color: ramps.neutral(1).hex() },
|
|
||||||
emphasis: { color: ramps.blue(0.5).hex() },
|
|
||||||
"emphasis.strong": {
|
|
||||||
color: ramps.blue(0.5).hex(),
|
|
||||||
weight: font_weights.bold,
|
|
||||||
},
|
|
||||||
link_uri: { color: ramps.green(0.5).hex(), underline: true },
|
|
||||||
link_text: { color: ramps.orange(0.5).hex(), italic: true },
|
|
||||||
"text.literal": { color: ramps.orange(0.5).hex() },
|
|
||||||
punctuation: { color: ramps.neutral(0.86).hex() },
|
|
||||||
"punctuation.bracket": { color: ramps.neutral(0.86).hex() },
|
|
||||||
"punctuation.special": { color: ramps.neutral(0.86).hex() },
|
|
||||||
"punctuation.delimiter": { color: ramps.neutral(0.86).hex() },
|
|
||||||
"punctuation.list_marker": { color: ramps.neutral(0.86).hex() },
|
|
||||||
string: { color: ramps.orange(0.5).hex() },
|
|
||||||
"string.special": { color: ramps.orange(0.5).hex() },
|
|
||||||
"string.special.symbol": { color: ramps.orange(0.5).hex() },
|
|
||||||
"string.escape": { color: ramps.neutral(0.71).hex() },
|
|
||||||
"string.regex": { color: ramps.orange(0.5).hex() },
|
|
||||||
"method.constructor": { color: ramps.blue(0.5).hex() },
|
|
||||||
type: { color: ramps.cyan(0.5).hex() },
|
|
||||||
label: { color: ramps.blue(0.5).hex() },
|
|
||||||
attribute: { color: ramps.blue(0.5).hex() },
|
|
||||||
property: { color: ramps.blue(0.5).hex() },
|
|
||||||
constant: { color: ramps.green(0.5).hex() },
|
|
||||||
keyword: { color: ramps.blue(0.5).hex() },
|
|
||||||
operator: { color: ramps.orange(0.5).hex() },
|
|
||||||
number: { color: ramps.green(0.5).hex() },
|
|
||||||
boolean: { color: ramps.green(0.5).hex() },
|
|
||||||
function: { color: ramps.yellow(0.5).hex() },
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseSyntax = apply_defaults(ramps, syntax_highlights)
|
|
||||||
const mergedSyntax = merge_syntax(baseSyntax, theme_syntax_overrides)
|
|
||||||
return mergedSyntax
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Scale, Color } from "chroma-js"
|
import { Scale, Color } from "chroma-js"
|
||||||
import { SyntaxHighlightStyle, SyntaxProperty } from "../types/syntax"
|
import { Syntax } from "./syntax"
|
||||||
|
|
||||||
interface ThemeMeta {
|
interface ThemeMeta {
|
||||||
/** The name of the theme */
|
/** The name of the theme */
|
||||||
|
@ -55,9 +55,7 @@ export type ThemeConfigInputColorsKeys = keyof ThemeConfigInputColors
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export type ThemeConfigInputSyntax = Partial<
|
export type ThemeConfigInputSyntax = Partial<Syntax>
|
||||||
Record<SyntaxProperty, Partial<SyntaxHighlightStyle>>
|
|
||||||
>
|
|
||||||
|
|
||||||
interface ThemeConfigOverrides {
|
interface ThemeConfigOverrides {
|
||||||
syntax: ThemeConfigInputSyntax
|
syntax: ThemeConfigInputSyntax
|
||||||
|
|
|
@ -4,13 +4,17 @@ import {
|
||||||
SingleOtherToken,
|
SingleOtherToken,
|
||||||
TokenTypes,
|
TokenTypes,
|
||||||
} from "@tokens-studio/types"
|
} from "@tokens-studio/types"
|
||||||
import { Shadow } from "../create_theme"
|
import {
|
||||||
|
Shadow,
|
||||||
|
SyntaxHighlightStyle,
|
||||||
|
ThemeSyntax,
|
||||||
|
} from "../create_theme"
|
||||||
import { LayerToken, layer_token } from "./layer"
|
import { LayerToken, layer_token } from "./layer"
|
||||||
import { PlayersToken, players_token } from "./players"
|
import { PlayersToken, players_token } from "./players"
|
||||||
import { color_token } from "./token"
|
import { color_token } from "./token"
|
||||||
|
import { Syntax } from "../syntax"
|
||||||
import editor from "../../style_tree/editor"
|
import editor from "../../style_tree/editor"
|
||||||
import { useTheme } from "../../../src/common"
|
import { useTheme } from "../../../src/common"
|
||||||
import { Syntax, SyntaxHighlightStyle } from "../../types/syntax"
|
|
||||||
|
|
||||||
interface ThemeTokens {
|
interface ThemeTokens {
|
||||||
name: SingleOtherToken
|
name: SingleOtherToken
|
||||||
|
@ -47,7 +51,7 @@ const modal_shadow_token = (): SingleBoxShadowToken => {
|
||||||
return create_shadow_token(shadow, "modal_shadow")
|
return create_shadow_token(shadow, "modal_shadow")
|
||||||
}
|
}
|
||||||
|
|
||||||
type ThemeSyntaxColorTokens = Record<keyof Syntax, SingleColorToken>
|
type ThemeSyntaxColorTokens = Record<keyof ThemeSyntax, SingleColorToken>
|
||||||
|
|
||||||
function syntax_highlight_style_color_tokens(
|
function syntax_highlight_style_color_tokens(
|
||||||
syntax: Syntax
|
syntax: Syntax
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
import {
|
import { ThemeLicenseType, ThemeSyntax, ThemeFamilyMeta } from "../../common"
|
||||||
ThemeLicenseType,
|
|
||||||
ThemeFamilyMeta,
|
|
||||||
ThemeConfigInputSyntax,
|
|
||||||
} from "../../common"
|
|
||||||
|
|
||||||
export interface Variant {
|
export interface Variant {
|
||||||
colors: {
|
colors: {
|
||||||
|
@ -33,7 +29,7 @@ export const meta: ThemeFamilyMeta = {
|
||||||
"https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/",
|
"https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const build_syntax = (variant: Variant): ThemeConfigInputSyntax => {
|
export const build_syntax = (variant: Variant): ThemeSyntax => {
|
||||||
const { colors } = variant
|
const { colors } = variant
|
||||||
return {
|
return {
|
||||||
primary: { color: colors.base06 },
|
primary: { color: colors.base06 },
|
||||||
|
@ -54,6 +50,7 @@ export const build_syntax = (variant: Variant): ThemeConfigInputSyntax => {
|
||||||
property: { color: colors.base08 },
|
property: { color: colors.base08 },
|
||||||
variable: { color: colors.base06 },
|
variable: { color: colors.base06 },
|
||||||
"variable.special": { color: colors.base0E },
|
"variable.special": { color: colors.base0E },
|
||||||
|
variant: { color: colors.base0A },
|
||||||
keyword: { color: colors.base0E },
|
keyword: { color: colors.base0E },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ import {
|
||||||
chroma,
|
chroma,
|
||||||
color_ramp,
|
color_ramp,
|
||||||
ThemeLicenseType,
|
ThemeLicenseType,
|
||||||
|
ThemeSyntax,
|
||||||
ThemeFamilyMeta,
|
ThemeFamilyMeta,
|
||||||
ThemeConfigInputSyntax,
|
|
||||||
} from "../../common"
|
} from "../../common"
|
||||||
|
|
||||||
export const ayu = {
|
export const ayu = {
|
||||||
|
@ -27,7 +27,7 @@ export const build_theme = (t: typeof dark, light: boolean) => {
|
||||||
purple: t.syntax.constant.hex(),
|
purple: t.syntax.constant.hex(),
|
||||||
}
|
}
|
||||||
|
|
||||||
const syntax: ThemeConfigInputSyntax = {
|
const syntax: ThemeSyntax = {
|
||||||
constant: { color: t.syntax.constant.hex() },
|
constant: { color: t.syntax.constant.hex() },
|
||||||
"string.regex": { color: t.syntax.regexp.hex() },
|
"string.regex": { color: t.syntax.regexp.hex() },
|
||||||
string: { color: t.syntax.string.hex() },
|
string: { color: t.syntax.string.hex() },
|
||||||
|
@ -61,7 +61,7 @@ export const build_theme = (t: typeof dark, light: boolean) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const build_syntax = (t: typeof dark): ThemeConfigInputSyntax => {
|
export const build_syntax = (t: typeof dark): ThemeSyntax => {
|
||||||
return {
|
return {
|
||||||
constant: { color: t.syntax.constant.hex() },
|
constant: { color: t.syntax.constant.hex() },
|
||||||
"string.regex": { color: t.syntax.regexp.hex() },
|
"string.regex": { color: t.syntax.regexp.hex() },
|
||||||
|
|
|
@ -4,8 +4,8 @@ import {
|
||||||
ThemeAppearance,
|
ThemeAppearance,
|
||||||
ThemeLicenseType,
|
ThemeLicenseType,
|
||||||
ThemeConfig,
|
ThemeConfig,
|
||||||
|
ThemeSyntax,
|
||||||
ThemeFamilyMeta,
|
ThemeFamilyMeta,
|
||||||
ThemeConfigInputSyntax,
|
|
||||||
} from "../../common"
|
} from "../../common"
|
||||||
|
|
||||||
const meta: ThemeFamilyMeta = {
|
const meta: ThemeFamilyMeta = {
|
||||||
|
@ -214,7 +214,7 @@ const build_variant = (variant: Variant): ThemeConfig => {
|
||||||
magenta: color_ramp(chroma(variant.colors.gray)),
|
magenta: color_ramp(chroma(variant.colors.gray)),
|
||||||
}
|
}
|
||||||
|
|
||||||
const syntax: ThemeConfigInputSyntax = {
|
const syntax: ThemeSyntax = {
|
||||||
primary: { color: neutral[is_light ? 0 : 8] },
|
primary: { color: neutral[is_light ? 0 : 8] },
|
||||||
"text.literal": { color: colors.blue },
|
"text.literal": { color: colors.blue },
|
||||||
comment: { color: colors.gray },
|
comment: { color: colors.gray },
|
||||||
|
@ -229,7 +229,7 @@ const build_variant = (variant: Variant): ThemeConfig => {
|
||||||
"string.special.symbol": { color: colors.aqua },
|
"string.special.symbol": { color: colors.aqua },
|
||||||
"string.regex": { color: colors.orange },
|
"string.regex": { color: colors.orange },
|
||||||
type: { color: colors.yellow },
|
type: { color: colors.yellow },
|
||||||
// enum: { color: colors.orange },
|
enum: { color: colors.orange },
|
||||||
tag: { color: colors.aqua },
|
tag: { color: colors.aqua },
|
||||||
constant: { color: colors.yellow },
|
constant: { color: colors.yellow },
|
||||||
keyword: { color: colors.red },
|
keyword: { color: colors.red },
|
||||||
|
|
|
@ -54,6 +54,7 @@ export const theme: ThemeConfig = {
|
||||||
syntax: {
|
syntax: {
|
||||||
boolean: { color: color.orange },
|
boolean: { color: color.orange },
|
||||||
comment: { color: color.grey },
|
comment: { color: color.grey },
|
||||||
|
enum: { color: color.red },
|
||||||
"emphasis.strong": { color: color.orange },
|
"emphasis.strong": { color: color.orange },
|
||||||
function: { color: color.blue },
|
function: { color: color.blue },
|
||||||
keyword: { color: color.purple },
|
keyword: { color: color.purple },
|
||||||
|
@ -72,7 +73,8 @@ export const theme: ThemeConfig = {
|
||||||
"text.literal": { color: color.green },
|
"text.literal": { color: color.green },
|
||||||
type: { color: color.teal },
|
type: { color: color.teal },
|
||||||
"variable.special": { color: color.orange },
|
"variable.special": { color: color.orange },
|
||||||
"method.constructor": { color: color.blue },
|
variant: { color: color.blue },
|
||||||
|
constructor: { color: color.blue },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ export const theme: ThemeConfig = {
|
||||||
syntax: {
|
syntax: {
|
||||||
boolean: { color: color.orange },
|
boolean: { color: color.orange },
|
||||||
comment: { color: color.grey },
|
comment: { color: color.grey },
|
||||||
|
enum: { color: color.red },
|
||||||
"emphasis.strong": { color: color.orange },
|
"emphasis.strong": { color: color.orange },
|
||||||
function: { color: color.blue },
|
function: { color: color.blue },
|
||||||
keyword: { color: color.purple },
|
keyword: { color: color.purple },
|
||||||
|
@ -72,6 +73,7 @@ export const theme: ThemeConfig = {
|
||||||
"text.literal": { color: color.green },
|
"text.literal": { color: color.green },
|
||||||
type: { color: color.teal },
|
type: { color: color.teal },
|
||||||
"variable.special": { color: color.orange },
|
"variable.special": { color: color.orange },
|
||||||
|
variant: { color: color.blue },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ThemeConfigInputSyntax } from "../../common"
|
import { ThemeSyntax } from "../../common"
|
||||||
|
|
||||||
export const color = {
|
export const color = {
|
||||||
default: {
|
default: {
|
||||||
|
@ -54,7 +54,7 @@ export const color = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const syntax = (c: typeof color.default): ThemeConfigInputSyntax => {
|
export const syntax = (c: typeof color.default): Partial<ThemeSyntax> => {
|
||||||
return {
|
return {
|
||||||
comment: { color: c.muted },
|
comment: { color: c.muted },
|
||||||
operator: { color: c.pine },
|
operator: { color: c.pine },
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
import fs from "fs"
|
|
||||||
import path from "path"
|
|
||||||
import readline from "readline"
|
|
||||||
|
|
||||||
function escapeTypeName(name: string): string {
|
|
||||||
return `'${name.replace("@", "").toLowerCase()}'`
|
|
||||||
}
|
|
||||||
|
|
||||||
const generatedNote = `// This file is generated by extract_syntax_types.ts
|
|
||||||
// Do not edit this file directly
|
|
||||||
// It is generated from the highlight.scm files in the zed crate
|
|
||||||
|
|
||||||
// To regenerate this file manually:
|
|
||||||
// 'npm run extract-syntax-types' from ./styles`
|
|
||||||
|
|
||||||
const defaultTextProperty = ` /** Default text color */
|
|
||||||
| 'primary'`
|
|
||||||
|
|
||||||
const main = async () => {
|
|
||||||
const pathFromRoot = "crates/zed/src/languages"
|
|
||||||
const directoryPath = path.join(__dirname, "../../../", pathFromRoot)
|
|
||||||
const stylesMap: Record<string, Set<string>> = {}
|
|
||||||
const propertyLanguageMap: Record<string, Set<string>> = {}
|
|
||||||
|
|
||||||
const processFile = async (filePath: string, language: string) => {
|
|
||||||
const fileStream = fs.createReadStream(filePath)
|
|
||||||
const rl = readline.createInterface({
|
|
||||||
input: fileStream,
|
|
||||||
crlfDelay: Infinity,
|
|
||||||
})
|
|
||||||
|
|
||||||
for await (const line of rl) {
|
|
||||||
const cleanedLine = line.replace(/"@[a-zA-Z0-9_.]*"/g, "")
|
|
||||||
const match = cleanedLine.match(/@(\w+\.*)*/g)
|
|
||||||
if (match) {
|
|
||||||
match.forEach((property) => {
|
|
||||||
const formattedProperty = escapeTypeName(property)
|
|
||||||
// Only add non-empty properties
|
|
||||||
if (formattedProperty !== "''") {
|
|
||||||
if (!propertyLanguageMap[formattedProperty]) {
|
|
||||||
propertyLanguageMap[formattedProperty] = new Set()
|
|
||||||
}
|
|
||||||
propertyLanguageMap[formattedProperty].add(language)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const directories = fs
|
|
||||||
.readdirSync(directoryPath, { withFileTypes: true })
|
|
||||||
.filter((dirent) => dirent.isDirectory())
|
|
||||||
.map((dirent) => dirent.name)
|
|
||||||
|
|
||||||
for (const dir of directories) {
|
|
||||||
const highlightsFilePath = path.join(
|
|
||||||
directoryPath,
|
|
||||||
dir,
|
|
||||||
"highlights.scm"
|
|
||||||
)
|
|
||||||
if (fs.existsSync(highlightsFilePath)) {
|
|
||||||
await processFile(highlightsFilePath, dir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [language, properties] of Object.entries(stylesMap)) {
|
|
||||||
console.log(`${language}: ${Array.from(properties).join(", ")}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const sortedProperties = Object.entries(propertyLanguageMap).sort(
|
|
||||||
([propA], [propB]) => propA.localeCompare(propB)
|
|
||||||
)
|
|
||||||
|
|
||||||
const outStream = fs.createWriteStream(path.join(__dirname, "syntax.ts"))
|
|
||||||
let allProperties = ""
|
|
||||||
const syntaxKeys = []
|
|
||||||
for (const [property, languages] of sortedProperties) {
|
|
||||||
let languagesArray = Array.from(languages)
|
|
||||||
const moreThanSeven = languagesArray.length > 7
|
|
||||||
// Limit to the first 7 languages, append "..." if more than 7
|
|
||||||
languagesArray = languagesArray.slice(0, 7)
|
|
||||||
if (moreThanSeven) {
|
|
||||||
languagesArray.push("...")
|
|
||||||
}
|
|
||||||
const languagesString = languagesArray.join(", ")
|
|
||||||
const comment = `/** ${languagesString} */`
|
|
||||||
allProperties += ` ${comment}\n | ${property} \n`
|
|
||||||
syntaxKeys.push(property)
|
|
||||||
}
|
|
||||||
outStream.write(`${generatedNote}
|
|
||||||
|
|
||||||
export type SyntaxHighlightStyle = {
|
|
||||||
color: string,
|
|
||||||
fade_out?: number,
|
|
||||||
italic?: boolean,
|
|
||||||
underline?: boolean,
|
|
||||||
weight?: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Syntax = Record<SyntaxProperty, SyntaxHighlightStyle>
|
|
||||||
export type SyntaxOverride = Partial<Syntax>
|
|
||||||
|
|
||||||
export type SyntaxProperty = \n${defaultTextProperty}\n\n${allProperties}
|
|
||||||
|
|
||||||
export const allSyntaxKeys: SyntaxProperty[] = [\n ${syntaxKeys.join(
|
|
||||||
",\n "
|
|
||||||
)}\n]`)
|
|
||||||
outStream.end()
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch(console.error)
|
|
|
@ -1,202 +0,0 @@
|
||||||
// This file is generated by extract_syntax_types.ts
|
|
||||||
// Do not edit this file directly
|
|
||||||
// It is generated from the highlight.scm files in the zed crate
|
|
||||||
|
|
||||||
// To regenerate this file manually:
|
|
||||||
// 'npm run extract-syntax-types' from ./styles
|
|
||||||
|
|
||||||
export type SyntaxHighlightStyle = {
|
|
||||||
color: string
|
|
||||||
fade_out?: number
|
|
||||||
italic?: boolean
|
|
||||||
underline?: boolean
|
|
||||||
weight?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Syntax = Record<SyntaxProperty, SyntaxHighlightStyle>
|
|
||||||
export type SyntaxOverride = Partial<Syntax>
|
|
||||||
|
|
||||||
export type SyntaxProperty =
|
|
||||||
/** Default text color */
|
|
||||||
| "primary"
|
|
||||||
|
|
||||||
/** elixir */
|
|
||||||
| "__attribute__"
|
|
||||||
/** elixir */
|
|
||||||
| "__name__"
|
|
||||||
/** elixir */
|
|
||||||
| "_sigil_name"
|
|
||||||
/** css, heex, lua */
|
|
||||||
| "attribute"
|
|
||||||
/** javascript, lua, tsx, typescript, yaml */
|
|
||||||
| "boolean"
|
|
||||||
/** elixir */
|
|
||||||
| "comment.doc"
|
|
||||||
/** elixir */
|
|
||||||
| "comment.unused"
|
|
||||||
/** bash, c, cpp, css, elixir, elm, erb, ... */
|
|
||||||
| "comment"
|
|
||||||
/** elixir, go, javascript, lua, php, python, racket, ... */
|
|
||||||
| "constant.builtin"
|
|
||||||
/** bash, c, cpp, elixir, elm, glsl, heex, ... */
|
|
||||||
| "constant"
|
|
||||||
/** glsl */
|
|
||||||
| "delimiter"
|
|
||||||
/** bash, elixir, javascript, python, ruby, tsx, typescript */
|
|
||||||
| "embedded"
|
|
||||||
/** markdown */
|
|
||||||
| "emphasis.strong"
|
|
||||||
/** markdown */
|
|
||||||
| "emphasis"
|
|
||||||
/** go, python, racket, ruby, scheme */
|
|
||||||
| "escape"
|
|
||||||
/** lua */
|
|
||||||
| "field"
|
|
||||||
/** lua, php, python */
|
|
||||||
| "function.builtin"
|
|
||||||
/** elm, lua, rust */
|
|
||||||
| "function.definition"
|
|
||||||
/** ruby */
|
|
||||||
| "function.method.builtin"
|
|
||||||
/** go, javascript, php, python, ruby, rust, tsx, ... */
|
|
||||||
| "function.method"
|
|
||||||
/** rust */
|
|
||||||
| "function.special.definition"
|
|
||||||
/** c, cpp, glsl, rust */
|
|
||||||
| "function.special"
|
|
||||||
/** bash, c, cpp, css, elixir, elm, glsl, ... */
|
|
||||||
| "function"
|
|
||||||
/** elm */
|
|
||||||
| "identifier"
|
|
||||||
/** glsl */
|
|
||||||
| "keyword.function"
|
|
||||||
/** bash, c, cpp, css, elixir, elm, erb, ... */
|
|
||||||
| "keyword"
|
|
||||||
/** c, cpp, glsl */
|
|
||||||
| "label"
|
|
||||||
/** markdown */
|
|
||||||
| "link_text"
|
|
||||||
/** markdown */
|
|
||||||
| "link_uri"
|
|
||||||
/** lua, php, tsx, typescript */
|
|
||||||
| "method.constructor"
|
|
||||||
/** lua */
|
|
||||||
| "method"
|
|
||||||
/** heex */
|
|
||||||
| "module"
|
|
||||||
/** svelte */
|
|
||||||
| "none"
|
|
||||||
/** bash, c, cpp, css, elixir, glsl, go, ... */
|
|
||||||
| "number"
|
|
||||||
/** bash, c, cpp, css, elixir, elm, glsl, ... */
|
|
||||||
| "operator"
|
|
||||||
/** lua */
|
|
||||||
| "parameter"
|
|
||||||
/** lua */
|
|
||||||
| "preproc"
|
|
||||||
/** bash, c, cpp, css, glsl, go, html, ... */
|
|
||||||
| "property"
|
|
||||||
/** c, cpp, elixir, elm, heex, html, javascript, ... */
|
|
||||||
| "punctuation.bracket"
|
|
||||||
/** c, cpp, css, elixir, elm, heex, javascript, ... */
|
|
||||||
| "punctuation.delimiter"
|
|
||||||
/** markdown */
|
|
||||||
| "punctuation.list_marker"
|
|
||||||
/** elixir, javascript, python, ruby, tsx, typescript, yaml */
|
|
||||||
| "punctuation.special"
|
|
||||||
/** elixir */
|
|
||||||
| "punctuation"
|
|
||||||
/** glsl */
|
|
||||||
| "storageclass"
|
|
||||||
/** elixir, elm, yaml */
|
|
||||||
| "string.escape"
|
|
||||||
/** elixir, javascript, racket, ruby, tsx, typescript */
|
|
||||||
| "string.regex"
|
|
||||||
/** elixir, ruby */
|
|
||||||
| "string.special.symbol"
|
|
||||||
/** css, elixir, toml */
|
|
||||||
| "string.special"
|
|
||||||
/** bash, c, cpp, css, elixir, elm, glsl, ... */
|
|
||||||
| "string"
|
|
||||||
/** svelte */
|
|
||||||
| "tag.delimiter"
|
|
||||||
/** css, heex, php, svelte */
|
|
||||||
| "tag"
|
|
||||||
/** markdown */
|
|
||||||
| "text.literal"
|
|
||||||
/** markdown */
|
|
||||||
| "title"
|
|
||||||
/** javascript, php, rust, tsx, typescript */
|
|
||||||
| "type.builtin"
|
|
||||||
/** glsl */
|
|
||||||
| "type.qualifier"
|
|
||||||
/** c, cpp, css, elixir, elm, glsl, go, ... */
|
|
||||||
| "type"
|
|
||||||
/** glsl, php */
|
|
||||||
| "variable.builtin"
|
|
||||||
/** cpp, css, javascript, lua, racket, ruby, rust, ... */
|
|
||||||
| "variable.special"
|
|
||||||
/** c, cpp, elm, glsl, go, javascript, lua, ... */
|
|
||||||
| "variable"
|
|
||||||
|
|
||||||
export const allSyntaxKeys: SyntaxProperty[] = [
|
|
||||||
"__attribute__",
|
|
||||||
"__name__",
|
|
||||||
"_sigil_name",
|
|
||||||
"attribute",
|
|
||||||
"boolean",
|
|
||||||
"comment.doc",
|
|
||||||
"comment.unused",
|
|
||||||
"comment",
|
|
||||||
"constant.builtin",
|
|
||||||
"constant",
|
|
||||||
"delimiter",
|
|
||||||
"embedded",
|
|
||||||
"emphasis.strong",
|
|
||||||
"emphasis",
|
|
||||||
"escape",
|
|
||||||
"field",
|
|
||||||
"function.builtin",
|
|
||||||
"function.definition",
|
|
||||||
"function.method.builtin",
|
|
||||||
"function.method",
|
|
||||||
"function.special.definition",
|
|
||||||
"function.special",
|
|
||||||
"function",
|
|
||||||
"identifier",
|
|
||||||
"keyword.function",
|
|
||||||
"keyword",
|
|
||||||
"label",
|
|
||||||
"link_text",
|
|
||||||
"link_uri",
|
|
||||||
"method.constructor",
|
|
||||||
"method",
|
|
||||||
"module",
|
|
||||||
"none",
|
|
||||||
"number",
|
|
||||||
"operator",
|
|
||||||
"parameter",
|
|
||||||
"preproc",
|
|
||||||
"property",
|
|
||||||
"punctuation.bracket",
|
|
||||||
"punctuation.delimiter",
|
|
||||||
"punctuation.list_marker",
|
|
||||||
"punctuation.special",
|
|
||||||
"punctuation",
|
|
||||||
"storageclass",
|
|
||||||
"string.escape",
|
|
||||||
"string.regex",
|
|
||||||
"string.special.symbol",
|
|
||||||
"string.special",
|
|
||||||
"string",
|
|
||||||
"tag.delimiter",
|
|
||||||
"tag",
|
|
||||||
"text.literal",
|
|
||||||
"title",
|
|
||||||
"type.builtin",
|
|
||||||
"type.qualifier",
|
|
||||||
"type",
|
|
||||||
"variable.builtin",
|
|
||||||
"variable.special",
|
|
||||||
"variable",
|
|
||||||
]
|
|
Loading…
Add table
Add a link
Reference in a new issue