diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a773ef6c7cade1b16d058a898577c89d0801bb5d..e97c529faf7eaa64d21f37832f97eb31c3ade3d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,11 @@ jobs: target: x86_64-apple-darwin profile: minimal + - name: Install Node + uses: actions/setup-node@v2 + with: + node-version: '16' + - name: Checkout repo uses: actions/checkout@v2 with: diff --git a/.gitignore b/.gitignore index a733bb3bb7ae5989e360381895664529dbef861d..f280b60475b367b16c13583975b32e81a95f4fd7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /crates/collab/.env.toml /crates/collab/static/styles.css /vendor/bin +/assets/themes/*.json diff --git a/.zed.toml b/.zed.toml deleted file mode 100644 index fae32125f4f236c7bc99f57f5bf9e6e041984069..0000000000000000000000000000000000000000 --- a/.zed.toml +++ /dev/null @@ -1 +0,0 @@ -collaborators = ["nathansobo", "as-cii", "maxbrunsfeld", "iamnbutler", "gibusu", "Kethku"] diff --git a/Cargo.lock b/Cargo.lock index f1254538f5c0838881d4e55ff87ddd2a7d0b618a..e9f385b173e428f332775e584b8e4295a88d2d5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -909,6 +909,7 @@ dependencies = [ "fuzzy", "gpui", "picker", + "project", "serde_json", "settings", "theme", diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index fdd5a4fcbb0e9da9f8727119253e59d8e82cacfb..0f2589e31d94b44325573ffc735e3cac8037f6fb 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -18,7 +18,10 @@ "cmd-s": "workspace::Save", "cmd-=": "zed::IncreaseBufferFontSize", "cmd--": "zed::DecreaseBufferFontSize", - "cmd-,": "zed::OpenSettings" + "cmd-,": "zed::OpenSettings", + "cmd-q": "zed::Quit", + "cmd-n": "workspace::OpenNew", + "cmd-o": "workspace::Open" } }, { @@ -210,7 +213,6 @@ "bindings": { "cmd-shift-F": "project_search::Deploy", "cmd-k cmd-t": "theme_selector::Toggle", - "cmd-k t": "theme_selector::Reload", "cmd-k cmd-s": "zed::OpenKeymap", "cmd-t": "project_symbols::Toggle", "cmd-p": "file_finder::Toggle", diff --git a/assets/themes/.gitkeep b/assets/themes/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index 65365a59923a2644f4b2df1dee3c8a36a3f30bae..d88236843842fa09ccd26552809c2514cba4e35a 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -470,6 +470,19 @@ impl Server { state.unregister_project(request.payload.project_id, request.sender_id)?; (state.user_id_for_connection(request.sender_id)?, project) }; + + broadcast( + request.sender_id, + project.guests.keys().copied(), + |conn_id| { + self.peer.send( + conn_id, + proto::UnregisterProject { + project_id: request.payload.project_id, + }, + ) + }, + ); for (_, receipts) in project.join_requests { for receipt in receipts { self.peer.respond( @@ -1665,7 +1678,7 @@ mod tests { use gpui::{ executor::{self, Deterministic}, geometry::vector::vec2f, - ModelHandle, TestAppContext, ViewHandle, + ModelHandle, Task, TestAppContext, ViewHandle, }; use language::{ range_to_lsp, tree_sitter_rust, Diagnostic, DiagnosticEntry, FakeLspAdapter, Language, @@ -1697,7 +1710,7 @@ mod tests { time::Duration, }; use theme::ThemeRegistry; - use workspace::{Item, SplitDirection, ToggleFollow, Workspace, WorkspaceParams}; + use workspace::{Item, SplitDirection, ToggleFollow, Workspace}; #[cfg(test)] #[ctor::ctor] @@ -1930,6 +1943,14 @@ mod tests { .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) .await .unwrap(); + + // When client A (the host) leaves, the project gets unshared and guests are notified. + cx_a.update(|_| drop(project_a)); + deterministic.run_until_parked(); + project_b2.read_with(cx_b, |project, _| { + assert!(project.is_read_only()); + assert!(project.collaborators().is_empty()); + }); } #[gpui::test(iterations = 10)] @@ -4357,13 +4378,7 @@ mod tests { // Join the project as client B. let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; - let mut params = cx_b.update(WorkspaceParams::test); - params.languages = lang_registry.clone(); - params.project = project_b.clone(); - params.client = client_b.client.clone(); - params.user_store = client_b.user_store.clone(); - - let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(¶ms, cx)); + let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(project_b.clone(), cx)); let editor_b = workspace_b .update(cx_b, |workspace, cx| { workspace.open_path((worktree_id, "main.rs"), true, cx) @@ -4598,13 +4613,7 @@ mod tests { // Join the worktree as client B. let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; - let mut params = cx_b.update(WorkspaceParams::test); - params.languages = lang_registry.clone(); - params.project = project_b.clone(); - params.client = client_b.client.clone(); - params.user_store = client_b.user_store.clone(); - - let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(¶ms, cx)); + let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(project_b.clone(), cx)); let editor_b = workspace_b .update(cx_b, |workspace, cx| { workspace.open_path((worktree_id, "one.rs"), true, cx) @@ -6637,13 +6646,21 @@ mod tests { }) }); + let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx)); + let app_state = Arc::new(workspace::AppState { + client: client.clone(), + user_store: user_store.clone(), + languages: Arc::new(LanguageRegistry::new(Task::ready(()))), + themes: ThemeRegistry::new((), cx.font_cache()), + fs: FakeFs::new(cx.background()), + build_window_options: || Default::default(), + initialize_workspace: |_, _, _| unimplemented!(), + }); + Channel::init(&client); Project::init(&client); - cx.update(|cx| { - workspace::init(&client, cx); - }); + cx.update(|cx| workspace::init(app_state.clone(), cx)); - let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx)); client .authenticate_and_connect(false, &cx.to_async()) .await @@ -6882,23 +6899,7 @@ mod tests { cx: &mut TestAppContext, ) -> ViewHandle { let (window_id, _) = cx.add_window(|_| EmptyView); - cx.add_view(window_id, |cx| { - let fs = project.read(cx).fs().clone(); - Workspace::new( - &WorkspaceParams { - fs, - project: project.clone(), - user_store: self.user_store.clone(), - languages: self.language_registry.clone(), - themes: ThemeRegistry::new((), cx.font_cache().clone()), - channel_list: cx.add_model(|cx| { - ChannelList::new(self.user_store.clone(), self.client.clone(), cx) - }), - client: self.client.clone(), - }, - cx, - ) - }) + cx.add_view(window_id, |cx| Workspace::new(project.clone(), cx)) } async fn simulate_host( diff --git a/crates/command_palette/Cargo.toml b/crates/command_palette/Cargo.toml index aeaffa3e6f0fd77082a1e4b9cd7896da9b713669..2a4d27570fc0552fc19ab3a94df2bab8ff03f326 100644 --- a/crates/command_palette/Cargo.toml +++ b/crates/command_palette/Cargo.toml @@ -12,6 +12,7 @@ editor = { path = "../editor" } fuzzy = { path = "../fuzzy" } gpui = { path = "../gpui" } picker = { path = "../picker" } +project = { path = "../project" } settings = { path = "../settings" } util = { path = "../util" } theme = { path = "../theme" } @@ -20,6 +21,7 @@ workspace = { path = "../workspace" } [dev-dependencies] gpui = { path = "../gpui", features = ["test-support"] } editor = { path = "../editor", features = ["test-support"] } +project = { path = "../project", features = ["test-support"] } serde_json = { version = "1.0.64", features = ["preserve_order"] } workspace = { path = "../workspace", features = ["test-support"] } ctor = "0.1" diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index f724cc19a611866e6252af79c9e67ac1d61dff6c..9f0f396d8530b4d074a4763772c0584a9d5f263b 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -299,7 +299,8 @@ mod tests { use super::*; use editor::Editor; use gpui::TestAppContext; - use workspace::{Workspace, WorkspaceParams}; + use project::Project; + use workspace::{AppState, Workspace}; #[test] fn test_humanize_action_name() { @@ -319,15 +320,16 @@ mod tests { #[gpui::test] async fn test_command_palette(cx: &mut TestAppContext) { - let params = cx.update(WorkspaceParams::test); + let app_state = cx.update(AppState::test); cx.update(|cx| { editor::init(cx); - workspace::init(¶ms.client, cx); + workspace::init(app_state.clone(), cx); init(cx); }); - let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); + let project = Project::test(app_state.fs.clone(), [], cx).await; + let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); let editor = cx.add_view(window_id, |cx| { let mut editor = Editor::single_line(None, cx); editor.set_text("abc", cx); diff --git a/crates/contacts_panel/src/contacts_panel.rs b/crates/contacts_panel/src/contacts_panel.rs index a1d1d31aa4e237fe0090b7b1248eaa4ffdb554c6..44aa0626c59cea9a6704e1c8bef7e28920d80c4c 100644 --- a/crates/contacts_panel/src/contacts_panel.rs +++ b/crates/contacts_panel/src/contacts_panel.rs @@ -23,7 +23,7 @@ use theme::IconButton; use workspace::{ menu::{Confirm, SelectNext, SelectPrev}, sidebar::SidebarItem, - AppState, JoinProject, Workspace, + JoinProject, Workspace, }; impl_actions!( @@ -60,7 +60,6 @@ pub struct ContactsPanel { filter_editor: ViewHandle, collapsed_sections: Vec
, selection: Option, - app_state: Arc, _maintain_contacts: Subscription, } @@ -92,7 +91,7 @@ pub fn init(cx: &mut MutableAppContext) { impl ContactsPanel { pub fn new( - app_state: Arc, + user_store: ModelHandle, workspace: WeakViewHandle, cx: &mut ViewContext, ) -> Self { @@ -152,8 +151,8 @@ impl ContactsPanel { } }); - cx.subscribe(&app_state.user_store, { - let user_store = app_state.user_store.downgrade(); + cx.subscribe(&user_store, { + let user_store = user_store.downgrade(); move |_, _, event, cx| { if let Some((workspace, user_store)) = workspace.upgrade(cx).zip(user_store.upgrade(cx)) @@ -187,7 +186,6 @@ impl ContactsPanel { let mut this = Self { list_state: ListState::new(0, Orientation::Top, 1000., { let this = cx.weak_handle(); - let app_state = app_state.clone(); move |ix, cx| { let this = this.upgrade(cx).unwrap(); let this = this.read(cx); @@ -234,7 +232,6 @@ impl ContactsPanel { contact.clone(), current_user_id, *project_ix, - app_state.clone(), theme, is_last_project_for_contact, is_selected, @@ -249,10 +246,8 @@ impl ContactsPanel { entries: Default::default(), match_candidates: Default::default(), filter_editor, - _maintain_contacts: cx - .observe(&app_state.user_store, |this, _, cx| this.update_entries(cx)), - user_store: app_state.user_store.clone(), - app_state, + _maintain_contacts: cx.observe(&user_store, |this, _, cx| this.update_entries(cx)), + user_store, }; this.update_entries(cx); this @@ -351,7 +346,6 @@ impl ContactsPanel { contact: Arc, current_user_id: Option, project_index: usize, - app_state: Arc, theme: &theme::ContactsPanel, is_last_project: bool, is_selected: bool, @@ -456,7 +450,6 @@ impl ContactsPanel { cx.dispatch_global_action(JoinProject { contact: contact.clone(), project_index, - app_state: app_state.clone(), }); } }) @@ -782,7 +775,6 @@ impl ContactsPanel { .dispatch_global_action(JoinProject { contact: contact.clone(), project_index: *project_index, - app_state: self.app_state.clone(), }), _ => {} } @@ -987,19 +979,20 @@ impl PartialEq for ContactEntry { #[cfg(test)] mod tests { use super::*; - use client::{proto, test::FakeServer, ChannelList, Client}; + use client::{proto, test::FakeServer, Client}; use gpui::TestAppContext; use language::LanguageRegistry; + use project::Project; use theme::ThemeRegistry; - use workspace::WorkspaceParams; + use workspace::AppState; #[gpui::test] async fn test_contact_panel(cx: &mut TestAppContext) { let (app_state, server) = init(cx).await; - let workspace_params = cx.update(WorkspaceParams::test); - let workspace = cx.add_view(0, |cx| Workspace::new(&workspace_params, cx)); + let project = Project::test(app_state.fs.clone(), [], cx).await; + let workspace = cx.add_view(0, |cx| Workspace::new(project, cx)); let panel = cx.add_view(0, |cx| { - ContactsPanel::new(app_state.clone(), workspace.downgrade(), cx) + ContactsPanel::new(app_state.user_store.clone(), workspace.downgrade(), cx) }); let get_users_request = server.receive::().await.unwrap(); @@ -1181,13 +1174,6 @@ mod tests { let mut client = Client::new(http_client.clone()); let server = FakeServer::for_client(100, &mut client, &cx).await; let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx)); - let channel_list = - cx.add_model(|cx| ChannelList::new(user_store.clone(), client.clone(), cx)); - - let get_channels = server.receive::().await.unwrap(); - server - .respond(get_channels.receipt(), Default::default()) - .await; ( Arc::new(AppState { @@ -1196,9 +1182,8 @@ mod tests { client, user_store: user_store.clone(), fs, - channel_list, - build_window_options: || unimplemented!(), - build_workspace: |_, _, _| unimplemented!(), + build_window_options: || Default::default(), + initialize_workspace: |_, _, _| {}, }), server, ) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 8f2aa6cea2f21db35f8dff0840d3b70bf2a2b10b..66d101ac3321012d990559f6baaf4440ad6bd1b3 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -707,49 +707,42 @@ mod tests { use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity, PointUtf16}; use serde_json::json; use unindent::Unindent as _; - use workspace::WorkspaceParams; + use workspace::AppState; #[gpui::test] async fn test_diagnostics(cx: &mut TestAppContext) { - let params = cx.update(WorkspaceParams::test); - let project = params.project.clone(); - let workspace = cx.add_view(0, |cx| Workspace::new(¶ms, cx)); - - params + let app_state = cx.update(AppState::test); + app_state .fs .as_fake() .insert_tree( "/test", json!({ "consts.rs": " - const a: i32 = 'a'; - const b: i32 = c; - " + const a: i32 = 'a'; + const b: i32 = c; + " .unindent(), "main.rs": " - fn main() { - let x = vec![]; - let y = vec![]; - a(x); - b(y); - // comment 1 - // comment 2 - c(y); - d(x); - } - " + fn main() { + let x = vec![]; + let y = vec![]; + a(x); + b(y); + // comment 1 + // comment 2 + c(y); + d(x); + } + " .unindent(), }), ) .await; - project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/test", true, cx) - }) - .await - .unwrap(); + let project = Project::test(app_state.fs.clone(), ["/test".as_ref()], cx).await; + let workspace = cx.add_view(0, |cx| Workspace::new(project.clone(), cx)); // Create some diagnostics project.update(cx, |project, cx| { diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 9b160acf646737d63d6fa99eb2ab3aa1ffed41ae..31dc6df357ead5f76c84fb2397f3eccbf8d72d8e 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -862,7 +862,14 @@ impl Editor { ) -> Self { let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx) + Self::new( + EditorMode::SingleLine, + buffer, + None, + field_editor_style, + None, + cx, + ) } pub fn auto_height( @@ -877,6 +884,7 @@ impl Editor { buffer, None, field_editor_style, + None, cx, ) } @@ -887,7 +895,7 @@ impl Editor { cx: &mut ViewContext, ) -> Self { let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - Self::new(EditorMode::Full, buffer, project, None, cx) + Self::new(EditorMode::Full, buffer, project, None, None, cx) } pub fn for_multibuffer( @@ -895,7 +903,7 @@ impl Editor { project: Option>, cx: &mut ViewContext, ) -> Self { - Self::new(EditorMode::Full, buffer, project, None, cx) + Self::new(EditorMode::Full, buffer, project, None, None, cx) } pub fn clone(&self, cx: &mut ViewContext) -> Self { @@ -904,6 +912,7 @@ impl Editor { self.buffer.clone(), self.project.clone(), self.get_field_editor_theme, + Some(self.selections.clone()), cx, ); clone.scroll_position = self.scroll_position; @@ -917,6 +926,7 @@ impl Editor { buffer: ModelHandle, project: Option>, get_field_editor_theme: Option, + selections: Option, cx: &mut ViewContext, ) -> Self { let display_map = cx.add_model(|cx| { @@ -937,7 +947,8 @@ impl Editor { cx.observe(&display_map, Self::on_display_map_changed) .detach(); - let selections = SelectionsCollection::new(display_map.clone(), buffer.clone()); + let selections = selections + .unwrap_or_else(|| SelectionsCollection::new(display_map.clone(), buffer.clone())); let mut this = Self { handle: cx.weak_handle(), @@ -6025,7 +6036,10 @@ mod tests { use std::{cell::RefCell, rc::Rc, time::Instant}; use text::Point; use unindent::Unindent; - use util::test::{marked_text_by, marked_text_ranges, marked_text_ranges_by, sample_text}; + use util::{ + assert_set_eq, + test::{marked_text_by, marked_text_ranges, marked_text_ranges_by, sample_text}, + }; use workspace::{FollowableItem, ItemHandle}; #[gpui::test] @@ -6304,6 +6318,26 @@ mod tests { }); } + #[gpui::test] + fn test_clone_with_selections(cx: &mut gpui::MutableAppContext) { + let (text, selection_ranges) = marked_text_ranges(indoc! {" + The qu[ick brown + fox jum]ps over + the lazy dog + "}); + cx.set_global(Settings::test(cx)); + let buffer = MultiBuffer::build_simple(&text, cx); + + let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); + + let cloned_editor = view.update(cx, |view, cx| { + view.change_selections(None, cx, |s| s.select_ranges(selection_ranges.clone())); + view.clone(cx) + }); + + assert_set_eq!(cloned_editor.selections.ranges(cx), selection_ranges); + } + #[gpui::test] fn test_navigation_history(cx: &mut gpui::MutableAppContext) { cx.set_global(Settings::test(cx)); @@ -8815,7 +8849,7 @@ mod tests { let fs = FakeFs::new(cx.background().clone()); fs.insert_file("/file.rs", Default::default()).await; - let project = Project::test(fs, ["/file.rs"], cx).await; + let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; project.update(cx, |project, _| project.languages().add(Arc::new(language))); let buffer = project .update(cx, |project, cx| project.open_local_buffer("/file.rs", cx)) @@ -8937,7 +8971,7 @@ mod tests { let fs = FakeFs::new(cx.background().clone()); fs.insert_file("/file.rs", text).await; - let project = Project::test(fs, ["/file.rs"], cx).await; + let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; project.update(cx, |project, _| project.languages().add(Arc::new(language))); let buffer = project .update(cx, |project, cx| project.open_local_buffer("/file.rs", cx)) @@ -9765,7 +9799,7 @@ mod tests { } fn build_editor(buffer: ModelHandle, cx: &mut ViewContext) -> Editor { - Editor::new(EditorMode::Full, buffer, None, None, cx) + Editor::new(EditorMode::Full, buffer, None, None, None, cx) } fn assert_selection_ranges( diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index d3d67060f20f32c2c19e945d6d1cd7b99455a1f1..355d1f44337c9c855625ecc0255e51b57ee5db4b 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1517,7 +1517,7 @@ mod tests { cx.set_global(Settings::test(cx)); let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx); let (window_id, editor) = cx.add_window(Default::default(), |cx| { - Editor::new(EditorMode::Full, buffer, None, None, cx) + Editor::new(EditorMode::Full, buffer, None, None, None, cx) }); let element = EditorElement::new( editor.downgrade(), @@ -1539,7 +1539,7 @@ mod tests { cx.set_global(Settings::test(cx)); let buffer = MultiBuffer::build_simple("", cx); let (window_id, editor) = cx.add_window(Default::default(), |cx| { - Editor::new(EditorMode::Full, buffer, None, None, cx) + Editor::new(EditorMode::Full, buffer, None, None, None, cx) }); editor.update(cx, |editor, cx| { diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index c6796159487f1f65ceb3a8c8e8e25a447e3fa2a3..a11cb22adf426b4af01aeea58f5e3304a13a65d4 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -2479,6 +2479,7 @@ impl History { self.undo_stack.pop(); false } else { + self.redo_stack.clear(); let transaction = self.undo_stack.last_mut().unwrap(); transaction.last_edit_at = now; for (buffer_id, transaction_id) in buffer_transactions { @@ -2511,6 +2512,7 @@ impl History { }; if !transaction.buffer_transactions.is_empty() { self.undo_stack.push(transaction); + self.redo_stack.clear(); } } @@ -3935,6 +3937,16 @@ mod tests { buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx)); assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678"); + // Redo stack gets cleared after an edit. + now += 2 * group_interval; + multibuffer.start_transaction_at(now, cx); + multibuffer.edit([(0..0, "X")], cx); + multibuffer.end_transaction_at(now, cx); + assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); + multibuffer.redo(cx); + assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); + multibuffer.undo(cx); + assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678"); multibuffer.undo(cx); assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); }); diff --git a/crates/editor/src/selections_collection.rs b/crates/editor/src/selections_collection.rs index aabfb676ff8be09aaa49352b2be17b2176570c0f..07fa2cd9b501d4e5964ddf776be12bc22a7bb87f 100644 --- a/crates/editor/src/selections_collection.rs +++ b/crates/editor/src/selections_collection.rs @@ -22,6 +22,7 @@ pub struct PendingSelection { pub mode: SelectMode, } +#[derive(Clone)] pub struct SelectionsCollection { display_map: ModelHandle, buffer: ModelHandle, diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index e85147d7e2a9b5a20e86ebd20fcce87f07be073d..f58c733cc7aa8bd44e3643ddef4a78ee9861f2c4 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -258,9 +258,10 @@ mod tests { use super::*; use editor::{Editor, Input}; use serde_json::json; - use std::path::PathBuf; - use workspace::menu::{Confirm, SelectNext}; - use workspace::{Workspace, WorkspaceParams}; + use workspace::{ + menu::{Confirm, SelectNext}, + AppState, Workspace, + }; #[ctor::ctor] fn init_logger() { @@ -271,13 +272,13 @@ mod tests { #[gpui::test] async fn test_matching_paths(cx: &mut gpui::TestAppContext) { - cx.update(|cx| { + let app_state = cx.update(|cx| { super::init(cx); editor::init(cx); + AppState::test(cx) }); - let params = cx.update(WorkspaceParams::test); - params + app_state .fs .as_fake() .insert_tree( @@ -291,16 +292,8 @@ mod tests { ) .await; - let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/root", true, cx) - }) - .await - .unwrap(); - cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) - .await; + let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; + let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); cx.dispatch_action(window_id, Toggle); let finder = cx.read(|cx| { @@ -341,32 +334,26 @@ mod tests { #[gpui::test] async fn test_matching_cancellation(cx: &mut gpui::TestAppContext) { - let params = cx.update(WorkspaceParams::test); - let fs = params.fs.as_fake(); - fs.insert_tree( - "/dir", - json!({ - "hello": "", - "goodbye": "", - "halogen-light": "", - "happiness": "", - "height": "", - "hi": "", - "hiccup": "", - }), - ) - .await; - - let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/dir", true, cx) - }) - .await - .unwrap(); - cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) + let app_state = cx.update(AppState::test); + app_state + .fs + .as_fake() + .insert_tree( + "/dir", + json!({ + "hello": "", + "goodbye": "", + "halogen-light": "", + "happiness": "", + "height": "", + "hi": "", + "hiccup": "", + }), + ) .await; + + let project = Project::test(app_state.fs.clone(), ["/dir".as_ref()], cx).await; + let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); let (_, finder) = cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), cx)); @@ -406,23 +393,20 @@ mod tests { #[gpui::test] async fn test_single_file_worktrees(cx: &mut gpui::TestAppContext) { - let params = cx.update(WorkspaceParams::test); - params + let app_state = cx.update(AppState::test); + app_state .fs .as_fake() .insert_tree("/root", json!({ "the-parent-dir": { "the-file": "" } })) .await; - let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/root/the-parent-dir/the-file", true, cx) - }) - .await - .unwrap(); - cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) - .await; + let project = Project::test( + app_state.fs.clone(), + ["/root/the-parent-dir/the-file".as_ref()], + cx, + ) + .await; + let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); let (_, finder) = cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), cx)); @@ -451,10 +435,12 @@ mod tests { finder.read_with(cx, |f, _| assert_eq!(f.matches.len(), 0)); } - #[gpui::test(retries = 5)] + #[gpui::test] async fn test_multiple_matches_with_same_relative_path(cx: &mut gpui::TestAppContext) { - let params = cx.update(WorkspaceParams::test); - params + cx.foreground().forbid_parking(); + + let app_state = cx.update(AppState::test); + app_state .fs .as_fake() .insert_tree( @@ -466,19 +452,13 @@ mod tests { ) .await; - let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - - workspace - .update(cx, |workspace, cx| { - workspace.open_paths( - vec![PathBuf::from("/root/dir1"), PathBuf::from("/root/dir2")], - cx, - ) - }) - .await; - cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) - .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::new(project, cx)); let (_, finder) = cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), cx)); diff --git a/crates/fsevent/src/fsevent.rs b/crates/fsevent/src/fsevent.rs index 95171f835c7d4adef52dece7b740cdbfb9e0f4cd..4b4d3766bd60f77e1c800eccdbb9fbe5aeb8de6b 100644 --- a/crates/fsevent/src/fsevent.rs +++ b/crates/fsevent/src/fsevent.rs @@ -8,7 +8,7 @@ use std::{ ffi::{c_void, CStr, OsStr}, os::unix::ffi::OsStrExt, path::{Path, PathBuf}, - slice, + ptr, slice, sync::Arc, time::Duration, }; @@ -21,12 +21,28 @@ pub struct Event { } pub struct EventStream { + lifecycle: Arc>, + state: Box, +} + +struct State { + latency: Duration, + paths: cf::CFMutableArrayRef, + callback: Option) -> bool>>, + last_valid_event_id: Option, stream: fs::FSEventStreamRef, - state: Arc>, - callback: Box>, } -type RunCallback = Box) -> bool>; +impl Drop for State { + fn drop(&mut self) { + unsafe { + cf::CFRelease(self.paths); + fs::FSEventStreamStop(self.stream); + fs::FSEventStreamInvalidate(self.stream); + fs::FSEventStreamRelease(self.stream); + } + } +} enum Lifecycle { New, @@ -42,15 +58,6 @@ unsafe impl Send for Lifecycle {} impl EventStream { pub fn new(paths: &[&Path], latency: Duration) -> (Self, Handle) { unsafe { - let callback = Box::new(None); - let stream_context = fs::FSEventStreamContext { - version: 0, - info: callback.as_ref() as *const _ as *mut c_void, - retain: None, - release: None, - copy_description: None, - }; - let cf_paths = cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks); assert!(!cf_paths.is_null()); @@ -69,6 +76,20 @@ impl EventStream { cf::CFRelease(cf_url); } + let mut state = Box::new(State { + latency, + paths: cf_paths, + callback: None, + last_valid_event_id: None, + stream: ptr::null_mut(), + }); + let stream_context = fs::FSEventStreamContext { + version: 0, + info: state.as_ref() as *const _ as *mut c_void, + retain: None, + release: None, + copy_description: None, + }; let stream = fs::FSEventStreamCreate( cf::kCFAllocatorDefault, Self::trampoline, @@ -80,17 +101,15 @@ impl EventStream { | fs::kFSEventStreamCreateFlagNoDefer | fs::kFSEventStreamCreateFlagWatchRoot, ); - cf::CFRelease(cf_paths); - - let state = Arc::new(Mutex::new(Lifecycle::New)); + state.stream = stream; + let lifecycle = Arc::new(Mutex::new(Lifecycle::New)); ( EventStream { - stream, - state: state.clone(), - callback, + lifecycle: lifecycle.clone(), + state, }, - Handle(state), + Handle(lifecycle), ) } } @@ -99,21 +118,24 @@ impl EventStream { where F: FnMut(Vec) -> bool + 'static, { - *self.callback = Some(Box::new(f)); + self.state.callback = Some(Box::new(f)); unsafe { let run_loop = cf::CFRunLoopGetCurrent(); { - let mut state = self.state.lock(); + let mut state = self.lifecycle.lock(); match *state { Lifecycle::New => *state = Lifecycle::Running(run_loop), Lifecycle::Running(_) => unreachable!(), Lifecycle::Stopped => return, } } - fs::FSEventStreamScheduleWithRunLoop(self.stream, run_loop, cf::kCFRunLoopDefaultMode); - fs::FSEventStreamStart(self.stream); + fs::FSEventStreamScheduleWithRunLoop( + self.state.stream, + run_loop, + cf::kCFRunLoopDefaultMode, + ); + fs::FSEventStreamStart(self.state.stream); cf::CFRunLoopRun(); - fs::FSEventStreamRelease(self.stream); } } @@ -129,8 +151,8 @@ impl EventStream { let event_paths = event_paths as *const *const ::std::os::raw::c_char; let e_ptr = event_flags as *mut u32; let i_ptr = event_ids as *mut u64; - let callback_ptr = (info as *mut Option).as_mut().unwrap(); - let callback = if let Some(callback) = callback_ptr.as_mut() { + let state = (info as *mut State).as_mut().unwrap(); + let callback = if let Some(callback) = state.callback.as_mut() { callback } else { return; @@ -139,30 +161,83 @@ impl EventStream { let paths = slice::from_raw_parts(event_paths, num); let flags = slice::from_raw_parts_mut(e_ptr, num); let ids = slice::from_raw_parts_mut(i_ptr, num); + let mut stream_restarted = false; + + // Sometimes FSEvents reports a "dropped" event, an indication that either the kernel + // or our code couldn't keep up with the sheer volume of file-system events that were + // generated. If we observed a valid event before this happens, we'll try to read the + // file-system journal by stopping the current stream and creating a new one starting at + // such event. Otherwise, we'll let invoke the callback with the dropped event, which + // will likely perform a re-scan of one of the root directories. + if flags + .iter() + .copied() + .filter_map(StreamFlags::from_bits) + .any(|flags| { + flags.contains(StreamFlags::USER_DROPPED) + || flags.contains(StreamFlags::KERNEL_DROPPED) + }) + { + if let Some(last_valid_event_id) = state.last_valid_event_id.take() { + fs::FSEventStreamStop(state.stream); + fs::FSEventStreamInvalidate(state.stream); + fs::FSEventStreamRelease(state.stream); + + let stream_context = fs::FSEventStreamContext { + version: 0, + info, + retain: None, + release: None, + copy_description: None, + }; + let stream = fs::FSEventStreamCreate( + cf::kCFAllocatorDefault, + Self::trampoline, + &stream_context, + state.paths, + last_valid_event_id, + state.latency.as_secs_f64(), + fs::kFSEventStreamCreateFlagFileEvents + | fs::kFSEventStreamCreateFlagNoDefer + | fs::kFSEventStreamCreateFlagWatchRoot, + ); + + state.stream = stream; + fs::FSEventStreamScheduleWithRunLoop( + state.stream, + cf::CFRunLoopGetCurrent(), + cf::kCFRunLoopDefaultMode, + ); + fs::FSEventStreamStart(state.stream); + stream_restarted = true; + } + } - let mut events = Vec::with_capacity(num); - for p in 0..num { - let path_c_str = CStr::from_ptr(paths[p]); - let path = PathBuf::from(OsStr::from_bytes(path_c_str.to_bytes())); - if let Some(flag) = StreamFlags::from_bits(flags[p]) { - if flag.contains(StreamFlags::HISTORY_DONE) { - events.clear(); + if !stream_restarted { + let mut events = Vec::with_capacity(num); + for p in 0..num { + if let Some(flag) = StreamFlags::from_bits(flags[p]) { + if !flag.contains(StreamFlags::HISTORY_DONE) { + let path_c_str = CStr::from_ptr(paths[p]); + let path = PathBuf::from(OsStr::from_bytes(path_c_str.to_bytes())); + let event = Event { + event_id: ids[p], + flags: flag, + path, + }; + state.last_valid_event_id = Some(event.event_id); + events.push(event); + } } else { - events.push(Event { - event_id: ids[p], - flags: flag, - path, - }); + debug_assert!(false, "unknown flag set for fs event: {}", flags[p]); } - } else { - debug_assert!(false, "unknown flag set for fs event: {}", flags[p]); } - } - if !events.is_empty() { - if !callback(events) { - fs::FSEventStreamStop(stream_ref); - cf::CFRunLoopStop(cf::CFRunLoopGetCurrent()); + if !events.is_empty() { + if !callback(events) { + fs::FSEventStreamStop(stream_ref); + cf::CFRunLoopStop(cf::CFRunLoopGetCurrent()); + } } } } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 826592daa0bf9fb615640071ca3ac8b3da5ea055..a7ff52e19e1349b5ff4e21523167cea23d2a2f04 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -154,7 +154,6 @@ pub struct Menu<'a> { pub enum MenuItem<'a> { Action { name: &'a str, - keystroke: Option<&'a str>, action: Box, }, Separator, @@ -193,6 +192,20 @@ impl App { cx.borrow_mut().quit(); } })); + foreground_platform.on_will_open_menu(Box::new({ + let cx = app.0.clone(); + move || { + let mut cx = cx.borrow_mut(); + cx.keystroke_matcher.clear_pending(); + } + })); + foreground_platform.on_validate_menu_command(Box::new({ + let cx = app.0.clone(); + move |action| { + let cx = cx.borrow_mut(); + !cx.keystroke_matcher.has_pending_keystrokes() && cx.is_action_available(action) + } + })); foreground_platform.on_menu_command(Box::new({ let cx = app.0.clone(); move |action| { @@ -1070,7 +1083,8 @@ impl MutableAppContext { } pub fn set_menus(&mut self, menus: Vec) { - self.foreground_platform.set_menus(menus); + self.foreground_platform + .set_menus(menus, &self.keystroke_matcher); } fn prompt( @@ -1364,6 +1378,26 @@ impl MutableAppContext { }) } + pub fn is_action_available(&self, action: &dyn Action) -> bool { + let action_type = action.as_any().type_id(); + if let Some(window_id) = self.cx.platform.key_window_id() { + if let Some((presenter, _)) = self.presenters_and_platform_windows.get(&window_id) { + let dispatch_path = presenter.borrow().dispatch_path(&self.cx); + for view_id in dispatch_path { + if let Some(view) = self.views.get(&(window_id, view_id)) { + let view_type = view.as_any().type_id(); + if let Some(actions) = self.actions.get(&view_type) { + if actions.contains_key(&action_type) { + return true; + } + } + } + } + } + } + self.global_actions.contains_key(&action_type) + } + pub fn dispatch_action_at(&mut self, window_id: usize, view_id: usize, action: &dyn Action) { let presenter = self .presenters_and_platform_windows diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index 526a9aea404ff8cafc2202daf4377cd8aa72c86f..3f384b5ea526f6ead4fc9eaaca8b5f5867d65911 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -215,12 +215,12 @@ where self.autoscroll(scroll_max, size.y(), item_height); let start = cmp::min( - ((self.scroll_top() - self.padding_top) / item_height) as usize, + ((self.scroll_top() - self.padding_top) / item_height.max(1.)) as usize, self.item_count, ); let end = cmp::min( self.item_count, - start + (size.y() / item_height).ceil() as usize + 1, + start + (size.y() / item_height.max(1.)).ceil() as usize + 1, ); if (start..end).contains(&sample_item_ix) { diff --git a/crates/gpui/src/keymap.rs b/crates/gpui/src/keymap.rs index c42fbff907061e5e6813da2411477b62a697c28c..bd156ed66149007068b2b8fc4f1b9be58c479390 100644 --- a/crates/gpui/src/keymap.rs +++ b/crates/gpui/src/keymap.rs @@ -123,6 +123,10 @@ impl Matcher { self.pending.clear(); } + pub fn has_pending_keystrokes(&self) -> bool { + !self.pending.is_empty() + } + pub fn push_keystroke( &mut self, keystroke: Keystroke, diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index d851e195be80fa807790bd0e08513b81133e3016..c4b68c0741703530cba643c67515d6e90a06f452 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -14,6 +14,7 @@ use crate::{ rect::{RectF, RectI}, vector::Vector2F, }, + keymap, text_layout::{LineLayout, RunStyle}, Action, ClipboardItem, Menu, Scene, }; @@ -72,7 +73,9 @@ pub(crate) trait ForegroundPlatform { fn run(&self, on_finish_launching: Box ()>); fn on_menu_command(&self, callback: Box); - fn set_menus(&self, menus: Vec); + fn on_validate_menu_command(&self, callback: Box bool>); + fn on_will_open_menu(&self, callback: Box); + fn set_menus(&self, menus: Vec, matcher: &keymap::Matcher); fn prompt_for_paths( &self, options: PathPromptOptions, diff --git a/crates/gpui/src/platform/mac/event.rs b/crates/gpui/src/platform/mac/event.rs index 651805370c0be39bc17d5a0dde379f7c9e825a07..9d07177b16fd322c92973745983396a6c0abf5ea 100644 --- a/crates/gpui/src/platform/mac/event.rs +++ b/crates/gpui/src/platform/mac/event.rs @@ -8,7 +8,35 @@ use cocoa::{ base::{id, nil, YES}, foundation::NSString as _, }; -use std::{ffi::CStr, os::raw::c_char}; +use std::{borrow::Cow, ffi::CStr, os::raw::c_char}; + +pub fn key_to_native(key: &str) -> Cow { + use cocoa::appkit::*; + let code = match key { + "backspace" => 0x7F, + "up" => NSUpArrowFunctionKey, + "down" => NSDownArrowFunctionKey, + "left" => NSLeftArrowFunctionKey, + "right" => NSRightArrowFunctionKey, + "pageup" => NSPageUpFunctionKey, + "pagedown" => NSPageDownFunctionKey, + "delete" => NSDeleteFunctionKey, + "f1" => NSF1FunctionKey, + "f2" => NSF2FunctionKey, + "f3" => NSF3FunctionKey, + "f4" => NSF4FunctionKey, + "f5" => NSF5FunctionKey, + "f6" => NSF6FunctionKey, + "f7" => NSF7FunctionKey, + "f8" => NSF8FunctionKey, + "f9" => NSF9FunctionKey, + "f10" => NSF10FunctionKey, + "f11" => NSF11FunctionKey, + "f12" => NSF12FunctionKey, + _ => return Cow::Borrowed(key), + }; + Cow::Owned(String::from_utf16(&[code]).unwrap()) +} impl Event { pub unsafe fn from_native(native_event: id, window_height: Option) -> Option { diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index fc1b7e59d80d3a9b721a67787bc4c140727fa10b..26cde46c0492eb82138192c962e83f553baeb876 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -1,7 +1,6 @@ -use super::{BoolExt as _, Dispatcher, FontSystem, Window}; +use super::{event::key_to_native, BoolExt as _, Dispatcher, FontSystem, Window}; use crate::{ - executor, - keymap::Keystroke, + executor, keymap, platform::{self, CursorStyle}, Action, ClipboardItem, Event, Menu, MenuItem, }; @@ -90,6 +89,14 @@ unsafe fn build_classes() { sel!(handleGPUIMenuItem:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); + decl.add_method( + sel!(validateMenuItem:), + validate_menu_item as extern "C" fn(&mut Object, Sel, id) -> bool, + ); + decl.add_method( + sel!(menuWillOpen:), + menu_will_open as extern "C" fn(&mut Object, Sel, id), + ); decl.add_method( sel!(application:openURLs:), open_urls as extern "C" fn(&mut Object, Sel, id, id), @@ -108,14 +115,22 @@ pub struct MacForegroundPlatformState { quit: Option>, event: Option bool>>, menu_command: Option>, + validate_menu_command: Option bool>>, + will_open_menu: Option>, open_urls: Option)>>, finish_launching: Option ()>>, menu_actions: Vec>, } impl MacForegroundPlatform { - unsafe fn create_menu_bar(&self, menus: Vec) -> id { + unsafe fn create_menu_bar( + &self, + menus: Vec, + delegate: id, + keystroke_matcher: &keymap::Matcher, + ) -> id { let menu_bar = NSMenu::new(nil).autorelease(); + menu_bar.setDelegate_(delegate); let mut state = self.0.borrow_mut(); state.menu_actions.clear(); @@ -126,6 +141,7 @@ impl MacForegroundPlatform { let menu_name = menu_config.name; menu.setTitle_(ns_string(menu_name)); + menu.setDelegate_(delegate); for item_config in menu_config.items { let item; @@ -134,19 +150,18 @@ impl MacForegroundPlatform { MenuItem::Separator => { item = NSMenuItem::separatorItem(nil); } - MenuItem::Action { - name, - keystroke, - action, - } => { - if let Some(keystroke) = keystroke { - let keystroke = Keystroke::parse(keystroke).unwrap_or_else(|err| { - panic!( - "Invalid keystroke for menu item {}:{} - {:?}", - menu_name, name, err - ) - }); + MenuItem::Action { name, action } => { + let mut keystroke = None; + if let Some(binding) = keystroke_matcher + .bindings_for_action_type(action.as_any().type_id()) + .next() + { + if binding.keystrokes().len() == 1 { + keystroke = binding.keystrokes().first() + } + } + if let Some(keystroke) = keystroke { let mut mask = NSEventModifierFlags::empty(); for (modifier, flag) in &[ (keystroke.cmd, NSEventModifierFlags::NSCommandKeyMask), @@ -162,7 +177,7 @@ impl MacForegroundPlatform { .initWithTitle_action_keyEquivalent_( ns_string(name), selector("handleGPUIMenuItem:"), - ns_string(&keystroke.key), + ns_string(key_to_native(&keystroke.key).as_ref()), ) .autorelease(); item.setKeyEquivalentModifierMask_(mask); @@ -239,10 +254,18 @@ impl platform::ForegroundPlatform for MacForegroundPlatform { self.0.borrow_mut().menu_command = Some(callback); } - fn set_menus(&self, menus: Vec) { + fn on_will_open_menu(&self, callback: Box) { + self.0.borrow_mut().will_open_menu = Some(callback); + } + + fn on_validate_menu_command(&self, callback: Box bool>) { + self.0.borrow_mut().validate_menu_command = Some(callback); + } + + fn set_menus(&self, menus: Vec, keystroke_matcher: &keymap::Matcher) { unsafe { let app: id = msg_send![APP_CLASS, sharedApplication]; - app.setMainMenu_(self.create_menu_bar(menus)); + app.setMainMenu_(self.create_menu_bar(menus, app.delegate(), keystroke_matcher)); } } @@ -740,6 +763,34 @@ extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) { } } +extern "C" fn validate_menu_item(this: &mut Object, _: Sel, item: id) -> bool { + unsafe { + let mut result = false; + let platform = get_foreground_platform(this); + let mut platform = platform.0.borrow_mut(); + if let Some(mut callback) = platform.validate_menu_command.take() { + let tag: NSInteger = msg_send![item, tag]; + let index = tag as usize; + if let Some(action) = platform.menu_actions.get(index) { + result = callback(action.as_ref()); + } + platform.validate_menu_command = Some(callback); + } + result + } +} + +extern "C" fn menu_will_open(this: &mut Object, _: Sel, _: id) { + unsafe { + let platform = get_foreground_platform(this); + let mut platform = platform.0.borrow_mut(); + if let Some(mut callback) = platform.will_open_menu.take() { + callback(); + platform.will_open_menu = Some(callback); + } + } +} + unsafe fn ns_string(string: &str) -> id { NSString::alloc(nil).init_str(string).autorelease() } diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index 8786eff25510bb3aeca85a7c2fb839f6803d4fc5..30ceec335e6dc219bb43f4adefed6a91a9ee0f18 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -1,7 +1,7 @@ use super::{AppVersion, CursorStyle, WindowBounds}; use crate::{ geometry::vector::{vec2f, Vector2F}, - Action, ClipboardItem, + keymap, Action, ClipboardItem, }; use anyhow::{anyhow, Result}; use parking_lot::Mutex; @@ -73,8 +73,9 @@ impl super::ForegroundPlatform for ForegroundPlatform { } fn on_menu_command(&self, _: Box) {} - - fn set_menus(&self, _: Vec) {} + fn on_validate_menu_command(&self, _: Box bool>) {} + fn on_will_open_menu(&self, _: Box) {} + fn set_menus(&self, _: Vec, _: &keymap::Matcher) {} fn prompt_for_paths( &self, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index e6eb2dcf771fd4f8ff8924f60145834e6b2a768c..abcd667293478ab1d13673d657e4e476852c5c38 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -497,7 +497,7 @@ impl Project { #[cfg(any(test, feature = "test-support"))] pub async fn test( fs: Arc, - root_paths: impl IntoIterator>, + root_paths: impl IntoIterator, cx: &mut gpui::TestAppContext, ) -> ModelHandle { let languages = Arc::new(LanguageRegistry::test()); @@ -528,6 +528,14 @@ impl Project { &self.languages } + pub fn client(&self) -> Arc { + self.client.clone() + } + + pub fn user_store(&self) -> ModelHandle { + self.user_store.clone() + } + #[cfg(any(test, feature = "test-support"))] pub fn check_invariants(&self, cx: &AppContext) { if self.is_local() { @@ -5294,7 +5302,7 @@ mod tests { ) .unwrap(); - let project = Project::test(Arc::new(RealFs), [root_link_path], cx).await; + let project = Project::test(Arc::new(RealFs), [root_link_path.as_ref()], cx).await; project.read_with(cx, |project, cx| { let tree = project.worktrees(cx).next().unwrap().read(cx); @@ -5378,7 +5386,7 @@ mod tests { ) .await; - let project = Project::test(fs.clone(), ["/the-root"], cx).await; + let project = Project::test(fs.clone(), ["/the-root".as_ref()], cx).await; project.update(cx, |project, _| { project.languages.add(Arc::new(rust_language)); project.languages.add(Arc::new(json_language)); @@ -5714,7 +5722,7 @@ mod tests { ) .await; - let project = Project::test(fs, ["/dir/a.rs", "/dir/b.rs"], cx).await; + let project = Project::test(fs, ["/dir/a.rs".as_ref(), "/dir/b.rs".as_ref()], cx).await; let buffer_a = project .update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx)) @@ -5825,7 +5833,7 @@ mod tests { ) .await; - let project = Project::test(fs, ["/dir"], cx).await; + let project = Project::test(fs, ["/dir".as_ref()], cx).await; project.update(cx, |project, _| project.languages.add(Arc::new(language))); let worktree_id = project.read_with(cx, |p, cx| p.worktrees(cx).next().unwrap().read(cx).id()); @@ -5947,7 +5955,7 @@ mod tests { let fs = FakeFs::new(cx.background()); fs.insert_tree("/dir", json!({ "a.rs": "" })).await; - let project = Project::test(fs, ["/dir"], cx).await; + let project = Project::test(fs, ["/dir".as_ref()], cx).await; project.update(cx, |project, _| project.languages.add(Arc::new(language))); let buffer = project @@ -6016,7 +6024,7 @@ mod tests { let fs = FakeFs::new(cx.background()); fs.insert_tree("/dir", json!({ "a.rs": text })).await; - let project = Project::test(fs, ["/dir"], cx).await; + let project = Project::test(fs, ["/dir".as_ref()], cx).await; project.update(cx, |project, _| project.languages.add(Arc::new(language))); let buffer = project @@ -6285,7 +6293,7 @@ mod tests { let fs = FakeFs::new(cx.background()); fs.insert_tree("/dir", json!({ "a.rs": text })).await; - let project = Project::test(fs, ["/dir"], cx).await; + let project = Project::test(fs, ["/dir".as_ref()], cx).await; let buffer = project .update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx)) .await @@ -6376,7 +6384,7 @@ mod tests { ) .await; - let project = Project::test(fs, ["/dir"], cx).await; + let project = Project::test(fs, ["/dir".as_ref()], cx).await; project.update(cx, |project, _| project.languages.add(Arc::new(language))); let buffer = project .update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx)) @@ -6530,7 +6538,7 @@ mod tests { ) .await; - let project = Project::test(fs, ["/dir"], cx).await; + let project = Project::test(fs, ["/dir".as_ref()], cx).await; let buffer = project .update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx)) .await @@ -6686,7 +6694,7 @@ mod tests { ) .await; - let project = Project::test(fs, ["/dir/b.rs"], cx).await; + let project = Project::test(fs, ["/dir/b.rs".as_ref()], cx).await; project.update(cx, |project, _| project.languages.add(Arc::new(language))); let buffer = project @@ -6780,7 +6788,7 @@ mod tests { ) .await; - let project = Project::test(fs, ["/dir"], cx).await; + let project = Project::test(fs, ["/dir".as_ref()], cx).await; project.update(cx, |project, _| project.languages.add(Arc::new(language))); let buffer = project .update(cx, |p, cx| p.open_local_buffer("/dir/a.ts", cx)) @@ -6838,7 +6846,7 @@ mod tests { ) .await; - let project = Project::test(fs, ["/dir"], cx).await; + let project = Project::test(fs, ["/dir".as_ref()], cx).await; project.update(cx, |project, _| project.languages.add(Arc::new(language))); let buffer = project .update(cx, |p, cx| p.open_local_buffer("/dir/a.ts", cx)) @@ -6944,7 +6952,7 @@ mod tests { ) .await; - let project = Project::test(fs.clone(), ["/dir"], cx).await; + let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; let buffer = project .update(cx, |p, cx| p.open_local_buffer("/dir/file1", cx)) .await @@ -6973,7 +6981,7 @@ mod tests { ) .await; - let project = Project::test(fs.clone(), ["/dir/file1"], cx).await; + let project = Project::test(fs.clone(), ["/dir/file1".as_ref()], cx).await; let buffer = project .update(cx, |p, cx| p.open_local_buffer("/dir/file1", cx)) .await @@ -6995,7 +7003,7 @@ mod tests { let fs = FakeFs::new(cx.background()); fs.insert_tree("/dir", json!({})).await; - let project = Project::test(fs.clone(), ["/dir"], cx).await; + let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; let buffer = project.update(cx, |project, cx| { project.create_buffer("", None, cx).unwrap() }); @@ -7182,7 +7190,7 @@ mod tests { ) .await; - let project = Project::test(fs.clone(), ["/dir"], cx).await; + let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; // Spawn multiple tasks to open paths, repeating some paths. let (buffer_a_1, buffer_b, buffer_a_2) = project.update(cx, |p, cx| { @@ -7227,7 +7235,7 @@ mod tests { ) .await; - let project = Project::test(fs.clone(), ["/dir"], cx).await; + let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; let buffer1 = project .update(cx, |p, cx| p.open_local_buffer("/dir/file1", cx)) @@ -7359,7 +7367,7 @@ mod tests { }), ) .await; - let project = Project::test(fs.clone(), ["/dir"], cx).await; + let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; let buffer = project .update(cx, |p, cx| p.open_local_buffer("/dir/the-file", cx)) .await @@ -7444,7 +7452,7 @@ mod tests { ) .await; - let project = Project::test(fs.clone(), ["/the-dir"], cx).await; + let project = Project::test(fs.clone(), ["/the-dir".as_ref()], cx).await; let buffer = project .update(cx, |p, cx| p.open_local_buffer("/the-dir/a.rs", cx)) .await @@ -7708,7 +7716,7 @@ mod tests { ) .await; - let project = Project::test(fs.clone(), ["/dir"], cx).await; + let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; project.update(cx, |project, _| project.languages.add(Arc::new(language))); let buffer = project .update(cx, |project, cx| { @@ -7827,7 +7835,7 @@ mod tests { }), ) .await; - let project = Project::test(fs.clone(), ["/dir"], cx).await; + let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; assert_eq!( search(&project, SearchQuery::text("TWO", false, true), cx) .await diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 639d7b44d9c7f1d89d6af6486842a258765ab3d1..443b165a36d42f258afed45bc09ca0f3d9f13a7e 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -913,11 +913,14 @@ mod tests { use project::FakeFs; use serde_json::json; use std::{collections::HashSet, path::Path}; - use workspace::WorkspaceParams; #[gpui::test] async fn test_visible_list(cx: &mut gpui::TestAppContext) { cx.foreground().forbid_parking(); + cx.update(|cx| { + let settings = Settings::test(cx); + cx.set_global(settings); + }); let fs = FakeFs::new(cx.background()); fs.insert_tree( @@ -956,9 +959,8 @@ mod tests { ) .await; - let project = Project::test(fs.clone(), ["/root1", "/root2"], cx).await; - let params = cx.update(WorkspaceParams::test); - let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); + let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; + let (_, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx)); let panel = workspace.update(cx, |_, cx| ProjectPanel::new(project, cx)); assert_eq!( visible_entries_as_strings(&panel, 0..50, cx), @@ -1005,6 +1007,10 @@ mod tests { #[gpui::test(iterations = 30)] async fn test_editing_files(cx: &mut gpui::TestAppContext) { cx.foreground().forbid_parking(); + cx.update(|cx| { + let settings = Settings::test(cx); + cx.set_global(settings); + }); let fs = FakeFs::new(cx.background()); fs.insert_tree( @@ -1043,9 +1049,8 @@ mod tests { ) .await; - let project = Project::test(fs.clone(), ["/root1", "/root2"], cx).await; - let params = cx.update(WorkspaceParams::test); - let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); + let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; + let (_, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx)); let panel = workspace.update(cx, |_, cx| ProjectPanel::new(project, cx)); select_path(&panel, "root1", cx); diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index f30370a0c040209815c344755be6f42072712bfd..20da49b1dfdc93d846f98b8a2fa2a33980b6c87d 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -295,7 +295,7 @@ mod tests { let fs = FakeFs::new(cx.background()); fs.insert_tree("/dir", json!({ "test.rs": "" })).await; - let project = Project::test(fs.clone(), ["/dir"], cx).await; + let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; project.update(cx, |project, _| project.languages().add(Arc::new(language))); let _buffer = project diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 636c055f1cd1404b89d49e77efbfe66c82a92429..97c2d3201e7a02df7871daec52eae08bb5362681 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -848,7 +848,7 @@ mod tests { }), ) .await; - let project = Project::test(fs.clone(), ["/dir"], 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_view = cx.add_view(Default::default(), |cx| { ProjectSearchView::new(search.clone(), cx) diff --git a/crates/text/src/tests.rs b/crates/text/src/tests.rs index 7994d5b8f1a1ce3f6daed3df54a399f6ef2a2be2..e66837f21b295a14c5011bc4921f5d43717b386e 100644 --- a/crates/text/src/tests.rs +++ b/crates/text/src/tests.rs @@ -529,6 +529,16 @@ fn test_history() { assert!(buffer.end_transaction_at(now).is_none()); buffer.undo(); assert_eq!(buffer.text(), "12cde6"); + + // Redo stack gets cleared after performing an edit. + buffer.edit([(0..0, "X")]); + assert_eq!(buffer.text(), "X12cde6"); + buffer.redo(); + assert_eq!(buffer.text(), "X12cde6"); + buffer.undo(); + assert_eq!(buffer.text(), "12cde6"); + buffer.undo(); + assert_eq!(buffer.text(), "123456"); } #[test] diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 7bf8ee208fcece78063e4c0fd226401a9d7e2cdb..8d37ad0c8b0c7dca7c12ef03740d763fe0554823 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -216,6 +216,7 @@ impl History { self.undo_stack.pop(); None } else { + self.redo_stack.clear(); let entry = self.undo_stack.last_mut().unwrap(); entry.last_edit_at = now; Some(entry) @@ -276,6 +277,7 @@ impl History { last_edit_at: now, suppress_grouping: false, }); + self.redo_stack.clear(); } fn push_undo(&mut self, op_id: clock::Local) { diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 718268788c39f17f32ca993ca5e9ce2f2b9fb4ce..9f445c633af0ff2c8e9715ab5fe107790f240db3 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -7,7 +7,7 @@ use picker::{Picker, PickerDelegate}; use settings::Settings; use std::sync::Arc; use theme::{Theme, ThemeRegistry}; -use workspace::Workspace; +use workspace::{AppState, Workspace}; pub struct ThemeSelector { registry: Arc, @@ -21,10 +21,14 @@ pub struct ThemeSelector { actions!(theme_selector, [Toggle, Reload]); -pub fn init(cx: &mut MutableAppContext) { - cx.add_action(ThemeSelector::toggle); - cx.add_action(ThemeSelector::reload); +pub fn init(app_state: Arc, cx: &mut MutableAppContext) { Picker::::init(cx); + cx.add_action({ + let theme_registry = app_state.themes.clone(); + move |workspace, _: &Toggle, cx| { + ThemeSelector::toggle(workspace, theme_registry.clone(), cx) + } + }); } pub enum Event { @@ -64,8 +68,11 @@ impl ThemeSelector { this } - fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext) { - let themes = workspace.themes(); + fn toggle( + workspace: &mut Workspace, + themes: Arc, + cx: &mut ViewContext, + ) { workspace.toggle_modal(cx, |_, cx| { let this = cx.add_view(|cx| Self::new(themes, cx)); cx.subscribe(&this, Self::on_event).detach(); @@ -73,9 +80,9 @@ impl ThemeSelector { }); } - fn reload(workspace: &mut Workspace, _: &Reload, cx: &mut ViewContext) { + #[cfg(debug_assertions)] + pub fn reload(themes: Arc, cx: &mut MutableAppContext) { let current_theme_name = cx.global::().theme.name.clone(); - let themes = workspace.themes(); themes.clear(); match themes.get(¤t_theme_name) { Ok(theme) => { diff --git a/crates/vim/src/vim_test_context.rs b/crates/vim/src/vim_test_context.rs index 4122c46059ef7b6887eb1a7e782b042884b3b583..f9080e554cb23638b44b5401d0c1ca762b078900 100644 --- a/crates/vim/src/vim_test_context.rs +++ b/crates/vim/src/vim_test_context.rs @@ -7,11 +7,12 @@ use editor::{display_map::ToDisplayPoint, Autoscroll}; use gpui::{json::json, keymap::Keystroke, ViewHandle}; use indoc::indoc; use language::Selection; +use project::Project; use util::{ set_eq, test::{marked_text, marked_text_ranges_by, SetEqError}, }; -use workspace::{WorkspaceHandle, WorkspaceParams}; +use workspace::{AppState, WorkspaceHandle}; use crate::{state::Operator, *}; @@ -30,7 +31,8 @@ impl<'a> VimTestContext<'a> { settings::KeymapFileContent::load("keymaps/vim.json", cx).unwrap(); }); - let params = cx.update(WorkspaceParams::test); + let params = cx.update(AppState::test); + let project = Project::test(params.fs.clone(), [], cx).await; cx.update(|cx| { cx.update_global(|settings: &mut Settings, _| { @@ -44,9 +46,8 @@ impl<'a> VimTestContext<'a> { .insert_tree("/root", json!({ "dir": { "test.txt": "" } })) .await; - let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project + let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx)); + project .update(cx, |project, cx| { project.find_or_create_local_worktree("/root", true, cx) }) diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index e963ca7e02ab4d1f2d8179fcb37658f371926f8f..97bb8a2bc066c7800dc2bd956fb02e5876490b45 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -920,7 +920,7 @@ impl NavHistory { #[cfg(test)] mod tests { use super::*; - use crate::WorkspaceParams; + use crate::AppState; use gpui::{ModelHandle, TestAppContext, ViewContext}; use project::Project; use std::sync::atomic::AtomicUsize; @@ -929,8 +929,9 @@ mod tests { async fn test_close_items(cx: &mut TestAppContext) { cx.foreground().forbid_parking(); - let params = cx.update(WorkspaceParams::test); - let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); + let app_state = cx.update(AppState::test); + let project = Project::test(app_state.fs.clone(), None, cx).await; + let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); let item1 = cx.add_view(window_id, |_| { let mut item = TestItem::new(); item.is_dirty = true; @@ -1019,8 +1020,9 @@ mod tests { async fn test_prompting_only_on_last_item_for_entry(cx: &mut TestAppContext) { cx.foreground().forbid_parking(); - let params = cx.update(WorkspaceParams::test); - let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); + let app_state = cx.update(AppState::test); + let project = Project::test(app_state.fs.clone(), [], cx).await; + let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); let item = cx.add_view(window_id, |_| { let mut item = TestItem::new(); item.is_dirty = true; diff --git a/crates/workspace/src/waiting_room.rs b/crates/workspace/src/waiting_room.rs index fef7bf2e4332ebfe94c96bafd6fefd3706cd7f13..3720d9ec43aca0ef25aa96b8ca4edc232480ee18 100644 --- a/crates/workspace/src/waiting_room.rs +++ b/crates/workspace/src/waiting_room.rs @@ -1,6 +1,6 @@ use crate::{ sidebar::{Side, ToggleSidebarItem}, - AppState, ToggleFollow, + AppState, ToggleFollow, Workspace, }; use anyhow::Result; use client::{proto, Client, Contact}; @@ -77,86 +77,87 @@ impl WaitingRoom { ) -> Self { let project_id = contact.projects[project_index].id; let client = app_state.client.clone(); - let _join_task = cx.spawn_weak({ - let contact = contact.clone(); - |this, mut cx| async move { - let project = Project::remote( - project_id, - app_state.client.clone(), - app_state.user_store.clone(), - app_state.languages.clone(), - app_state.fs.clone(), - &mut cx, - ) - .await; + let _join_task = + cx.spawn_weak({ + let contact = contact.clone(); + |this, mut cx| async move { + let project = Project::remote( + project_id, + app_state.client.clone(), + app_state.user_store.clone(), + app_state.languages.clone(), + app_state.fs.clone(), + &mut cx, + ) + .await; - if let Some(this) = this.upgrade(&cx) { - this.update(&mut cx, |this, cx| { - this.waiting = false; - match project { - Ok(project) => { - cx.replace_root_view(|cx| { - let mut workspace = (app_state.build_workspace)( - project.clone(), - &app_state, - cx, - ); - workspace.toggle_sidebar_item( - &ToggleSidebarItem { - side: Side::Left, - item_index: 0, - }, - cx, - ); - if let Some((host_peer_id, _)) = project - .read(cx) - .collaborators() - .iter() - .find(|(_, collaborator)| collaborator.replica_id == 0) - { - if let Some(follow) = workspace - .toggle_follow(&ToggleFollow(*host_peer_id), cx) + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, cx| { + this.waiting = false; + match project { + Ok(project) => { + cx.replace_root_view(|cx| { + let mut workspace = Workspace::new(project, cx); + (app_state.initialize_workspace)( + &mut workspace, + &app_state, + cx, + ); + workspace.toggle_sidebar_item( + &ToggleSidebarItem { + side: Side::Left, + item_index: 0, + }, + cx, + ); + if let Some((host_peer_id, _)) = + workspace.project.read(cx).collaborators().iter().find( + |(_, collaborator)| collaborator.replica_id == 0, + ) { - follow.detach_and_log_err(cx); + if let Some(follow) = workspace + .toggle_follow(&ToggleFollow(*host_peer_id), cx) + { + follow.detach_and_log_err(cx); + } } - } - workspace - }); - } - Err(error @ _) => { - let login = &contact.user.github_login; - let message = match error { - project::JoinProjectError::HostDeclined => { - format!("@{} declined your request.", login) - } - project::JoinProjectError::HostClosedProject => { - format!( - "@{} closed their copy of {}.", - login, - humanize_list( - &contact.projects[project_index] - .worktree_root_names + workspace + }); + } + Err(error @ _) => { + let login = &contact.user.github_login; + let message = match error { + project::JoinProjectError::HostDeclined => { + format!("@{} declined your request.", login) + } + project::JoinProjectError::HostClosedProject => { + format!( + "@{} closed their copy of {}.", + login, + humanize_list( + &contact.projects[project_index] + .worktree_root_names + ) ) - ) - } - project::JoinProjectError::HostWentOffline => { - format!("@{} went offline.", login) - } - project::JoinProjectError::Other(error) => { - log::error!("error joining project: {}", error); - "An error occurred.".to_string() - } - }; - this.message = message; - cx.notify(); + } + project::JoinProjectError::HostWentOffline => { + format!("@{} went offline.", login) + } + project::JoinProjectError::Other(error) => { + log::error!("error joining project: {}", error); + "An error occurred.".to_string() + } + }; + this.message = message; + cx.notify(); + } } - } - }) - } + }) + } - Ok(()) - } - }); + Ok(()) + } + }); Self { project_id, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index b6cb95292acfd9a8479ef9c5126a37c12adba6da..d12c8a2eea7d32bb6a8c683600e7ad387b5a5569 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -9,8 +9,7 @@ mod waiting_room; use anyhow::{anyhow, Context, Result}; use client::{ - proto, Authenticate, ChannelList, Client, Contact, PeerId, Subscription, TypedEnvelope, User, - UserStore, + proto, Authenticate, Client, Contact, PeerId, Subscription, TypedEnvelope, User, UserStore, }; use clock::ReplicaId; use collections::{hash_map, HashMap, HashSet}; @@ -75,6 +74,8 @@ type FollowableItemBuilders = HashMap< actions!( workspace, [ + Open, + OpenNew, Unfollow, Save, ActivatePreviousPane, @@ -83,16 +84,9 @@ actions!( ] ); -#[derive(Clone)] -pub struct Open(pub Arc); - -#[derive(Clone)] -pub struct OpenNew(pub Arc); - #[derive(Clone)] pub struct OpenPaths { pub paths: Vec, - pub app_state: Arc, } #[derive(Clone)] @@ -102,31 +96,37 @@ pub struct ToggleFollow(pub PeerId); pub struct JoinProject { pub contact: Arc, pub project_index: usize, - pub app_state: Arc, } -impl_internal_actions!( - workspace, - [Open, OpenNew, OpenPaths, ToggleFollow, JoinProject] -); +impl_internal_actions!(workspace, [OpenPaths, ToggleFollow, JoinProject]); -pub fn init(client: &Arc, cx: &mut MutableAppContext) { +pub fn init(app_state: Arc, cx: &mut MutableAppContext) { pane::init(cx); cx.add_global_action(open); - cx.add_global_action(move |action: &OpenPaths, cx: &mut MutableAppContext| { - open_paths(&action.paths, &action.app_state, cx).detach(); + cx.add_global_action({ + let app_state = Arc::downgrade(&app_state); + move |action: &OpenPaths, cx: &mut MutableAppContext| { + if let Some(app_state) = app_state.upgrade() { + open_paths(&action.paths, &app_state, cx).detach(); + } + } }); - cx.add_global_action(move |action: &OpenNew, cx: &mut MutableAppContext| { - open_new(&action.0, cx) + cx.add_global_action({ + let app_state = Arc::downgrade(&app_state); + move |_: &OpenNew, cx: &mut MutableAppContext| { + if let Some(app_state) = app_state.upgrade() { + open_new(&app_state, cx) + } + } }); - cx.add_global_action(move |action: &JoinProject, cx: &mut MutableAppContext| { - join_project( - action.contact.clone(), - action.project_index, - &action.app_state, - cx, - ); + cx.add_global_action({ + let app_state = Arc::downgrade(&app_state); + move |action: &JoinProject, cx: &mut MutableAppContext| { + if let Some(app_state) = app_state.upgrade() { + join_project(action.contact.clone(), action.project_index, &app_state, cx); + } + } }); cx.add_async_action(Workspace::toggle_follow); @@ -151,6 +151,7 @@ pub fn init(client: &Arc, cx: &mut MutableAppContext) { workspace.activate_next_pane(cx) }); + let client = &app_state.client; client.add_view_request_handler(Workspace::handle_follow); client.add_view_message_handler(Workspace::handle_unfollow); client.add_view_message_handler(Workspace::handle_update_followers); @@ -188,10 +189,8 @@ pub struct AppState { pub client: Arc, pub user_store: ModelHandle, pub fs: Arc, - pub channel_list: ModelHandle, pub build_window_options: fn() -> WindowOptions<'static>, - pub build_workspace: - fn(ModelHandle, &Arc, &mut ViewContext) -> Workspace, + pub initialize_workspace: fn(&mut Workspace, &Arc, &mut ViewContext), } pub trait Item: View { @@ -636,20 +635,9 @@ impl Into for &dyn NotificationHandle { } } -#[derive(Clone)] -pub struct WorkspaceParams { - pub project: ModelHandle, - pub client: Arc, - pub fs: Arc, - pub languages: Arc, - pub themes: Arc, - pub user_store: ModelHandle, - pub channel_list: ModelHandle, -} - -impl WorkspaceParams { +impl AppState { #[cfg(any(test, feature = "test-support"))] - pub fn test(cx: &mut MutableAppContext) -> Self { + pub fn test(cx: &mut MutableAppContext) -> Arc { let settings = Settings::test(cx); cx.set_global(settings); @@ -658,42 +646,16 @@ impl WorkspaceParams { let http_client = client::test::FakeHttpClient::with_404_response(); let client = Client::new(http_client.clone()); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx)); - let project = Project::local( - client.clone(), - user_store.clone(), - languages.clone(), - fs.clone(), - cx, - ); - Self { - project, - channel_list: cx - .add_model(|cx| ChannelList::new(user_store.clone(), client.clone(), cx)), + let themes = ThemeRegistry::new((), cx.font_cache().clone()); + Arc::new(Self { client, - themes: ThemeRegistry::new((), cx.font_cache().clone()), + themes, fs, languages, user_store, - } - } - - #[cfg(any(test, feature = "test-support"))] - pub fn local(app_state: &Arc, cx: &mut MutableAppContext) -> Self { - Self { - project: Project::local( - app_state.client.clone(), - app_state.user_store.clone(), - app_state.languages.clone(), - app_state.fs.clone(), - cx, - ), - client: app_state.client.clone(), - fs: app_state.fs.clone(), - themes: app_state.themes.clone(), - languages: app_state.languages.clone(), - user_store: app_state.user_store.clone(), - channel_list: app_state.channel_list.clone(), - } + initialize_workspace: |_, _, _| {}, + build_window_options: || Default::default(), + }) } } @@ -708,7 +670,6 @@ pub struct Workspace { user_store: ModelHandle, remote_entity_subscription: Option, fs: Arc, - themes: Arc, modal: Option, center: PaneGroup, left_sidebar: ViewHandle, @@ -744,8 +705,8 @@ enum FollowerItem { } impl Workspace { - pub fn new(params: &WorkspaceParams, cx: &mut ViewContext) -> Self { - cx.observe(¶ms.project, |_, project, cx| { + pub fn new(project: ModelHandle, cx: &mut ViewContext) -> Self { + cx.observe(&project, |_, project, cx| { if project.read(cx).is_read_only() { cx.blur(); } @@ -753,7 +714,7 @@ impl Workspace { }) .detach(); - cx.subscribe(¶ms.project, move |this, project, event, cx| { + cx.subscribe(&project, move |this, project, event, cx| { match event { project::Event::RemoteIdChanged(remote_id) => { this.project_remote_id_changed(*remote_id, cx); @@ -785,8 +746,11 @@ impl Workspace { cx.focus(&pane); cx.emit(Event::PaneAdded(pane.clone())); - let mut current_user = params.user_store.read(cx).watch_current_user().clone(); - let mut connection_status = params.client.status().clone(); + let fs = project.read(cx).fs().clone(); + let user_store = project.read(cx).user_store(); + let client = project.read(cx).client(); + let mut current_user = user_store.read(cx).watch_current_user().clone(); + let mut connection_status = client.status().clone(); let _observe_current_user = cx.spawn_weak(|this, mut cx| async move { current_user.recv().await; connection_status.recv().await; @@ -826,14 +790,13 @@ impl Workspace { active_pane: pane.clone(), status_bar, notifications: Default::default(), - client: params.client.clone(), + client, remote_entity_subscription: None, - user_store: params.user_store.clone(), - fs: params.fs.clone(), - themes: params.themes.clone(), + user_store, + fs, left_sidebar, right_sidebar, - project: params.project.clone(), + project, leader_state: Default::default(), follower_states_by_leader: Default::default(), last_leaders_by_pane: Default::default(), @@ -867,10 +830,6 @@ impl Workspace { &self.project } - pub fn themes(&self) -> Arc { - self.themes.clone() - } - pub fn worktrees<'a>( &self, cx: &'a AppContext, @@ -2203,8 +2162,7 @@ impl std::fmt::Debug for OpenPaths { } } -fn open(action: &Open, cx: &mut MutableAppContext) { - let app_state = action.0.clone(); +fn open(_: &Open, cx: &mut MutableAppContext) { let mut paths = cx.prompt_for_paths(PathPromptOptions { files: true, directories: true, @@ -2212,7 +2170,7 @@ fn open(action: &Open, cx: &mut MutableAppContext) { }); cx.spawn(|mut cx| async move { if let Some(paths) = paths.recv().await.flatten() { - cx.update(|cx| cx.dispatch_global_action(OpenPaths { paths, app_state })); + cx.update(|cx| cx.dispatch_global_action(OpenPaths { paths })); } }) .detach(); @@ -2260,14 +2218,17 @@ pub fn open_paths( .contains(&false); cx.add_window((app_state.build_window_options)(), |cx| { - let project = Project::local( - app_state.client.clone(), - app_state.user_store.clone(), - app_state.languages.clone(), - app_state.fs.clone(), + let mut workspace = Workspace::new( + Project::local( + app_state.client.clone(), + app_state.user_store.clone(), + app_state.languages.clone(), + app_state.fs.clone(), + cx, + ), cx, ); - let mut workspace = (app_state.build_workspace)(project, &app_state, cx); + (app_state.initialize_workspace)(&mut workspace, &app_state, cx); if contains_directory { workspace.toggle_sidebar_item( &ToggleSidebarItem { @@ -2313,14 +2274,18 @@ pub fn join_project( fn open_new(app_state: &Arc, cx: &mut MutableAppContext) { let (window_id, workspace) = cx.add_window((app_state.build_window_options)(), |cx| { - let project = Project::local( - app_state.client.clone(), - app_state.user_store.clone(), - app_state.languages.clone(), - app_state.fs.clone(), + let mut workspace = Workspace::new( + Project::local( + app_state.client.clone(), + app_state.user_store.clone(), + app_state.languages.clone(), + app_state.fs.clone(), + cx, + ), cx, ); - (app_state.build_workspace)(project, &app_state, cx) + (app_state.initialize_workspace)(&mut workspace, app_state, cx); + workspace }); - cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew(app_state.clone())); + cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew); } diff --git a/crates/zed/build.rs b/crates/zed/build.rs index 46d9d41c858a78ebedae0a8cf16c89faa9b00bf0..c42fa6bda833cf4143c429b5f9721614ca114877 100644 --- a/crates/zed/build.rs +++ b/crates/zed/build.rs @@ -1,3 +1,31 @@ +use std::process::Command; + fn main() { println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.14"); + + let output = Command::new("npm") + .current_dir("../../styles") + .args(["ci"]) + .output() + .expect("failed to run npm"); + if !output.status.success() { + panic!( + "failed to install theme dependencies {}", + String::from_utf8_lossy(&output.stderr) + ); + } + + let output = Command::new("npm") + .current_dir("../../styles") + .args(["run", "build-themes"]) + .output() + .expect("failed to run npm"); + if !output.status.success() { + panic!( + "build-themes script failed {}", + String::from_utf8_lossy(&output.stderr) + ); + } + + println!("cargo:rerun-if-changed=../../styles"); } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index a4f85ab9bc7467b108092c01db7a26d5920098d9..8231d2ac3ff947ac19704c3cb9008645aab18daa 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -12,7 +12,7 @@ use cli::{ use client::{ self, http::{self, HttpClient}, - ChannelList, UserStore, ZED_SECRET_CLIENT_TOKEN, + UserStore, ZED_SECRET_CLIENT_TOKEN, }; use fs::OpenOptions; use futures::{ @@ -40,9 +40,9 @@ use theme::{ThemeRegistry, DEFAULT_THEME_NAME}; use util::{ResultExt, TryFutureExt}; use workspace::{self, AppState, OpenNew, OpenPaths}; use zed::{ - self, build_window_options, build_workspace, + self, build_window_options, fs::RealFs, - languages, menus, + initialize_workspace, languages, menus, settings_file::{settings_from_files, watch_keymap_file, WatchedJsonFile}, }; @@ -133,15 +133,12 @@ fn main() { let client = client::Client::new(http.clone()); let mut languages = languages::build_language_registry(login_shell_env_loaded); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx)); - let channel_list = - cx.add_model(|cx| ChannelList::new(user_store.clone(), client.clone(), cx)); auto_update::init(http, client::ZED_SERVER_URL.clone(), cx); project::Project::init(&client); client::Channel::init(&client); client::init(client.clone(), cx); command_palette::init(cx); - workspace::init(&client, cx); editor::init(cx); go_to_line::init(cx); file_finder::init(cx); @@ -162,6 +159,8 @@ fn main() { cx.font_cache().clone(), ); + cx.spawn(|cx| watch_themes(fs.clone(), themes.clone(), cx)) + .detach(); cx.spawn(|cx| watch_keymap_file(keymap_file, cx)).detach(); let settings = cx.background().block(settings_rx.next()).unwrap(); @@ -190,33 +189,33 @@ fn main() { let app_state = Arc::new(AppState { languages, themes, - channel_list, client: client.clone(), user_store, fs, build_window_options, - build_workspace, + initialize_workspace, }); + workspace::init(app_state.clone(), cx); journal::init(app_state.clone(), cx); - theme_selector::init(cx); + theme_selector::init(app_state.clone(), cx); zed::init(&app_state, cx); - cx.set_menus(menus::menus(&app_state.clone())); + cx.set_menus(menus::menus()); if stdout_is_a_pty() { cx.platform().activate(true); let paths = collect_path_args(); if paths.is_empty() { - cx.dispatch_global_action(OpenNew(app_state.clone())); + cx.dispatch_global_action(OpenNew); } else { - cx.dispatch_global_action(OpenPaths { paths, app_state }); + cx.dispatch_global_action(OpenPaths { paths }); } } else { if let Ok(Some(connection)) = cli_connections_rx.try_next() { cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx)) .detach(); } else { - cx.dispatch_global_action(OpenNew(app_state.clone())); + cx.dispatch_global_action(OpenNew); } cx.spawn(|cx| async move { while let Some(connection) = cli_connections_rx.next().await { @@ -440,6 +439,43 @@ fn load_embedded_fonts(app: &App) { .unwrap(); } +#[cfg(debug_assertions)] +async fn watch_themes( + fs: Arc, + themes: Arc, + mut cx: AsyncAppContext, +) -> Option<()> { + let mut events = fs + .watch("styles/src".as_ref(), Duration::from_millis(100)) + .await; + while let Some(_) = events.next().await { + let output = Command::new("npm") + .current_dir("styles") + .args(["run", "build-themes"]) + .output() + .await + .log_err()?; + if output.status.success() { + cx.update(|cx| theme_selector::ThemeSelector::reload(themes.clone(), cx)) + } else { + eprintln!( + "build-themes script failed {}", + String::from_utf8_lossy(&output.stderr) + ); + } + } + Some(()) +} + +#[cfg(not(debug_assertions))] +async fn watch_themes( + _fs: Arc, + _themes: Arc, + _cx: AsyncAppContext, +) -> Option<()> { + None +} + fn load_config_files( app: &App, fs: Arc, diff --git a/crates/zed/src/menus.rs b/crates/zed/src/menus.rs index 3f19dcbdac04e4153ccb916a13e0a087cb1c5be8..c5ea7b73912b2dac02239cbc41c869c190c3b4ae 100644 --- a/crates/zed/src/menus.rs +++ b/crates/zed/src/menus.rs @@ -1,33 +1,27 @@ -use crate::AppState; use gpui::{Menu, MenuItem}; -use std::sync::Arc; #[cfg(target_os = "macos")] -pub fn menus(state: &Arc) -> Vec> { +pub fn menus() -> Vec> { vec![ Menu { name: "Zed", items: vec![ MenuItem::Action { name: "About Zed…", - keystroke: None, action: Box::new(super::About), }, MenuItem::Action { name: "Check for Updates", - keystroke: None, action: Box::new(auto_update::Check), }, MenuItem::Separator, MenuItem::Action { name: "Install CLI", - keystroke: None, action: Box::new(super::InstallCommandLineInterface), }, MenuItem::Separator, MenuItem::Action { name: "Quit", - keystroke: Some("cmd-q"), action: Box::new(super::Quit), }, ], @@ -37,14 +31,20 @@ pub fn menus(state: &Arc) -> Vec> { items: vec![ MenuItem::Action { name: "New", - keystroke: Some("cmd-n"), - action: Box::new(workspace::OpenNew(state.clone())), + action: Box::new(workspace::OpenNew), }, MenuItem::Separator, MenuItem::Action { name: "Open…", - keystroke: Some("cmd-o"), - action: Box::new(workspace::Open(state.clone())), + action: Box::new(workspace::Open), + }, + MenuItem::Action { + name: "Save", + action: Box::new(workspace::Save), + }, + MenuItem::Action { + name: "Close Editor", + action: Box::new(workspace::CloseActiveItem), }, ], }, @@ -53,30 +53,160 @@ pub fn menus(state: &Arc) -> Vec> { items: vec![ MenuItem::Action { name: "Undo", - keystroke: Some("cmd-z"), action: Box::new(editor::Undo), }, MenuItem::Action { name: "Redo", - keystroke: Some("cmd-Z"), action: Box::new(editor::Redo), }, MenuItem::Separator, MenuItem::Action { name: "Cut", - keystroke: Some("cmd-x"), action: Box::new(editor::Cut), }, MenuItem::Action { name: "Copy", - keystroke: Some("cmd-c"), action: Box::new(editor::Copy), }, MenuItem::Action { name: "Paste", - keystroke: Some("cmd-v"), action: Box::new(editor::Paste), }, + MenuItem::Separator, + MenuItem::Action { + name: "Find", + action: Box::new(search::buffer_search::Deploy { focus: true }), + }, + MenuItem::Action { + name: "Find In Project", + action: Box::new(search::project_search::Deploy), + }, + MenuItem::Separator, + MenuItem::Action { + name: "Toggle Line Comment", + action: Box::new(editor::ToggleComments), + }, + ], + }, + Menu { + name: "Selection", + items: vec![ + MenuItem::Action { + name: "Select All", + action: Box::new(editor::SelectAll), + }, + MenuItem::Action { + name: "Expand Selection", + action: Box::new(editor::SelectLargerSyntaxNode), + }, + MenuItem::Action { + name: "Shrink Selection", + action: Box::new(editor::SelectSmallerSyntaxNode), + }, + MenuItem::Separator, + MenuItem::Action { + name: "Add Cursor Above", + action: Box::new(editor::AddSelectionAbove), + }, + MenuItem::Action { + name: "Add Cursor Below", + action: Box::new(editor::AddSelectionBelow), + }, + MenuItem::Action { + name: "Select Next Occurrence", + action: Box::new(editor::SelectNext { + replace_newest: false, + }), + }, + MenuItem::Separator, + MenuItem::Action { + name: "Move Line Up", + action: Box::new(editor::MoveLineUp), + }, + MenuItem::Action { + name: "Move Line Down", + action: Box::new(editor::MoveLineDown), + }, + MenuItem::Action { + name: "Duplicate Selection", + action: Box::new(editor::DuplicateLine), + }, + ], + }, + Menu { + name: "View", + items: vec![ + MenuItem::Action { + name: "Zoom In", + action: Box::new(super::IncreaseBufferFontSize), + }, + MenuItem::Action { + name: "Zoom Out", + action: Box::new(super::DecreaseBufferFontSize), + }, + MenuItem::Separator, + MenuItem::Action { + name: "Project Browser", + action: Box::new(workspace::sidebar::ToggleSidebarItemFocus { + side: workspace::sidebar::Side::Left, + item_index: 0, + }), + }, + MenuItem::Action { + name: "Command Palette", + action: Box::new(command_palette::Toggle), + }, + MenuItem::Action { + name: "Diagnostics", + action: Box::new(diagnostics::Deploy), + }, + ], + }, + Menu { + name: "Go", + items: vec![ + MenuItem::Action { + name: "Back", + action: Box::new(workspace::GoBack { pane: None }), + }, + MenuItem::Action { + name: "Forward", + action: Box::new(workspace::GoForward { pane: None }), + }, + MenuItem::Separator, + MenuItem::Action { + name: "Go to File", + action: Box::new(file_finder::Toggle), + }, + MenuItem::Action { + name: "Go to Symbol in Project", + action: Box::new(project_symbols::Toggle), + }, + MenuItem::Action { + name: "Go to Symbol in Editor", + action: Box::new(outline::Toggle), + }, + MenuItem::Action { + name: "Go to Definition", + action: Box::new(editor::GoToDefinition), + }, + MenuItem::Action { + name: "Go to References", + action: Box::new(editor::FindAllReferences), + }, + MenuItem::Action { + name: "Go to Line/Column", + action: Box::new(go_to_line::Toggle), + }, + MenuItem::Separator, + MenuItem::Action { + name: "Next Problem", + action: Box::new(editor::GoToNextDiagnostic), + }, + MenuItem::Action { + name: "Previous Problem", + action: Box::new(editor::GoToPrevDiagnostic), + }, ], }, ] diff --git a/crates/zed/src/test.rs b/crates/zed/src/test.rs index d4f24297e4d2dc26b0ab6f432acf20e4f64aafa7..67622db83f94539ff40ec728843799a51628e8aa 100644 --- a/crates/zed/src/test.rs +++ b/crates/zed/src/test.rs @@ -1,13 +1,3 @@ -use crate::{build_window_options, build_workspace, AppState}; -use assets::Assets; -use client::{test::FakeHttpClient, ChannelList, Client, UserStore}; -use gpui::MutableAppContext; -use language::LanguageRegistry; -use project::fs::FakeFs; -use settings::Settings; -use std::sync::Arc; -use theme::ThemeRegistry; - #[cfg(test)] #[ctor::ctor] fn init_logger() { @@ -15,32 +5,3 @@ fn init_logger() { env_logger::init(); } } - -pub fn test_app_state(cx: &mut MutableAppContext) -> Arc { - let settings = Settings::test(cx); - editor::init(cx); - cx.set_global(settings); - let themes = ThemeRegistry::new(Assets, cx.font_cache().clone()); - let http = FakeHttpClient::with_404_response(); - let client = Client::new(http.clone()); - let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx)); - let languages = LanguageRegistry::test(); - languages.add(Arc::new(language::Language::new( - language::LanguageConfig { - name: "Rust".into(), - path_suffixes: vec!["rs".to_string()], - ..Default::default() - }, - Some(tree_sitter_rust::language()), - ))); - Arc::new(AppState { - themes, - languages: Arc::new(languages), - channel_list: cx.add_model(|cx| ChannelList::new(user_store.clone(), client.clone(), cx)), - client, - user_store, - fs: FakeFs::new(cx.background().clone()), - build_window_options, - build_workspace, - }) -} diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index bfb75d88740ae1eee3928cc7d1f18b9b2cbe3dad..4f0f8e21ccfe7ac536f0a7859c99516987e3f0c6 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -15,7 +15,7 @@ use gpui::{ actions, geometry::vector::vec2f, platform::{WindowBounds, WindowOptions}, - AsyncAppContext, ModelHandle, ViewContext, + AsyncAppContext, ViewContext, }; use lazy_static::lazy_static; pub use lsp; @@ -31,7 +31,7 @@ use std::{ }; use util::ResultExt; pub use workspace; -use workspace::{AppState, Workspace, WorkspaceParams}; +use workspace::{AppState, Workspace}; actions!( zed, @@ -115,13 +115,13 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { settings::KeymapFileContent::load_defaults(cx); } -pub fn build_workspace( - project: ModelHandle, +pub fn initialize_workspace( + workspace: &mut Workspace, app_state: &Arc, cx: &mut ViewContext, -) -> Workspace { +) { cx.subscribe(&cx.handle(), { - let project = project.clone(); + let project = workspace.project().clone(); move |_, _, event, cx| { if let workspace::Event::PaneAdded(pane) = event { pane.update(cx, |pane, cx| { @@ -139,22 +139,12 @@ pub fn build_workspace( }) .detach(); - let workspace_params = WorkspaceParams { - project, - client: app_state.client.clone(), - fs: app_state.fs.clone(), - languages: app_state.languages.clone(), - themes: app_state.themes.clone(), - user_store: app_state.user_store.clone(), - channel_list: app_state.channel_list.clone(), - }; - let workspace = Workspace::new(&workspace_params, cx); - let project = workspace.project().clone(); + cx.emit(workspace::Event::PaneAdded(workspace.active_pane().clone())); let theme_names = app_state.themes.list().collect(); let language_names = app_state.languages.language_names(); - project.update(cx, |project, cx| { + workspace.project().update(cx, |project, cx| { let action_names = cx.all_action_names().collect::>(); project.set_language_server_settings(serde_json::json!({ "json": { @@ -172,9 +162,10 @@ pub fn build_workspace( })); }); - let project_panel = ProjectPanel::new(project, cx); - let contact_panel = - cx.add_view(|cx| ContactsPanel::new(app_state.clone(), workspace.weak_handle(), cx)); + let project_panel = ProjectPanel::new(workspace.project().clone(), cx); + let contact_panel = cx.add_view(|cx| { + ContactsPanel::new(app_state.user_store.clone(), workspace.weak_handle(), cx) + }); workspace.left_sidebar().update(cx, |sidebar, cx| { sidebar.add_item("icons/folder-tree-solid-14.svg", project_panel.into(), cx) @@ -196,8 +187,6 @@ pub fn build_workspace( status_bar.add_right_item(cursor_position, cx); status_bar.add_right_item(auto_update, cx); }); - - workspace } pub fn build_window_options() -> WindowOptions<'static> { @@ -287,14 +276,18 @@ fn open_config_file( workspace.open_paths(vec![path.to_path_buf()], cx) } else { let (_, workspace) = cx.add_window((app_state.build_window_options)(), |cx| { - let project = Project::local( - app_state.client.clone(), - app_state.user_store.clone(), - app_state.languages.clone(), - app_state.fs.clone(), + let mut workspace = Workspace::new( + Project::local( + app_state.client.clone(), + app_state.user_store.clone(), + app_state.languages.clone(), + app_state.fs.clone(), + cx, + ), cx, ); - (app_state.build_workspace)(project, &app_state, cx) + (app_state.initialize_workspace)(&mut workspace, &app_state, cx); + workspace }); workspace.update(cx, |workspace, cx| { workspace.open_paths(vec![path.to_path_buf()], cx) @@ -313,43 +306,45 @@ mod tests { use assets::Assets; use editor::{Autoscroll, DisplayPoint, Editor}; use gpui::{AssetSource, MutableAppContext, TestAppContext, ViewHandle}; - use project::{Fs, ProjectPath}; + use project::ProjectPath; use serde_json::json; use std::{ collections::HashSet, path::{Path, PathBuf}, }; - use test::test_app_state; use theme::{Theme, ThemeRegistry, DEFAULT_THEME_NAME}; - use util::test::temp_tree; use workspace::{ open_paths, pane, Item, ItemHandle, OpenNew, Pane, SplitDirection, WorkspaceHandle, }; #[gpui::test] async fn test_open_paths_action(cx: &mut TestAppContext) { - let app_state = cx.update(test_app_state); - let dir = temp_tree(json!({ - "a": { - "aa": null, - "ab": null, - }, - "b": { - "ba": null, - "bb": null, - }, - "c": { - "ca": null, - "cb": null, - }, - })); + let app_state = init(cx); + app_state + .fs + .as_fake() + .insert_tree( + "/root", + json!({ + "a": { + "aa": null, + "ab": null, + }, + "b": { + "ba": null, + "bb": null, + }, + "c": { + "ca": null, + "cb": null, + }, + }), + ) + .await; cx.update(|cx| { open_paths( - &[ - dir.path().join("a").to_path_buf(), - dir.path().join("b").to_path_buf(), - ], + &[PathBuf::from("/root/a"), PathBuf::from("/root/b")], &app_state, cx, ) @@ -357,7 +352,7 @@ mod tests { .await; assert_eq!(cx.window_ids().len(), 1); - cx.update(|cx| open_paths(&[dir.path().join("a").to_path_buf()], &app_state, cx)) + cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, cx)) .await; assert_eq!(cx.window_ids().len(), 1); let workspace_1 = cx.root_view::(cx.window_ids()[0]).unwrap(); @@ -369,10 +364,7 @@ mod tests { cx.update(|cx| { open_paths( - &[ - dir.path().join("b").to_path_buf(), - dir.path().join("c").to_path_buf(), - ], + &[PathBuf::from("/root/b"), PathBuf::from("/root/c")], &app_state, cx, ) @@ -383,11 +375,8 @@ mod tests { #[gpui::test] async fn test_new_empty_workspace(cx: &mut TestAppContext) { - let app_state = cx.update(test_app_state); - cx.update(|cx| { - workspace::init(&app_state.client, cx); - }); - cx.dispatch_global_action(workspace::OpenNew(app_state.clone())); + let app_state = init(cx); + cx.dispatch_global_action(workspace::OpenNew); let window_id = *cx.window_ids().first().unwrap(); let workspace = cx.root_view::(window_id).unwrap(); let editor = workspace.update(cx, |workspace, cx| { @@ -414,7 +403,7 @@ mod tests { #[gpui::test] async fn test_open_entry(cx: &mut TestAppContext) { - let app_state = cx.update(test_app_state); + let app_state = init(cx); app_state .fs .as_fake() @@ -429,18 +418,10 @@ mod tests { }), ) .await; - let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx)); - let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/root", true, cx) - }) - .await - .unwrap(); - cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) - .await; + let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; + let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); + let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); let file2 = entries[1].clone(); @@ -535,7 +516,8 @@ mod tests { #[gpui::test] async fn test_open_paths(cx: &mut TestAppContext) { - let app_state = cx.update(test_app_state); + let app_state = init(cx); + let fs = app_state.fs.as_fake(); fs.insert_dir("/dir1").await; fs.insert_dir("/dir2").await; @@ -544,17 +526,8 @@ mod tests { fs.insert_file("/dir2/b.txt", "".into()).await; fs.insert_file("/dir3/c.txt", "".into()).await; - let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx)); - let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/dir1", true, cx) - }) - .await - .unwrap(); - cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) - .await; + let project = Project::test(app_state.fs.clone(), ["/dir1".as_ref()], cx).await; + let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); // Open a file within an existing worktree. cx.update(|cx| { @@ -655,19 +628,15 @@ mod tests { #[gpui::test] async fn test_save_conflicting_item(cx: &mut TestAppContext) { - let app_state = cx.update(test_app_state); - let fs = app_state.fs.as_fake(); - fs.insert_tree("/root", json!({ "a.txt": "" })).await; - - let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx)); - let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/root", true, cx) - }) - .await - .unwrap(); + let app_state = init(cx); + app_state + .fs + .as_fake() + .insert_tree("/root", json!({ "a.txt": "" })) + .await; + + let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; + let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); // Open a file within an existing worktree. cx.update(|cx| { @@ -687,7 +656,11 @@ mod tests { editor.handle_input(&editor::Input("x".into()), cx) }) }); - fs.insert_file("/root/a.txt", "changed".to_string()).await; + app_state + .fs + .as_fake() + .insert_file("/root/a.txt", "changed".to_string()) + .await; editor .condition(&cx, |editor, cx| editor.has_conflict(cx)) .await; @@ -704,21 +677,16 @@ mod tests { #[gpui::test] async fn test_open_and_save_new_file(cx: &mut TestAppContext) { - let app_state = cx.update(test_app_state); + let app_state = init(cx); app_state.fs.as_fake().insert_dir("/root").await; - let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx)); - let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/root", true, cx) - }) - .await - .unwrap(); + + let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; + project.update(cx, |project, _| project.languages().add(rust_lang())); + let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap()); // Create a new untitled buffer - cx.dispatch_action(window_id, OpenNew(app_state.clone())); + cx.dispatch_action(window_id, OpenNew); let editor = workspace.read_with(cx, |workspace, cx| { workspace .active_item(cx) @@ -773,18 +741,11 @@ mod tests { // Open the same newly-created file in another pane item. The new editor should reuse // the same buffer. - cx.dispatch_action(window_id, OpenNew(app_state.clone())); + cx.dispatch_action(window_id, OpenNew); workspace .update(cx, |workspace, cx| { workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx); - workspace.open_path( - ProjectPath { - worktree_id: worktree.read(cx).id(), - path: Path::new("the-new-name.rs").into(), - }, - true, - cx, - ) + workspace.open_path((worktree.read(cx).id(), "the-new-name.rs"), true, cx) }) .await .unwrap(); @@ -805,13 +766,15 @@ mod tests { #[gpui::test] async fn test_setting_language_when_saving_as_single_file_worktree(cx: &mut TestAppContext) { - let app_state = cx.update(test_app_state); + let app_state = init(cx); app_state.fs.as_fake().insert_dir("/root").await; - let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx)); - let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); + + let project = Project::test(app_state.fs.clone(), [], cx).await; + project.update(cx, |project, _| project.languages().add(rust_lang())); + let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); // Create a new untitled buffer - cx.dispatch_action(window_id, OpenNew(app_state.clone())); + cx.dispatch_action(window_id, OpenNew); let editor = workspace.read_with(cx, |workspace, cx| { workspace .active_item(cx) @@ -842,10 +805,9 @@ mod tests { #[gpui::test] async fn test_pane_actions(cx: &mut TestAppContext) { - cx.foreground().forbid_parking(); + init(cx); - cx.update(|cx| pane::init(cx)); - let app_state = cx.update(test_app_state); + let app_state = cx.update(AppState::test); app_state .fs .as_fake() @@ -861,17 +823,9 @@ mod tests { ) .await; - let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx)); - let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/root", true, cx) - }) - .await - .unwrap(); - cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) - .await; + let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; + let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); + let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); @@ -926,7 +880,7 @@ mod tests { #[gpui::test] async fn test_navigation(cx: &mut TestAppContext) { - let app_state = cx.update(test_app_state); + let app_state = init(cx); app_state .fs .as_fake() @@ -941,17 +895,10 @@ mod tests { }), ) .await; - let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx)); - let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx)); - params - .project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/root", true, cx) - }) - .await - .unwrap(); - cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) - .await; + + let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; + let (_, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx)); + let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); let file2 = entries[1].clone(); @@ -990,7 +937,7 @@ mod tests { editor.newline(&Default::default(), cx); editor.move_down(&Default::default(), cx); editor.move_down(&Default::default(), cx); - editor.save(params.project.clone(), cx) + editor.save(project.clone(), cx) }) .await .unwrap(); @@ -1104,7 +1051,6 @@ mod tests { .unwrap(); app_state .fs - .as_fake() .remove_file(Path::new("/root/a/file2"), Default::default()) .await .unwrap(); @@ -1219,4 +1165,29 @@ mod tests { } assert!(has_default_theme); } + + fn init(cx: &mut TestAppContext) -> Arc { + cx.foreground().forbid_parking(); + cx.update(|cx| { + let mut app_state = AppState::test(cx); + let state = Arc::get_mut(&mut app_state).unwrap(); + state.initialize_workspace = initialize_workspace; + state.build_window_options = build_window_options; + workspace::init(app_state.clone(), cx); + editor::init(cx); + pane::init(cx); + app_state + }) + } + + fn rust_lang() -> Arc { + Arc::new(language::Language::new( + language::LanguageConfig { + name: "Rust".into(), + path_suffixes: vec!["rs".to_string()], + ..Default::default() + }, + Some(tree_sitter_rust::language()), + )) + } } diff --git a/script/build-themes b/script/build-themes deleted file mode 100755 index aef3a4250cdac8a3934938e812d5c7602d388731..0000000000000000000000000000000000000000 --- a/script/build-themes +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -cd styles -npm install -npm run build diff --git a/styles/nodemon.json b/styles/nodemon.json deleted file mode 100644 index 47facd6322c80a79b87fe9320e4a71cc0bf275f9..0000000000000000000000000000000000000000 --- a/styles/nodemon.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "watch": [ - "./**/*" - ], - "ext": "ts", - "ignore": [], - "exec": "ts-node src/buildThemes.ts" -} diff --git a/styles/package-lock.json b/styles/package-lock.json index 63bf3d5a574fb810605841c940ef2b0db445dab4..49304dc2fa98dfec942bf6687be56cefc13cdf80 100644 --- a/styles/package-lock.json +++ b/styles/package-lock.json @@ -13,7 +13,6 @@ "@types/node": "^17.0.23", "case-anything": "^2.1.10", "chroma-js": "^2.4.2", - "nodemon": "^2.0.15", "ts-node": "^10.7.0" } }, @@ -36,25 +35,6 @@ "node": ">=12" } }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -85,11 +65,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==" }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, "node_modules/acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -109,157 +84,11 @@ "node": ">=0.4.0" } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/case-anything": { "version": "2.1.10", "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz", @@ -271,177 +100,16 @@ "url": "https://github.com/sponsors/mesqueeb" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/chroma-js": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz", "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==" }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dependencies": { - "mimic-response": "^1.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -450,950 +118,113 @@ "node": ">=0.3.1" } }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "engines": { - "node": ">=8" - } + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/ts-node": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", + "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", "dependencies": { - "to-regex-range": "^5.0.1" + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.0", + "yn": "3.1.1" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dependencies": { - "pump": "^3.0.0" + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" }, - "engines": { - "node": ">=6" + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" + "node_modules/typescript": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">= 6" + "node": ">=4.2.0" } }, - "node_modules/global-dirs": { + "node_modules/v8-compile-cache-lib": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", + "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==" }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "engines": { - "node": ">=8.6" + "node": ">=6" } + } + }, + "dependencies": { + "@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==" }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" + "@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "requires": { + "@cspotcode/source-map-consumer": "0.8.0" } }, - "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "engines": { - "node": ">=8" - } + "@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==" }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + "@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==" }, - "node_modules/ignore-by-default": { + "@tsconfig/node14": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" - }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "engines": { - "node": ">=4" - } + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==" }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" - }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" - }, - "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dependencies": { - "package-json": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/nodemon": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", - "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", - "hasInstallScript": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5", - "update-notifier": "^5.1.0" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "engines": { - "node": ">=4" - } - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dependencies": { - "escape-goat": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/ts-node": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", - "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", - "dependencies": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", - "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", - "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==" - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "engines": { - "node": ">=6" - } - } - }, - "dependencies": { - "@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==" - }, - "@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "requires": { - "@cspotcode/source-map-consumer": "0.8.0" - } - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==" - }, - "@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==" - }, - "@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==" - }, - "@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==" + "@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==" }, "@types/chroma-js": { "version": "2.1.3", @@ -1405,11 +236,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==" }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, "acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -1420,758 +246,36 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "requires": { - "string-width": "^4.1.0" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" - }, - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - } - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" - }, "case-anything": { "version": "2.1.10", "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz", "integrity": "sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ==" }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, "chroma-js": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz", "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==" }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" - }, - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "requires": { - "ini": "2.0.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" - }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "requires": { - "json-buffer": "3.0.0" - } - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "requires": { - "package-json": "^6.3.0" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "nodemon": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", - "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", - "requires": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5", - "update-notifier": "^5.1.0" - } - }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "requires": { - "abbrev": "1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" - }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" - }, - "pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "requires": { - "escape-goat": "^2.0.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - } - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "requires": { - "picomatch": "^2.2.1" - } - }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "requires": { - "rc": "^1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "requires": { - "rc": "^1.2.8" - } - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "requires": { - "nopt": "~1.0.10" - } - }, "ts-node": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", @@ -2192,126 +296,17 @@ "yn": "3.1.1" } }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, "typescript": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "peer": true }, - "undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "requires": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "requires": { - "prepend-http": "^2.0.0" - } - }, "v8-compile-cache-lib": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==" }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "requires": { - "string-width": "^4.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/styles/package.json b/styles/package.json index 727300e2cce7c5a2db01696a968cf32ba7f0f41b..eebc80d5213de0abc90b93de5721e7568276f9e3 100644 --- a/styles/package.json +++ b/styles/package.json @@ -6,8 +6,7 @@ "scripts": { "build": "npm run build-themes && npm run build-tokens", "build-themes": "ts-node ./src/buildThemes.ts", - "build-tokens": "ts-node ./src/buildTokens.ts", - "watch": "nodemon" + "build-tokens": "ts-node ./src/buildTokens.ts" }, "author": "", "license": "ISC", @@ -16,7 +15,6 @@ "@types/node": "^17.0.23", "case-anything": "^2.1.10", "chroma-js": "^2.4.2", - "ts-node": "^10.7.0", - "nodemon": "^2.0.15" + "ts-node": "^10.7.0" } } diff --git a/styles/src/buildThemes.ts b/styles/src/buildThemes.ts index 520a37395d5f1775ac37c465ec4f81ac5121b0ef..c43be067a869f37e7b39bda62cbe0dd7d6f81fd3 100644 --- a/styles/src/buildThemes.ts +++ b/styles/src/buildThemes.ts @@ -1,23 +1,30 @@ import * as fs from "fs"; import * as path from "path"; +import { tmpdir } from 'os'; import app from "./styleTree/app"; import themes from "./themes"; import snakeCase from "./utils/snakeCase"; const themeDirectory = `${__dirname}/../../assets/themes/`; +const tempDirectory = fs.mkdtempSync(path.join(tmpdir(), 'build-themes')); // Clear existing themes for (const file of fs.readdirSync(themeDirectory)) { - fs.unlinkSync(path.join(themeDirectory, file)); + if (file.endsWith('.json')) { + const name = file.replace(/\.json$/, ''); + if (!themes.find(theme => theme.name === name)) { + fs.unlinkSync(path.join(themeDirectory, file)); + } + } } // Write new themes to theme directory for (let theme of themes) { let styleTree = snakeCase(app(theme)); let styleTreeJSON = JSON.stringify(styleTree, null, 2); - let outPath = path.resolve( - `${__dirname}/../../assets/themes/${theme.name}.json` - ); - fs.writeFileSync(outPath, styleTreeJSON); + let tempPath = path.join(tempDirectory, `${theme.name}.json`); + let outPath = path.join(themeDirectory, `${theme.name}.json`); + fs.writeFileSync(tempPath, styleTreeJSON); + fs.renameSync(tempPath, outPath); console.log(`- ${outPath} created`); } diff --git a/styles/src/themes.ts b/styles/src/themes.ts index ef02fab8219fc3aa748436461fe08e916192dd5d..8d1782fd8472937f2ae97c3536139c35db1971de 100644 --- a/styles/src/themes.ts +++ b/styles/src/themes.ts @@ -7,10 +7,12 @@ export default themes; const themesPath = path.resolve(`${__dirname}/themes`); for (const fileName of fs.readdirSync(themesPath)) { + if (fileName == "template.ts") continue; const filePath = path.join(themesPath, fileName); + if (fs.statSync(filePath).isFile()) { const theme = require(filePath); - themes.push(theme.dark); - themes.push(theme.light); + if (theme.dark) themes.push(theme.dark); + if (theme.light) themes.push(theme.light); } } diff --git a/styles/src/themes/andromeda.ts b/styles/src/themes/andromeda.ts new file mode 100644 index 0000000000000000000000000000000000000000..b09f0e1ab722a8538f1467fcee27166e8b2cab78 --- /dev/null +++ b/styles/src/themes/andromeda.ts @@ -0,0 +1,27 @@ +import chroma from "chroma-js"; +import { colorRamp, createTheme } from "./common/base16"; + +const name = "andromeda"; + +const ramps = { + neutral: chroma.scale([ + "#1E2025", + "#23262E", + "#292E38", + "#2E323C", + "#ACA8AE", + "#CBC9CF", + "#E1DDE4", + "#F7F7F8", + ]), + red: colorRamp(chroma("#F92672")), + orange: colorRamp(chroma("#F39C12")), + yellow: colorRamp(chroma("#FFE66D")), + green: colorRamp(chroma("#96E072")), + cyan: colorRamp(chroma("#00E8C6")), + blue: colorRamp(chroma("#0CA793")), + violet: colorRamp(chroma("#8A3FA6")), + magenta: colorRamp(chroma("#C74DED")), +}; + +export const dark = createTheme(`${name}`, false, ramps); diff --git a/styles/src/themes/brushtrees.ts b/styles/src/themes/brushtrees.ts new file mode 100644 index 0000000000000000000000000000000000000000..24c0ac6eec9c2694516e8e59b08eb8ecf245bffa --- /dev/null +++ b/styles/src/themes/brushtrees.ts @@ -0,0 +1,28 @@ +import chroma from "chroma-js"; +import { colorRamp, createTheme } from "./common/base16"; + +const name = "brush-tree"; + +const ramps = { + neutral: chroma.scale([ + "#485867", + "#5A6D7A", + "#6D828E", + "#8299A1", + "#98AFB5", + "#B0C5C8", + "#C9DBDC", + "#E3EFEF", + ]), + red: colorRamp(chroma("#b38686")), + orange: colorRamp(chroma("#d8bba2")), + yellow: colorRamp(chroma("#aab386")), + green: colorRamp(chroma("#87b386")), + cyan: colorRamp(chroma("#86b3b3")), + blue: colorRamp(chroma("#868cb3")), + violet: colorRamp(chroma("#b386b2")), + magenta: colorRamp(chroma("#b39f9f")), +}; + +export const dark = createTheme(`${name}-dark`, false, ramps); +export const light = createTheme(`${name}-light`, true, ramps); diff --git a/styles/src/themes/cave.ts b/styles/src/themes/cave.ts index f3c8102ac9ecc5d7b267a7f201cf73e47275cbc1..2e66f4baf465c473ea4660adc46cfd22e416adbe 100644 --- a/styles/src/themes/cave.ts +++ b/styles/src/themes/cave.ts @@ -4,7 +4,16 @@ import { colorRamp, createTheme } from "./common/base16"; const name = "cave"; const ramps = { - neutral: chroma.scale(["#19171c", "#26232a", "#585260", "#655f6d", "#7e7887", "#8b8792", "#e2dfe7", "#efecf4"]), + neutral: chroma.scale([ + "#19171c", + "#26232a", + "#585260", + "#655f6d", + "#7e7887", + "#8b8792", + "#e2dfe7", + "#efecf4", + ]), red: colorRamp(chroma("#be4678")), orange: colorRamp(chroma("#aa573c")), yellow: colorRamp(chroma("#a06e3b")), @@ -13,7 +22,7 @@ const ramps = { blue: colorRamp(chroma("#576ddb")), violet: colorRamp(chroma("#955ae7")), magenta: colorRamp(chroma("#bf40bf")), -} +}; export const dark = createTheme(`${name}-dark`, false, ramps); -export const light = createTheme(`${name}-light`, true, ramps); \ No newline at end of file +export const light = createTheme(`${name}-light`, true, ramps); diff --git a/styles/src/themes/common/base16.ts b/styles/src/themes/common/base16.ts index 525b39f2148540378961bb996054f746e00ad2fd..a05b3b2e71eaa6017973a2a8e715595ee1590362 100644 --- a/styles/src/themes/common/base16.ts +++ b/styles/src/themes/common/base16.ts @@ -1,5 +1,4 @@ -import chroma from "chroma-js"; -import { Scale, Color } from "chroma-js"; +import chroma, { Color, Scale } from "chroma-js"; import { color, ColorToken, fontWeights, NumberToken } from "../../tokens"; import { withOpacity } from "../../utils/color"; import Theme, { buildPlayer, Syntax } from "./theme"; @@ -8,12 +7,15 @@ export function colorRamp(color: Color): Scale { let hue = color.hsl()[0]; let endColor = chroma.hsl(hue, 0.88, 0.96); let startColor = chroma.hsl(hue, 0.68, 0.12); - return chroma - .scale([startColor, color, endColor]) - .mode("hsl"); + return chroma.scale([startColor, color, endColor]).mode("hsl"); } -export function createTheme(name: string, isLight: boolean, ramps: { [rampName: string]: Scale }, blend?: number): Theme { +export function createTheme( + name: string, + isLight: boolean, + ramps: { [rampName: string]: Scale }, + blend?: number +): Theme { if (isLight) { for (var rampName in ramps) { ramps[rampName] = ramps[rampName].domain([1, 0]); @@ -62,22 +64,22 @@ export function createTheme(name: string, isLight: boolean, ramps: { [rampName: }, ok: { base: withOpacity(rampColor(ramps.green, 0.5), 0.15), - hovered: withOpacity(rampColor(ramps.green, 0.5), 0.20), + hovered: withOpacity(rampColor(ramps.green, 0.5), 0.2), active: withOpacity(rampColor(ramps.green, 0.5), 0.25), }, error: { base: withOpacity(rampColor(ramps.red, 0.5), 0.15), - hovered: withOpacity(rampColor(ramps.red, 0.5), 0.20), + hovered: withOpacity(rampColor(ramps.red, 0.5), 0.2), active: withOpacity(rampColor(ramps.red, 0.5), 0.25), }, warning: { base: withOpacity(rampColor(ramps.yellow, 0.5), 0.15), - hovered: withOpacity(rampColor(ramps.yellow, 0.5), 0.20), + hovered: withOpacity(rampColor(ramps.yellow, 0.5), 0.2), active: withOpacity(rampColor(ramps.yellow, 0.5), 0.25), }, info: { base: withOpacity(rampColor(ramps.blue, 0.5), 0.15), - hovered: withOpacity(rampColor(ramps.blue, 0.5), 0.20), + hovered: withOpacity(rampColor(ramps.blue, 0.5), 0.2), active: withOpacity(rampColor(ramps.blue, 0.5), 0.25), }, }; @@ -242,4 +244,4 @@ export function createTheme(name: string, isLight: boolean, ramps: { [rampName: player, shadowAlpha, }; -} \ No newline at end of file +} diff --git a/styles/src/themes/common/theme.ts b/styles/src/themes/common/theme.ts index 2c648e87ec530d639e3bd77167b01632219c38ea..d6a3149e312601b9cfa295fe69d5e34f219d4369 100644 --- a/styles/src/themes/common/theme.ts +++ b/styles/src/themes/common/theme.ts @@ -4,8 +4,8 @@ import { withOpacity } from "../../utils/color"; export interface SyntaxHighlightStyle { color: ColorToken; weight?: FontWeightToken; - underline?: boolean, - italic?: boolean, + underline?: boolean; + italic?: boolean; } export interface Player { @@ -25,7 +25,7 @@ export function buildPlayer( cursorColor: withOpacity(color, cursorOpacity || 1.0), selectionColor: withOpacity(color, selectionOpacity || 0.24), borderColor: withOpacity(color, borderOpacity || 0.8), - } + }; } export interface BackgroundColorSet { @@ -56,7 +56,7 @@ export interface Syntax { linkText: SyntaxHighlightStyle; [key: string]: SyntaxHighlightStyle; -}; +} export default interface Theme { name: string; @@ -86,8 +86,8 @@ export default interface Theme { muted: ColorToken; active: ColorToken; /** - * Used for rendering borders on top of media like avatars, images, video, etc. - */ + * Used for rendering borders on top of media like avatars, images, video, etc. + */ onMedia: ColorToken; ok: ColorToken; error: ColorToken; @@ -141,7 +141,7 @@ export default interface Theme { }; }; - syntax: Syntax, + syntax: Syntax; player: { 1: Player; diff --git a/styles/src/themes/rose-pine-dawn.ts b/styles/src/themes/rose-pine-dawn.ts new file mode 100644 index 0000000000000000000000000000000000000000..53d893f956d5b1d1b6abc0ef61187517636569ae --- /dev/null +++ b/styles/src/themes/rose-pine-dawn.ts @@ -0,0 +1,27 @@ +import chroma from "chroma-js"; +import { colorRamp, createTheme } from "./common/base16"; + +const name = "rosé-pine-dawn"; + +const ramps = { + neutral: chroma.scale([ + "#26233a", + "#555169", + "#575279", + "#6e6a86", + "#9893a5", + "#f2e9de", + "#fffaf3", + "#faf4ed", + ]), + red: colorRamp(chroma("#1f1d2e")), + orange: colorRamp(chroma("#b4637a")), + yellow: colorRamp(chroma("#ea9d34")), + green: colorRamp(chroma("#d7827e")), + cyan: colorRamp(chroma("#286983")), + blue: colorRamp(chroma("#56949f")), + violet: colorRamp(chroma("#907aa9")), + magenta: colorRamp(chroma("#c5c3ce")), +}; + +export const light = createTheme(`${name}`, true, ramps); diff --git a/styles/src/themes/rose-pine.ts b/styles/src/themes/rose-pine.ts new file mode 100644 index 0000000000000000000000000000000000000000..8150955bf710786b184551fed20aa6345149c6f4 --- /dev/null +++ b/styles/src/themes/rose-pine.ts @@ -0,0 +1,27 @@ +import chroma from "chroma-js"; +import { colorRamp, createTheme } from "./common/base16"; + +const name = "rosé-pine"; + +const ramps = { + neutral: chroma.scale([ + "#191724", + "#1f1d2e", + "#26233a", + "#555169", + "#6e6a86", + "#e0def4", + "#f0f0f3", + "#c5c3ce", + ]), + red: colorRamp(chroma("#e2e1e7")), + orange: colorRamp(chroma("#eb6f92")), + yellow: colorRamp(chroma("#f6c177")), + green: colorRamp(chroma("#ebbcba")), + cyan: colorRamp(chroma("#31748f")), + blue: colorRamp(chroma("#0CA793")), + violet: colorRamp(chroma("#8A3FA6")), + magenta: colorRamp(chroma("#C74DED")), +}; + +export const dark = createTheme(`${name}`, false, ramps); diff --git a/styles/src/themes/sandcastle.ts b/styles/src/themes/sandcastle.ts new file mode 100644 index 0000000000000000000000000000000000000000..45e0be16239333dd495f1c857f694a832520cbe6 --- /dev/null +++ b/styles/src/themes/sandcastle.ts @@ -0,0 +1,27 @@ +import chroma from "chroma-js"; +import { colorRamp, createTheme } from "./common/base16"; + +const name = "sandcastle"; + +const ramps = { + neutral: chroma.scale([ + "#282c34", + "#2c323b", + "#3e4451", + "#665c54", + "#928374", + "#a89984", + "#d5c4a1", + "#fdf4c1", + ]), + red: colorRamp(chroma("#83a598")), + orange: colorRamp(chroma("#a07e3b")), + yellow: colorRamp(chroma("#a07e3b")), + green: colorRamp(chroma("#528b8b")), + cyan: colorRamp(chroma("#83a598")), + blue: colorRamp(chroma("#83a598")), + violet: colorRamp(chroma("#d75f5f")), + magenta: colorRamp(chroma("#a87322")), +}; + +export const dark = createTheme(`${name}`, false, ramps); diff --git a/styles/src/themes/solarized.ts b/styles/src/themes/solarized.ts index 6992dc5bf8e86f30a67a9fde5c95b5b31ee489f2..7027d16447fc3753b909b5ffcc268cfaba78c78b 100644 --- a/styles/src/themes/solarized.ts +++ b/styles/src/themes/solarized.ts @@ -4,7 +4,16 @@ import { colorRamp, createTheme } from "./common/base16"; const name = "solarized"; const ramps = { - neutral: chroma.scale(["#002b36", "#073642", "#586e75", "#657b83", "#839496", "#93a1a1", "#eee8d5", "#fdf6e3"]), + neutral: chroma.scale([ + "#002b36", + "#073642", + "#586e75", + "#657b83", + "#839496", + "#93a1a1", + "#eee8d5", + "#fdf6e3", + ]), red: colorRamp(chroma("#dc322f")), orange: colorRamp(chroma("#cb4b16")), yellow: colorRamp(chroma("#b58900")), @@ -13,7 +22,7 @@ const ramps = { blue: colorRamp(chroma("#268bd2")), violet: colorRamp(chroma("#6c71c4")), magenta: colorRamp(chroma("#d33682")), -} +}; export const dark = createTheme(`${name}-dark`, false, ramps); -export const light = createTheme(`${name}-light`, true, ramps); \ No newline at end of file +export const light = createTheme(`${name}-light`, true, ramps); diff --git a/styles/src/themes/sulphurpool.ts b/styles/src/themes/sulphurpool.ts index 202d52bc68532cae2e109cedaf8c0b91c7edfcd3..6aa95008c305a121c068ca409510f01bf65802a5 100644 --- a/styles/src/themes/sulphurpool.ts +++ b/styles/src/themes/sulphurpool.ts @@ -4,7 +4,16 @@ import { colorRamp, createTheme } from "./common/base16"; const name = "sulphurpool"; const ramps = { - neutral: chroma.scale(["#202746", "#293256", "#5e6687", "#6b7394", "#898ea4", "#979db4", "#dfe2f1", "#f5f7ff"]), + neutral: chroma.scale([ + "#202746", + "#293256", + "#5e6687", + "#6b7394", + "#898ea4", + "#979db4", + "#dfe2f1", + "#f5f7ff", + ]), red: colorRamp(chroma("#c94922")), orange: colorRamp(chroma("#c76b29")), yellow: colorRamp(chroma("#c08b30")), @@ -13,7 +22,7 @@ const ramps = { blue: colorRamp(chroma("#3d8fd1")), violet: colorRamp(chroma("#6679cc")), magenta: colorRamp(chroma("#9c637a")), -} +}; export const dark = createTheme(`${name}-dark`, false, ramps); -export const light = createTheme(`${name}-light`, true, ramps); \ No newline at end of file +export const light = createTheme(`${name}-light`, true, ramps); diff --git a/styles/src/themes/summercamp.ts b/styles/src/themes/summercamp.ts new file mode 100644 index 0000000000000000000000000000000000000000..efb716c2df34a8efc9e496f18a4950c0391fc397 --- /dev/null +++ b/styles/src/themes/summercamp.ts @@ -0,0 +1,27 @@ +import chroma from "chroma-js"; +import { colorRamp, createTheme } from "./common/base16"; + +const name = "summercamp"; + +const ramps = { + neutral: chroma.scale([ + "#1c1810", + "#2a261c", + "#3a3527", + "#3a3527", + "#5f5b45", + "#736e55", + "#bab696", + "#f8f5de", + ]), + red: colorRamp(chroma("#e35142")), + orange: colorRamp(chroma("#fba11b")), + yellow: colorRamp(chroma("#f2ff27")), + green: colorRamp(chroma("#5ceb5a")), + cyan: colorRamp(chroma("#5aebbc")), + blue: colorRamp(chroma("#489bf0")), + violet: colorRamp(chroma("#FF8080")), + magenta: colorRamp(chroma("#F69BE7")), +}; + +export const dark = createTheme(`${name}`, false, ramps); diff --git a/styles/src/themes/summerfruit.ts b/styles/src/themes/summerfruit.ts new file mode 100644 index 0000000000000000000000000000000000000000..502e3893cbdf126862d621b76473da7dafa7d4ac --- /dev/null +++ b/styles/src/themes/summerfruit.ts @@ -0,0 +1,28 @@ +import chroma from "chroma-js"; +import { colorRamp, createTheme } from "./common/base16"; + +const name = "summerfruit"; + +const ramps = { + neutral: chroma.scale([ + "#151515", + "#202020", + "#303030", + "#505050", + "#B0B0B0", + "#D0D0D0", + "#E0E0E0", + "#FFFFFF", + ]), + red: colorRamp(chroma("#FF0086")), + orange: colorRamp(chroma("#FD8900")), + yellow: colorRamp(chroma("#ABA800")), + green: colorRamp(chroma("#00C918")), + cyan: colorRamp(chroma("#1FAAAA")), + blue: colorRamp(chroma("#3777E6")), + violet: colorRamp(chroma("#AD00A1")), + magenta: colorRamp(chroma("#CC6633")), +}; + +export const dark = createTheme(`${name}-dark`, false, ramps); +export const light = createTheme(`${name}-light`, true, ramps); diff --git a/styles/src/themes/template.ts b/styles/src/themes/template.ts new file mode 100644 index 0000000000000000000000000000000000000000..d8617287a26eb2b24db2c3fae47bc5b91e8229d6 --- /dev/null +++ b/styles/src/themes/template.ts @@ -0,0 +1,69 @@ +/** + * To create a new theme duplicate this file and move into templates + **/ + +import chroma from "chroma-js"; +import { colorRamp, createTheme } from "./common/base16"; + +/** + * Theme Name + * + * What the theme will be called in the UI + * Also used to generate filenames, etc + **/ + +const name = "themeName"; + +/** + * Theme Colors + * + * Zed themes are based on [base16](https://github.com/chriskempson/base16) + * The first 8 colors ("Neutrals") are used to construct the UI background, panels, etc. + * The latter 8 colors ("Accents") are used for syntax themes, semantic colors, and UI states. + **/ + +/** + * Color Ramps + * + * We use (chroma-js)[https://gka.github.io/chroma.js/] to minipulate color in themes and to build color ramps. + * + * You can use chroma-js operations on the ramps here. + * For example, you could use chroma.scale(...).correctLightness if your color ramps seem washed out near the ends. + **/ + +// TODO: Express accents without refering to them directly by color name. +// See common/base16.ts for where color tokens are used. + +const ramps = { + neutral: chroma.scale([ + "#19171c", // Dark: darkest backgrounds, inputs | Light: Lightest text, active states + "#26232a", + "#585260", + "#655f6d", + "#7e7887", + "#8b8792", + "#e2dfe7", + "#efecf4", // Light: darkest backgrounds, inputs | Dark: Lightest text, active states + ]), + red: colorRamp(chroma("#be4678")), // Errors + orange: colorRamp(chroma("#aa573c")), + yellow: colorRamp(chroma("#a06e3b")), // Warnings + green: colorRamp(chroma("#2a9292")), // Positive + cyan: colorRamp(chroma("#398bc6")), // Player 1 (Host) + blue: colorRamp(chroma("#576ddb")), // Info + violet: colorRamp(chroma("#955ae7")), + magenta: colorRamp(chroma("#bf40bf")), +}; + +/** + * Theme Variants + * + * Currently we only support (and require) dark and light themes + * Eventually you will be able to have only a light or dark theme, + * and define other variants here. + * + * createTheme([name], [isLight], [arrayOfRamps]) + **/ + +export const dark = createTheme(`${name}-dark`, false, ramps); +export const light = createTheme(`${name}-light`, true, ramps);