From 4305c5fdbef92f3a700b7e500642737ea62919aa Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 3 Jan 2024 12:33:51 -0800 Subject: [PATCH] Remove 2 suffix for ui, storybook, text Co-authored-by: Mikayla --- Cargo.lock | 111 +- Cargo.toml | 4 +- crates/activity_indicator/Cargo.toml | 2 +- crates/assistant/Cargo.toml | 2 +- crates/breadcrumbs/Cargo.toml | 2 +- crates/channel/Cargo.toml | 2 +- crates/client/Cargo.toml | 2 +- crates/collab/Cargo.toml | 2 +- crates/collab_ui/Cargo.toml | 2 +- crates/command_palette/Cargo.toml | 2 +- crates/copilot/Cargo.toml | 2 +- crates/diagnostics/Cargo.toml | 2 +- crates/editor/Cargo.toml | 6 +- crates/feedback/Cargo.toml | 2 +- crates/file_finder/Cargo.toml | 4 +- crates/fs/Cargo.toml | 2 +- crates/git/Cargo.toml | 2 +- crates/go_to_line/Cargo.toml | 4 +- crates/language/Cargo.toml | 4 +- crates/language_selector/Cargo.toml | 2 +- crates/language_tools/Cargo.toml | 2 +- crates/multi_buffer/Cargo.toml | 4 +- crates/notifications/Cargo.toml | 2 +- crates/outline/Cargo.toml | 4 +- crates/picker/Cargo.toml | 2 +- crates/project/Cargo.toml | 2 +- crates/project_panel/Cargo.toml | 2 +- crates/project_symbols/Cargo.toml | 2 +- crates/quick_action_bar/Cargo.toml | 2 +- crates/recent_projects/Cargo.toml | 4 +- crates/search/Cargo.toml | 2 +- crates/{storybook2 => storybook}/Cargo.lock | 0 crates/{storybook2 => storybook}/Cargo.toml | 6 +- crates/{storybook2 => storybook}/build.rs | 0 .../docs/thoughts.md | 0 .../{storybook2 => storybook}/src/assets.rs | 0 .../{storybook2 => storybook}/src/stories.rs | 0 .../src/stories/auto_height_editor.rs | 0 .../src/stories/cursor.rs | 0 .../src/stories/focus.rs | 0 .../src/stories/kitchen_sink.rs | 0 .../src/stories/overflow_scroll.rs | 0 .../src/stories/picker.rs | 0 .../src/stories/scroll.rs | 0 .../src/stories/text.rs | 2 +- .../src/stories/viewport_units.rs | 0 .../src/stories/z_index.rs | 0 .../src/story_selector.rs | 0 .../src/storybook.rs} | 0 crates/terminal2/Cargo.toml | 38 - crates/terminal_view/Cargo.toml | 2 +- crates/text/Cargo.toml | 2 +- crates/text/src/locator.rs | 4 +- crates/text/src/selection.rs | 2 +- crates/text/src/subscription.rs | 2 +- crates/text/src/text.rs | 5 +- crates/text2/Cargo.toml | 37 - crates/text2/src/anchor.rs | 144 - crates/text2/src/locator.rs | 125 - crates/text2/src/network.rs | 69 - crates/text2/src/operation_queue.rs | 153 - crates/text2/src/patch.rs | 594 ---- crates/text2/src/selection.rs | 123 - crates/text2/src/subscription.rs | 48 - crates/text2/src/tests.rs | 764 ----- crates/text2/src/text2.rs | 2679 ----------------- crates/text2/src/undo_map.rs | 112 - crates/theme_selector/Cargo.toml | 2 +- crates/{ui2 => ui}/Cargo.toml | 6 +- crates/{ui2 => ui}/docs/building-ui.md | 0 crates/{ui2 => ui}/docs/hello-world.md | 0 crates/{ui2 => ui}/docs/todo.md | 0 crates/{ui2 => ui}/src/clickable.rs | 0 crates/{ui2 => ui}/src/components.rs | 0 crates/{ui2 => ui}/src/components/avatar.rs | 0 crates/{ui2 => ui}/src/components/button.rs | 0 .../src/components/button/button.rs | 0 .../src/components/button/button_icon.rs | 0 .../src/components/button/button_like.rs | 0 .../src/components/button/icon_button.rs | 0 .../src/components/button/toggle_button.rs | 0 crates/{ui2 => ui}/src/components/checkbox.rs | 0 .../src/components/context_menu.rs | 0 .../{ui2 => ui}/src/components/disclosure.rs | 0 crates/{ui2 => ui}/src/components/divider.rs | 0 crates/{ui2 => ui}/src/components/icon.rs | 0 .../{ui2 => ui}/src/components/indicator.rs | 0 .../{ui2 => ui}/src/components/keybinding.rs | 0 crates/{ui2 => ui}/src/components/label.rs | 0 .../src/components/label/highlighted_label.rs | 0 .../{ui2 => ui}/src/components/label/label.rs | 0 .../src/components/label/label_like.rs | 0 crates/{ui2 => ui}/src/components/list.rs | 0 .../{ui2 => ui}/src/components/list/list.rs | 0 .../src/components/list/list_header.rs | 0 .../src/components/list/list_item.rs | 0 .../src/components/list/list_separator.rs | 0 .../src/components/list/list_sub_header.rs | 0 crates/{ui2 => ui}/src/components/popover.rs | 0 .../src/components/popover_menu.rs | 0 .../src/components/right_click_menu.rs | 0 crates/{ui2 => ui}/src/components/stack.rs | 0 crates/{ui2 => ui}/src/components/stories.rs | 0 .../src/components/stories/avatar.rs | 0 .../src/components/stories/button.rs | 0 .../src/components/stories/checkbox.rs | 0 .../src/components/stories/context_menu.rs | 0 .../src/components/stories/disclosure.rs | 0 .../src/components/stories/icon.rs | 0 .../src/components/stories/icon_button.rs | 0 .../src/components/stories/keybinding.rs | 0 .../src/components/stories/label.rs | 0 .../src/components/stories/list.rs | 0 .../src/components/stories/list_header.rs | 0 .../src/components/stories/list_item.rs | 0 .../{ui2 => ui}/src/components/stories/tab.rs | 0 .../src/components/stories/tab_bar.rs | 0 .../src/components/stories/toggle_button.rs | 0 crates/{ui2 => ui}/src/components/tab.rs | 0 crates/{ui2 => ui}/src/components/tab_bar.rs | 0 crates/{ui2 => ui}/src/components/tooltip.rs | 0 crates/{ui2 => ui}/src/disableable.rs | 0 crates/{ui2 => ui}/src/fixed.rs | 0 crates/{ui2 => ui}/src/prelude.rs | 0 crates/{ui2 => ui}/src/selectable.rs | 0 crates/{ui2 => ui}/src/styled_ext.rs | 0 crates/{ui2 => ui}/src/styles.rs | 0 crates/{ui2 => ui}/src/styles/color.rs | 0 .../{ui2 => ui}/src/styles/docs/elevation.md | 0 crates/{ui2 => ui}/src/styles/elevation.rs | 0 crates/{ui2 => ui}/src/styles/typography.rs | 0 crates/{ui2 => ui}/src/styles/units.rs | 0 crates/{ui2/src/ui2.rs => ui/src/ui.rs} | 0 crates/{ui2 => ui}/src/utils.rs | 0 .../{ui2 => ui}/src/utils/format_distance.rs | 0 crates/{ui2 => ui}/src/visible_on_hover.rs | 0 crates/vcs_menu/Cargo.toml | 2 +- crates/vim/Cargo.toml | 2 +- crates/welcome/Cargo.toml | 2 +- crates/workspace/Cargo.toml | 2 +- crates/zed/Cargo.toml | 4 +- script/storybook | 4 +- 142 files changed, 106 insertions(+), 5018 deletions(-) rename crates/{storybook2 => storybook}/Cargo.lock (100%) rename crates/{storybook2 => storybook}/Cargo.toml (89%) rename crates/{storybook2 => storybook}/build.rs (100%) rename crates/{storybook2 => storybook}/docs/thoughts.md (100%) rename crates/{storybook2 => storybook}/src/assets.rs (100%) rename crates/{storybook2 => storybook}/src/stories.rs (100%) rename crates/{storybook2 => storybook}/src/stories/auto_height_editor.rs (100%) rename crates/{storybook2 => storybook}/src/stories/cursor.rs (100%) rename crates/{storybook2 => storybook}/src/stories/focus.rs (100%) rename crates/{storybook2 => storybook}/src/stories/kitchen_sink.rs (100%) rename crates/{storybook2 => storybook}/src/stories/overflow_scroll.rs (100%) rename crates/{storybook2 => storybook}/src/stories/picker.rs (100%) rename crates/{storybook2 => storybook}/src/stories/scroll.rs (100%) rename crates/{storybook2 => storybook}/src/stories/text.rs (98%) rename crates/{storybook2 => storybook}/src/stories/viewport_units.rs (100%) rename crates/{storybook2 => storybook}/src/stories/z_index.rs (100%) rename crates/{storybook2 => storybook}/src/story_selector.rs (100%) rename crates/{storybook2/src/storybook2.rs => storybook/src/storybook.rs} (100%) delete mode 100644 crates/terminal2/Cargo.toml delete mode 100644 crates/text2/Cargo.toml delete mode 100644 crates/text2/src/anchor.rs delete mode 100644 crates/text2/src/locator.rs delete mode 100644 crates/text2/src/network.rs delete mode 100644 crates/text2/src/operation_queue.rs delete mode 100644 crates/text2/src/patch.rs delete mode 100644 crates/text2/src/selection.rs delete mode 100644 crates/text2/src/subscription.rs delete mode 100644 crates/text2/src/tests.rs delete mode 100644 crates/text2/src/text2.rs delete mode 100644 crates/text2/src/undo_map.rs rename crates/{ui2 => ui}/Cargo.toml (92%) rename crates/{ui2 => ui}/docs/building-ui.md (100%) rename crates/{ui2 => ui}/docs/hello-world.md (100%) rename crates/{ui2 => ui}/docs/todo.md (100%) rename crates/{ui2 => ui}/src/clickable.rs (100%) rename crates/{ui2 => ui}/src/components.rs (100%) rename crates/{ui2 => ui}/src/components/avatar.rs (100%) rename crates/{ui2 => ui}/src/components/button.rs (100%) rename crates/{ui2 => ui}/src/components/button/button.rs (100%) rename crates/{ui2 => ui}/src/components/button/button_icon.rs (100%) rename crates/{ui2 => ui}/src/components/button/button_like.rs (100%) rename crates/{ui2 => ui}/src/components/button/icon_button.rs (100%) rename crates/{ui2 => ui}/src/components/button/toggle_button.rs (100%) rename crates/{ui2 => ui}/src/components/checkbox.rs (100%) rename crates/{ui2 => ui}/src/components/context_menu.rs (100%) rename crates/{ui2 => ui}/src/components/disclosure.rs (100%) rename crates/{ui2 => ui}/src/components/divider.rs (100%) rename crates/{ui2 => ui}/src/components/icon.rs (100%) rename crates/{ui2 => ui}/src/components/indicator.rs (100%) rename crates/{ui2 => ui}/src/components/keybinding.rs (100%) rename crates/{ui2 => ui}/src/components/label.rs (100%) rename crates/{ui2 => ui}/src/components/label/highlighted_label.rs (100%) rename crates/{ui2 => ui}/src/components/label/label.rs (100%) rename crates/{ui2 => ui}/src/components/label/label_like.rs (100%) rename crates/{ui2 => ui}/src/components/list.rs (100%) rename crates/{ui2 => ui}/src/components/list/list.rs (100%) rename crates/{ui2 => ui}/src/components/list/list_header.rs (100%) rename crates/{ui2 => ui}/src/components/list/list_item.rs (100%) rename crates/{ui2 => ui}/src/components/list/list_separator.rs (100%) rename crates/{ui2 => ui}/src/components/list/list_sub_header.rs (100%) rename crates/{ui2 => ui}/src/components/popover.rs (100%) rename crates/{ui2 => ui}/src/components/popover_menu.rs (100%) rename crates/{ui2 => ui}/src/components/right_click_menu.rs (100%) rename crates/{ui2 => ui}/src/components/stack.rs (100%) rename crates/{ui2 => ui}/src/components/stories.rs (100%) rename crates/{ui2 => ui}/src/components/stories/avatar.rs (100%) rename crates/{ui2 => ui}/src/components/stories/button.rs (100%) rename crates/{ui2 => ui}/src/components/stories/checkbox.rs (100%) rename crates/{ui2 => ui}/src/components/stories/context_menu.rs (100%) rename crates/{ui2 => ui}/src/components/stories/disclosure.rs (100%) rename crates/{ui2 => ui}/src/components/stories/icon.rs (100%) rename crates/{ui2 => ui}/src/components/stories/icon_button.rs (100%) rename crates/{ui2 => ui}/src/components/stories/keybinding.rs (100%) rename crates/{ui2 => ui}/src/components/stories/label.rs (100%) rename crates/{ui2 => ui}/src/components/stories/list.rs (100%) rename crates/{ui2 => ui}/src/components/stories/list_header.rs (100%) rename crates/{ui2 => ui}/src/components/stories/list_item.rs (100%) rename crates/{ui2 => ui}/src/components/stories/tab.rs (100%) rename crates/{ui2 => ui}/src/components/stories/tab_bar.rs (100%) rename crates/{ui2 => ui}/src/components/stories/toggle_button.rs (100%) rename crates/{ui2 => ui}/src/components/tab.rs (100%) rename crates/{ui2 => ui}/src/components/tab_bar.rs (100%) rename crates/{ui2 => ui}/src/components/tooltip.rs (100%) rename crates/{ui2 => ui}/src/disableable.rs (100%) rename crates/{ui2 => ui}/src/fixed.rs (100%) rename crates/{ui2 => ui}/src/prelude.rs (100%) rename crates/{ui2 => ui}/src/selectable.rs (100%) rename crates/{ui2 => ui}/src/styled_ext.rs (100%) rename crates/{ui2 => ui}/src/styles.rs (100%) rename crates/{ui2 => ui}/src/styles/color.rs (100%) rename crates/{ui2 => ui}/src/styles/docs/elevation.md (100%) rename crates/{ui2 => ui}/src/styles/elevation.rs (100%) rename crates/{ui2 => ui}/src/styles/typography.rs (100%) rename crates/{ui2 => ui}/src/styles/units.rs (100%) rename crates/{ui2/src/ui2.rs => ui/src/ui.rs} (100%) rename crates/{ui2 => ui}/src/utils.rs (100%) rename crates/{ui2 => ui}/src/utils/format_distance.rs (100%) rename crates/{ui2 => ui}/src/visible_on_hover.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 0655998814..69673fd367 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,7 +16,7 @@ dependencies = [ "settings", "smallvec", "theme2", - "ui2", + "ui", "util", "workspace", ] @@ -333,7 +333,7 @@ dependencies = [ "smol", "theme2", "tiktoken-rs", - "ui2", + "ui", "util", "uuid 1.4.1", "workspace", @@ -1018,7 +1018,7 @@ dependencies = [ "search", "settings", "theme2", - "ui2", + "ui", "workspace", ] @@ -1217,7 +1217,7 @@ dependencies = [ "smol", "sum_tree", "tempfile", - "text2", + "text", "thiserror", "time", "tiny_http", @@ -1390,7 +1390,7 @@ dependencies = [ "sum_tree", "sysinfo", "tempfile", - "text2", + "text", "thiserror", "time", "tiny_http", @@ -1500,7 +1500,7 @@ dependencies = [ "sha-1 0.9.8", "smallvec", "sqlx", - "text2", + "text", "theme2", "time", "tokio", @@ -1556,7 +1556,7 @@ dependencies = [ "theme_selector", "time", "tree-sitter-markdown", - "ui2", + "ui", "util", "vcs_menu", "workspace", @@ -1612,7 +1612,7 @@ dependencies = [ "serde_json", "settings", "theme2", - "ui2", + "ui", "util", "workspace", "zed_actions", @@ -1714,7 +1714,7 @@ dependencies = [ "settings", "smol", "theme2", - "ui2", + "ui", "util", ] @@ -2242,7 +2242,7 @@ dependencies = [ "settings", "smallvec", "theme2", - "ui2", + "ui", "unindent", "util", "workspace", @@ -2422,13 +2422,13 @@ dependencies = [ "snippet", "sqlez", "sum_tree", - "text2", + "text", "theme2", "tree-sitter", "tree-sitter-html", "tree-sitter-rust", "tree-sitter-typescript", - "ui2", + "ui", "unindent", "util", "workspace", @@ -2638,7 +2638,7 @@ dependencies = [ "sysinfo", "theme2", "tree-sitter-markdown", - "ui2", + "ui", "urlencoding", "util", "workspace", @@ -2662,9 +2662,9 @@ dependencies = [ "serde", "serde_json", "settings", - "text2", + "text", "theme2", - "ui2", + "ui", "util", "workspace", ] @@ -2835,7 +2835,7 @@ dependencies = [ "smol", "sum_tree", "tempfile", - "text2", + "text", "time", "util", ] @@ -3095,7 +3095,7 @@ dependencies = [ "parking_lot 0.11.2", "smol", "sum_tree", - "text2", + "text", "unindent", "util", ] @@ -3154,9 +3154,9 @@ dependencies = [ "postage", "serde", "settings", - "text2", + "text", "theme2", - "ui2", + "ui", "util", "workspace", ] @@ -3960,7 +3960,7 @@ dependencies = [ "smallvec", "smol", "sum_tree", - "text2", + "text", "theme2", "tree-sitter", "tree-sitter-elixir", @@ -3991,7 +3991,7 @@ dependencies = [ "project", "settings", "theme2", - "ui2", + "ui", "util", "workspace", ] @@ -4014,7 +4014,7 @@ dependencies = [ "settings", "theme2", "tree-sitter", - "ui2", + "ui", "unindent", "util", "workspace", @@ -4624,7 +4624,7 @@ dependencies = [ "smol", "snippet", "sum_tree", - "text2", + "text", "theme2", "tree-sitter", "tree-sitter-html", @@ -4798,7 +4798,7 @@ dependencies = [ "rpc", "settings", "sum_tree", - "text2", + "text", "time", "util", ] @@ -5202,9 +5202,9 @@ dependencies = [ "postage", "settings", "smol", - "text2", + "text", "theme2", - "ui2", + "ui", "util", "workspace", ] @@ -5425,7 +5425,7 @@ dependencies = [ "serde_json", "settings", "theme2", - "ui2", + "ui", "util", "workspace", ] @@ -5746,7 +5746,7 @@ dependencies = [ "sum_tree", "tempdir", "terminal", - "text2", + "text", "thiserror", "toml 0.5.11", "unindent", @@ -5777,7 +5777,7 @@ dependencies = [ "settings", "smallvec", "theme2", - "ui2", + "ui", "unicase", "util", "workspace", @@ -5800,7 +5800,7 @@ dependencies = [ "project", "settings", "smol", - "text2", + "text", "theme2", "util", "workspace", @@ -5970,7 +5970,7 @@ dependencies = [ "editor", "gpui2", "search", - "ui2", + "ui", "workspace", ] @@ -6149,9 +6149,9 @@ dependencies = [ "postage", "settings", "smol", - "text2", + "text", "theme2", - "ui2", + "ui", "util", "workspace", ] @@ -6934,7 +6934,7 @@ dependencies = [ "smallvec", "smol", "theme2", - "ui2", + "ui", "unindent", "util", "workspace", @@ -7753,7 +7753,7 @@ dependencies = [ ] [[package]] -name = "storybook2" +name = "storybook" version = "0.1.0" dependencies = [ "anyhow", @@ -7778,7 +7778,7 @@ dependencies = [ "story", "strum", "theme2", - "ui2", + "ui", "util", ] @@ -8115,7 +8115,7 @@ dependencies = [ "terminal", "theme2", "thiserror", - "ui2", + "ui", "util", "workspace", ] @@ -8123,29 +8123,6 @@ dependencies = [ [[package]] name = "text" version = "0.1.0" -dependencies = [ - "anyhow", - "clock", - "collections", - "ctor", - "digest 0.9.0", - "env_logger", - "gpui", - "lazy_static", - "log", - "parking_lot 0.11.2", - "postage", - "rand 0.8.5", - "regex", - "rope", - "smallvec", - "sum_tree", - "util", -] - -[[package]] -name = "text2" -version = "0.1.0" dependencies = [ "anyhow", "clock", @@ -8251,7 +8228,7 @@ dependencies = [ "settings", "smol", "theme2", - "ui2", + "ui", "util", "workspace", ] @@ -9055,7 +9032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] -name = "ui2" +name = "ui" version = "0.1.0" dependencies = [ "anyhow", @@ -9315,7 +9292,7 @@ dependencies = [ "fuzzy", "gpui2", "picker", - "ui2", + "ui", "util", "workspace", ] @@ -9354,7 +9331,7 @@ dependencies = [ "settings", "theme2", "tokio", - "ui2", + "ui", "util", "workspace", "zed_actions", @@ -9767,7 +9744,7 @@ dependencies = [ "settings", "theme2", "theme_selector", - "ui2", + "ui", "util", "vim", "workspace", @@ -10045,7 +10022,7 @@ dependencies = [ "smallvec", "terminal", "theme2", - "ui2", + "ui", "util", "uuid 1.4.1", ] @@ -10212,7 +10189,7 @@ dependencies = [ "sum_tree", "tempdir", "terminal_view", - "text2", + "text", "theme2", "theme_selector", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index b13f7308e2..6b08fe4c55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ members = [ "crates/sqlez", "crates/sqlez_macros", "crates/rich_text", - "crates/storybook2", + "crates/storybook", "crates/sum_tree", "crates/terminal", "crates/terminal_view", @@ -79,7 +79,7 @@ members = [ "crates/theme2", "crates/theme_importer", "crates/theme_selector", - "crates/ui2", + "crates/ui", "crates/util", "crates/story", "crates/vim", diff --git a/crates/activity_indicator/Cargo.toml b/crates/activity_indicator/Cargo.toml index 5f7b8776cd..503a58c587 100644 --- a/crates/activity_indicator/Cargo.toml +++ b/crates/activity_indicator/Cargo.toml @@ -15,7 +15,7 @@ language = { path = "../language" } gpui = { path = "../gpui2", package = "gpui2" } project = { path = "../project" } settings = { path = "../settings" } -ui = { path = "../ui2", package = "ui2" } +ui = { path = "../ui" } util = { path = "../util" } theme = { path = "../theme2", package = "theme2" } workspace = { path = "../workspace", package = "workspace" } diff --git a/crates/assistant/Cargo.toml b/crates/assistant/Cargo.toml index 7429bfc04b..e07fd9676a 100644 --- a/crates/assistant/Cargo.toml +++ b/crates/assistant/Cargo.toml @@ -23,7 +23,7 @@ search = { path = "../search" } semantic_index = { path = "../semantic_index" } settings = { path = "../settings" } theme = { package = "theme2", path = "../theme2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } util = { path = "../util" } workspace = { path = "../workspace" } diff --git a/crates/breadcrumbs/Cargo.toml b/crates/breadcrumbs/Cargo.toml index afe9cf74c9..3227d7ce2a 100644 --- a/crates/breadcrumbs/Cargo.toml +++ b/crates/breadcrumbs/Cargo.toml @@ -12,7 +12,7 @@ doctest = false collections = { path = "../collections" } editor = { path = "../editor" } gpui = { package = "gpui2", path = "../gpui2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } language = { path = "../language" } project = { path = "../project" } search = { path = "../search" } diff --git a/crates/channel/Cargo.toml b/crates/channel/Cargo.toml index 91bfaeb0e4..966c56e351 100644 --- a/crates/channel/Cargo.toml +++ b/crates/channel/Cargo.toml @@ -18,7 +18,7 @@ db = { path = "../db" } gpui = { package = "gpui2", path = "../gpui2" } util = { path = "../util" } rpc = { path = "../rpc" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } language = { path = "../language" } settings = { path = "../settings" } feature_flags = { path = "../feature_flags" } diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index 4f1aab68aa..962fb82ab6 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -18,7 +18,7 @@ db = { path = "../db" } gpui = { package = "gpui2", path = "../gpui2" } util = { path = "../util" } rpc = { path = "../rpc" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } settings = { path = "../settings" } feature_flags = { path = "../feature_flags" } sum_tree = { path = "../sum_tree" } diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index 820968cd00..d4f1abd98e 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -17,7 +17,7 @@ required-features = ["seed-support"] clock = { path = "../clock" } collections = { path = "../collections" } live_kit_server = { path = "../live_kit_server" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } rpc = { path = "../rpc" } util = { path = "../util" } diff --git a/crates/collab_ui/Cargo.toml b/crates/collab_ui/Cargo.toml index a0673b7657..c910a40c77 100644 --- a/crates/collab_ui/Cargo.toml +++ b/crates/collab_ui/Cargo.toml @@ -48,7 +48,7 @@ feature_flags = { path = "../feature_flags"} theme = { package = "theme2", path = "../theme2" } theme_selector = { path = "../theme_selector" } vcs_menu = { path = "../vcs_menu" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } util = { path = "../util" } workspace = { path = "../workspace" } zed_actions = { path = "../zed_actions"} diff --git a/crates/command_palette/Cargo.toml b/crates/command_palette/Cargo.toml index 6b7c2a8b7f..b1223d7c1d 100644 --- a/crates/command_palette/Cargo.toml +++ b/crates/command_palette/Cargo.toml @@ -16,7 +16,7 @@ gpui = { package = "gpui2", path = "../gpui2" } picker = { path = "../picker" } project = { path = "../project" } settings = { path = "../settings" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } util = { path = "../util" } theme = { package = "theme2", path = "../theme2" } workspace = { path = "../workspace" } diff --git a/crates/copilot/Cargo.toml b/crates/copilot/Cargo.toml index cf761eeb33..f60488f1cb 100644 --- a/crates/copilot/Cargo.toml +++ b/crates/copilot/Cargo.toml @@ -28,7 +28,7 @@ theme = { package = "theme2", path = "../theme2" } lsp = { path = "../lsp" } node_runtime = { path = "../node_runtime"} util = { path = "../util" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } async-compression.workspace = true async-tar = "0.4.2" anyhow.workspace = true diff --git a/crates/diagnostics/Cargo.toml b/crates/diagnostics/Cargo.toml index 2c9ad2b6c1..5095cab9af 100644 --- a/crates/diagnostics/Cargo.toml +++ b/crates/diagnostics/Cargo.toml @@ -12,7 +12,7 @@ doctest = false collections = { path = "../collections" } editor = { path = "../editor" } gpui = { package = "gpui2", path = "../gpui2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } language = { path = "../language" } lsp = { path = "../lsp" } project = { path = "../project" } diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index 160bb016f1..ac7655f70a 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -41,9 +41,9 @@ rich_text = { path = "../rich_text" } settings = { path = "../settings" } snippet = { path = "../snippet" } sum_tree = { path = "../sum_tree" } -text = { package="text2", path = "../text2" } +text = { path = "../text" } theme = { package="theme2", path = "../theme2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } util = { path = "../util" } sqlez = { path = "../sqlez" } workspace = { path = "../workspace" } @@ -73,7 +73,7 @@ tree-sitter-typescript = { workspace = true, optional = true } [dev-dependencies] copilot = { path = "../copilot", features = ["test-support"] } -text = { package="text2", path = "../text2", features = ["test-support"] } +text = { path = "../text", features = ["test-support"] } language = { path = "../language", features = ["test-support"] } lsp = { path = "../lsp", features = ["test-support"] } gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] } diff --git a/crates/feedback/Cargo.toml b/crates/feedback/Cargo.toml index 7a550db266..bbda613754 100644 --- a/crates/feedback/Cargo.toml +++ b/crates/feedback/Cargo.toml @@ -21,7 +21,7 @@ project = { path = "../project" } search = { path = "../search" } settings = { path = "../settings" } theme = { package = "theme2", path = "../theme2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } util = { path = "../util" } workspace = { path = "../workspace"} diff --git a/crates/file_finder/Cargo.toml b/crates/file_finder/Cargo.toml index d83035166f..46afb7442a 100644 --- a/crates/file_finder/Cargo.toml +++ b/crates/file_finder/Cargo.toml @@ -17,10 +17,10 @@ menu = { path = "../menu" } picker = { path = "../picker" } project = { path = "../project" } settings = { path = "../settings" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } util = { path = "../util" } theme = { package = "theme2", path = "../theme2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } workspace = { path = "../workspace" } postage.workspace = true serde.workspace = true diff --git a/crates/fs/Cargo.toml b/crates/fs/Cargo.toml index a9c2d13049..13276564d2 100644 --- a/crates/fs/Cargo.toml +++ b/crates/fs/Cargo.toml @@ -10,7 +10,7 @@ path = "src/fs.rs" [dependencies] collections = { path = "../collections" } rope = { path = "../rope" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } util = { path = "../util" } sum_tree = { path = "../sum_tree" } diff --git a/crates/git/Cargo.toml b/crates/git/Cargo.toml index 1fc5da42d7..72668ba766 100644 --- a/crates/git/Cargo.toml +++ b/crates/git/Cargo.toml @@ -12,7 +12,7 @@ anyhow.workspace = true clock = { path = "../clock" } lazy_static.workspace = true sum_tree = { path = "../sum_tree" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } collections = { path = "../collections" } util = { path = "../util" } log.workspace = true diff --git a/crates/go_to_line/Cargo.toml b/crates/go_to_line/Cargo.toml index cbe054ee0a..6e7e6c079d 100644 --- a/crates/go_to_line/Cargo.toml +++ b/crates/go_to_line/Cargo.toml @@ -14,11 +14,11 @@ gpui = { package = "gpui2", path = "../gpui2" } menu = { path = "../menu" } serde.workspace = true settings = { path = "../settings" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } workspace = { path = "../workspace" } postage.workspace = true theme = { package = "theme2", path = "../theme2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } util = { path = "../util" } [dev-dependencies] diff --git a/crates/language/Cargo.toml b/crates/language/Cargo.toml index d4a1f7c6bc..164a84514f 100644 --- a/crates/language/Cargo.toml +++ b/crates/language/Cargo.toml @@ -31,7 +31,7 @@ lsp = { path = "../lsp" } rpc = { path = "../rpc" } settings = { path = "../settings" } sum_tree = { path = "../sum_tree" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } theme = { package = "theme2", path = "../theme2" } util = { path = "../util" } @@ -65,7 +65,7 @@ client = { path = "../client", features = ["test-support"] } collections = { path = "../collections", features = ["test-support"] } gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] } lsp = { path = "../lsp", features = ["test-support"] } -text = { package = "text2", path = "../text2", features = ["test-support"] } +text = { path = "../text", features = ["test-support"] } settings = { path = "../settings", features = ["test-support"] } util = { path = "../util", features = ["test-support"] } ctor.workspace = true diff --git a/crates/language_selector/Cargo.toml b/crates/language_selector/Cargo.toml index b6f309397a..2189aa11d0 100644 --- a/crates/language_selector/Cargo.toml +++ b/crates/language_selector/Cargo.toml @@ -16,7 +16,7 @@ gpui = { package = "gpui2", path = "../gpui2" } picker = { path = "../picker" } project = { path = "../project" } theme = { package = "theme2", path = "../theme2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } settings = { path = "../settings" } util = { path = "../util" } workspace = { path = "../workspace" } diff --git a/crates/language_tools/Cargo.toml b/crates/language_tools/Cargo.toml index d54e128465..217f41f824 100644 --- a/crates/language_tools/Cargo.toml +++ b/crates/language_tools/Cargo.toml @@ -17,7 +17,7 @@ language = { path = "../language" } project = { path = "../project" } workspace = { path = "../workspace" } gpui = { package = "gpui2", path = "../gpui2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } util = { path = "../util" } lsp = { path = "../lsp" } futures.workspace = true diff --git a/crates/multi_buffer/Cargo.toml b/crates/multi_buffer/Cargo.toml index 12867f4fec..3508d75cab 100644 --- a/crates/multi_buffer/Cargo.toml +++ b/crates/multi_buffer/Cargo.toml @@ -31,7 +31,7 @@ rich_text = { path = "../rich_text" } settings = { path = "../settings" } snippet = { path = "../snippet" } sum_tree = { path = "../sum_tree" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } theme = { package = "theme2", path = "../theme2" } util = { path = "../util" } @@ -60,7 +60,7 @@ tree-sitter-typescript = { workspace = true, optional = true } [dev-dependencies] copilot = { path = "../copilot", features = ["test-support"] } -text = { package = "text2", path = "../text2", features = ["test-support"] } +text = { path = "../text", features = ["test-support"] } language = { path = "../language", features = ["test-support"] } lsp = { path = "../lsp", features = ["test-support"] } gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] } diff --git a/crates/notifications/Cargo.toml b/crates/notifications/Cargo.toml index 446ca8ee29..d535d3c6fa 100644 --- a/crates/notifications/Cargo.toml +++ b/crates/notifications/Cargo.toml @@ -27,7 +27,7 @@ gpui = { package = "gpui2", path = "../gpui2" } rpc = { path = "../rpc" } settings = { path = "../settings" } sum_tree = { path = "../sum_tree" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } util = { path = "../util" } anyhow.workspace = true diff --git a/crates/outline/Cargo.toml b/crates/outline/Cargo.toml index ebb8717bc7..afac6a702b 100644 --- a/crates/outline/Cargo.toml +++ b/crates/outline/Cargo.toml @@ -12,11 +12,11 @@ doctest = false editor = { path = "../editor" } fuzzy = { path = "../fuzzy" } gpui = { package = "gpui2", path = "../gpui2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } language = { path = "../language" } picker = { path = "../picker" } settings = { path = "../settings" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } theme = { package = "theme2", path = "../theme2" } workspace = { path = "../workspace" } util = { path = "../util" } diff --git a/crates/picker/Cargo.toml b/crates/picker/Cargo.toml index 8fc10a8115..0b1408881b 100644 --- a/crates/picker/Cargo.toml +++ b/crates/picker/Cargo.toml @@ -10,7 +10,7 @@ doctest = false [dependencies] editor = { path = "../editor" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } gpui = { package = "gpui2", path = "../gpui2" } menu = { path = "../menu" } settings = { path = "../settings" } diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 8b7e27b893..a7cdc50ab1 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -20,7 +20,7 @@ test-support = [ ] [dependencies] -text = { package = "text2", path = "../text2" } +text = { path = "../text" } copilot = { path = "../copilot" } client = { path = "../client" } clock = { path = "../clock" } diff --git a/crates/project_panel/Cargo.toml b/crates/project_panel/Cargo.toml index 6a4e62f6e4..c05e2f83f8 100644 --- a/crates/project_panel/Cargo.toml +++ b/crates/project_panel/Cargo.toml @@ -18,7 +18,7 @@ project = { path = "../project" } search = { path = "../search" } settings = { path = "../settings" } theme = { path = "../theme2", package = "theme2" } -ui = { path = "../ui2", package = "ui2" } +ui = { path = "../ui" } util = { path = "../util" } workspace = { path = "../workspace", package = "workspace" } anyhow.workspace = true diff --git a/crates/project_symbols/Cargo.toml b/crates/project_symbols/Cargo.toml index 26d13abff9..4600bef118 100644 --- a/crates/project_symbols/Cargo.toml +++ b/crates/project_symbols/Cargo.toml @@ -14,7 +14,7 @@ fuzzy = { path = "../fuzzy" } gpui = { package = "gpui2", path = "../gpui2" } picker = { path = "../picker" } project = { path = "../project" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } settings = { path = "../settings" } workspace = { path = "../workspace" } theme = { package = "theme2", path = "../theme2" } diff --git a/crates/quick_action_bar/Cargo.toml b/crates/quick_action_bar/Cargo.toml index d5ec49c0bb..a9d9f215af 100644 --- a/crates/quick_action_bar/Cargo.toml +++ b/crates/quick_action_bar/Cargo.toml @@ -14,7 +14,7 @@ editor = { path = "../editor" } gpui = { package = "gpui2", path = "../gpui2" } search = { path = "../search" } workspace = { path = "../workspace" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } [dev-dependencies] editor = { path = "../editor", features = ["test-support"] } diff --git a/crates/recent_projects/Cargo.toml b/crates/recent_projects/Cargo.toml index ee28ca7724..dcbff6f23e 100644 --- a/crates/recent_projects/Cargo.toml +++ b/crates/recent_projects/Cargo.toml @@ -15,10 +15,10 @@ gpui = { package = "gpui2", path = "../gpui2" } language = { path = "../language" } picker = { path = "../picker" } settings = { path = "../settings" } -text = { package = "text2", path = "../text2" } +text = { path = "../text" } util = { path = "../util"} theme = { package = "theme2", path = "../theme2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } workspace = { path = "../workspace" } futures.workspace = true diff --git a/crates/search/Cargo.toml b/crates/search/Cargo.toml index 7b2743aed3..c48e29bad7 100644 --- a/crates/search/Cargo.toml +++ b/crates/search/Cargo.toml @@ -19,7 +19,7 @@ project = { path = "../project" } settings = { path = "../settings" } theme = { package = "theme2", path = "../theme2" } util = { path = "../util" } -ui = {package = "ui2", path = "../ui2"} +ui = {path = "../ui"} workspace = { path = "../workspace" } semantic_index = { path = "../semantic_index" } anyhow.workspace = true diff --git a/crates/storybook2/Cargo.lock b/crates/storybook/Cargo.lock similarity index 100% rename from crates/storybook2/Cargo.lock rename to crates/storybook/Cargo.lock diff --git a/crates/storybook2/Cargo.toml b/crates/storybook/Cargo.toml similarity index 89% rename from crates/storybook2/Cargo.toml rename to crates/storybook/Cargo.toml index f2e908729a..81b98286ea 100644 --- a/crates/storybook2/Cargo.toml +++ b/crates/storybook/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "storybook2" +name = "storybook" version = "0.1.0" edition = "2021" publish = false [[bin]] name = "storybook" -path = "src/storybook2.rs" +path = "src/storybook.rs" [dependencies] anyhow.workspace = true @@ -31,7 +31,7 @@ story = { path = "../story" } strum = { version = "0.25.0", features = ["derive"] } theme2 = { path = "../theme2" } menu = { path = "../menu" } -ui = { package = "ui2", path = "../ui2", features = ["stories"] } +ui = { path = "../ui", features = ["stories"] } util = { path = "../util" } picker = { path = "../picker" } diff --git a/crates/storybook2/build.rs b/crates/storybook/build.rs similarity index 100% rename from crates/storybook2/build.rs rename to crates/storybook/build.rs diff --git a/crates/storybook2/docs/thoughts.md b/crates/storybook/docs/thoughts.md similarity index 100% rename from crates/storybook2/docs/thoughts.md rename to crates/storybook/docs/thoughts.md diff --git a/crates/storybook2/src/assets.rs b/crates/storybook/src/assets.rs similarity index 100% rename from crates/storybook2/src/assets.rs rename to crates/storybook/src/assets.rs diff --git a/crates/storybook2/src/stories.rs b/crates/storybook/src/stories.rs similarity index 100% rename from crates/storybook2/src/stories.rs rename to crates/storybook/src/stories.rs diff --git a/crates/storybook2/src/stories/auto_height_editor.rs b/crates/storybook/src/stories/auto_height_editor.rs similarity index 100% rename from crates/storybook2/src/stories/auto_height_editor.rs rename to crates/storybook/src/stories/auto_height_editor.rs diff --git a/crates/storybook2/src/stories/cursor.rs b/crates/storybook/src/stories/cursor.rs similarity index 100% rename from crates/storybook2/src/stories/cursor.rs rename to crates/storybook/src/stories/cursor.rs diff --git a/crates/storybook2/src/stories/focus.rs b/crates/storybook/src/stories/focus.rs similarity index 100% rename from crates/storybook2/src/stories/focus.rs rename to crates/storybook/src/stories/focus.rs diff --git a/crates/storybook2/src/stories/kitchen_sink.rs b/crates/storybook/src/stories/kitchen_sink.rs similarity index 100% rename from crates/storybook2/src/stories/kitchen_sink.rs rename to crates/storybook/src/stories/kitchen_sink.rs diff --git a/crates/storybook2/src/stories/overflow_scroll.rs b/crates/storybook/src/stories/overflow_scroll.rs similarity index 100% rename from crates/storybook2/src/stories/overflow_scroll.rs rename to crates/storybook/src/stories/overflow_scroll.rs diff --git a/crates/storybook2/src/stories/picker.rs b/crates/storybook/src/stories/picker.rs similarity index 100% rename from crates/storybook2/src/stories/picker.rs rename to crates/storybook/src/stories/picker.rs diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook/src/stories/scroll.rs similarity index 100% rename from crates/storybook2/src/stories/scroll.rs rename to crates/storybook/src/stories/scroll.rs diff --git a/crates/storybook2/src/stories/text.rs b/crates/storybook/src/stories/text.rs similarity index 98% rename from crates/storybook2/src/stories/text.rs rename to crates/storybook/src/stories/text.rs index 8bf35b04f2..1c302cb48f 100644 --- a/crates/storybook2/src/stories/text.rs +++ b/crates/storybook/src/stories/text.rs @@ -15,7 +15,7 @@ impl TextStory { impl Render for TextStory { fn render(&mut self, cx: &mut gpui::ViewContext) -> impl IntoElement { - StoryContainer::new("Text Story", "crates/storybook2/src/stories/text.rs") + StoryContainer::new("Text Story", "crates/storybook/src/stories/text.rs") .children( vec![ diff --git a/crates/storybook2/src/stories/viewport_units.rs b/crates/storybook/src/stories/viewport_units.rs similarity index 100% rename from crates/storybook2/src/stories/viewport_units.rs rename to crates/storybook/src/stories/viewport_units.rs diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook/src/stories/z_index.rs similarity index 100% rename from crates/storybook2/src/stories/z_index.rs rename to crates/storybook/src/stories/z_index.rs diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook/src/story_selector.rs similarity index 100% rename from crates/storybook2/src/story_selector.rs rename to crates/storybook/src/story_selector.rs diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook/src/storybook.rs similarity index 100% rename from crates/storybook2/src/storybook2.rs rename to crates/storybook/src/storybook.rs diff --git a/crates/terminal2/Cargo.toml b/crates/terminal2/Cargo.toml deleted file mode 100644 index 50fa0b0eff..0000000000 --- a/crates/terminal2/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "terminal" -version = "0.1.0" -edition = "2021" -publish = false - -[lib] -path = "src/terminal.rs" -doctest = false - - -[dependencies] -gpui = { package = "gpui2", path = "../gpui2" } -settings = { path = "../settings" } -db = { path = "../db" } -theme = { package = "theme2", path = "../theme2" } -util = { path = "../util" } - -alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "33306142195b354ef3485ca2b1d8a85dfc6605ca" } -procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "5cd757e5f2eb039ed0c6bb6512223e69d5efc64d", default-features = false } -smallvec.workspace = true -smol.workspace = true -mio-extras = "2.0.6" -futures.workspace = true -ordered-float.workspace = true -itertools = "0.10" -dirs = "4.0.0" -shellexpand = "2.1.0" -libc = "0.2" -anyhow.workspace = true -schemars.workspace = true -thiserror.workspace = true -lazy_static.workspace = true -serde.workspace = true -serde_derive.workspace = true - -[dev-dependencies] -rand.workspace = true diff --git a/crates/terminal_view/Cargo.toml b/crates/terminal_view/Cargo.toml index 23de277ac3..cc059aa259 100644 --- a/crates/terminal_view/Cargo.toml +++ b/crates/terminal_view/Cargo.toml @@ -21,7 +21,7 @@ workspace = { path = "../workspace" } db = { path = "../db" } procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "5cd757e5f2eb039ed0c6bb6512223e69d5efc64d", default-features = false } terminal = { path = "../terminal" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } smallvec.workspace = true smol.workspace = true mio-extras = "2.0.6" diff --git a/crates/text/Cargo.toml b/crates/text/Cargo.toml index d1bc6cc8f8..5a21500b2f 100644 --- a/crates/text/Cargo.toml +++ b/crates/text/Cargo.toml @@ -30,7 +30,7 @@ regex.workspace = true [dev-dependencies] collections = { path = "../collections", features = ["test-support"] } -gpui = { path = "../gpui", features = ["test-support"] } +gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] } util = { path = "../util", features = ["test-support"] } ctor.workspace = true env_logger.workspace = true diff --git a/crates/text/src/locator.rs b/crates/text/src/locator.rs index 07b73ace05..0fb2fa5d16 100644 --- a/crates/text/src/locator.rs +++ b/crates/text/src/locator.rs @@ -20,11 +20,11 @@ impl Locator { } pub fn min_ref() -> &'static Self { - &*MIN + &MIN } pub fn max_ref() -> &'static Self { - &*MAX + &MAX } pub fn assign(&mut self, other: &Self) { diff --git a/crates/text/src/selection.rs b/crates/text/src/selection.rs index 480cb99d74..4f1f9a2922 100644 --- a/crates/text/src/selection.rs +++ b/crates/text/src/selection.rs @@ -5,7 +5,7 @@ use std::ops::Range; #[derive(Copy, Clone, Debug, PartialEq)] pub enum SelectionGoal { None, - HorizontalPosition(f32), + HorizontalPosition(f32), // todo!("Can we use pixels here without adding a runtime gpui dependency?") HorizontalRange { start: f32, end: f32 }, WrappedHorizontalPosition((u32, f32)), } diff --git a/crates/text/src/subscription.rs b/crates/text/src/subscription.rs index b636dfcc92..878e8a2cfe 100644 --- a/crates/text/src/subscription.rs +++ b/crates/text/src/subscription.rs @@ -18,7 +18,7 @@ impl Topic { } pub fn publish(&self, edits: impl Clone + IntoIterator>) { - publish(&mut *self.0.lock(), edits); + publish(&mut self.0.lock(), edits); } pub fn publish_mut(&mut self, edits: impl Clone + IntoIterator>) { diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index c05ea1109c..fd23d3dca4 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -1189,7 +1189,6 @@ impl Buffer { self.undo_or_redo(transaction).log_err() } - #[allow(clippy::needless_collect)] pub fn undo_to_transaction(&mut self, transaction_id: TransactionId) -> Vec { let transactions = self .history @@ -1223,7 +1222,6 @@ impl Buffer { } } - #[allow(clippy::needless_collect)] pub fn redo_to_transaction(&mut self, transaction_id: TransactionId) -> Vec { let transactions = self .history @@ -1536,7 +1534,6 @@ impl Buffer { edits } - #[allow(clippy::type_complexity)] pub fn randomly_edit( &mut self, rng: &mut T, @@ -2655,7 +2652,7 @@ impl LineEnding { max_ix -= 1; } - if let Some(ix) = text[..max_ix].find(&['\n']) { + if let Some(ix) = text[..max_ix].find(['\n']) { if ix > 0 && text.as_bytes()[ix - 1] == b'\r' { Self::Windows } else { diff --git a/crates/text2/Cargo.toml b/crates/text2/Cargo.toml deleted file mode 100644 index 7c12d22adf..0000000000 --- a/crates/text2/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "text2" -version = "0.1.0" -edition = "2021" -publish = false - -[lib] -path = "src/text2.rs" -doctest = false - -[features] -test-support = ["rand"] - -[dependencies] -clock = { path = "../clock" } -collections = { path = "../collections" } -rope = { path = "../rope" } -sum_tree = { path = "../sum_tree" } -util = { path = "../util" } - -anyhow.workspace = true -digest = { version = "0.9", features = ["std"] } -lazy_static.workspace = true -log.workspace = true -parking_lot.workspace = true -postage.workspace = true -rand = { workspace = true, optional = true } -smallvec.workspace = true -regex.workspace = true - -[dev-dependencies] -collections = { path = "../collections", features = ["test-support"] } -gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] } -util = { path = "../util", features = ["test-support"] } -ctor.workspace = true -env_logger.workspace = true -rand.workspace = true diff --git a/crates/text2/src/anchor.rs b/crates/text2/src/anchor.rs deleted file mode 100644 index 084be0e336..0000000000 --- a/crates/text2/src/anchor.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::{ - locator::Locator, BufferSnapshot, Point, PointUtf16, TextDimension, ToOffset, ToPoint, - ToPointUtf16, -}; -use anyhow::Result; -use std::{cmp::Ordering, fmt::Debug, ops::Range}; -use sum_tree::Bias; - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)] -pub struct Anchor { - pub timestamp: clock::Lamport, - pub offset: usize, - pub bias: Bias, - pub buffer_id: Option, -} - -impl Anchor { - pub const MIN: Self = Self { - timestamp: clock::Lamport::MIN, - offset: usize::MIN, - bias: Bias::Left, - buffer_id: None, - }; - - pub const MAX: Self = Self { - timestamp: clock::Lamport::MAX, - offset: usize::MAX, - bias: Bias::Right, - buffer_id: None, - }; - - pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering { - let fragment_id_comparison = if self.timestamp == other.timestamp { - Ordering::Equal - } else { - buffer - .fragment_id_for_anchor(self) - .cmp(buffer.fragment_id_for_anchor(other)) - }; - - fragment_id_comparison - .then_with(|| self.offset.cmp(&other.offset)) - .then_with(|| self.bias.cmp(&other.bias)) - } - - pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self { - if self.cmp(other, buffer).is_le() { - *self - } else { - *other - } - } - - pub fn max(&self, other: &Self, buffer: &BufferSnapshot) -> Self { - if self.cmp(other, buffer).is_ge() { - *self - } else { - *other - } - } - - pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor { - if bias == Bias::Left { - self.bias_left(buffer) - } else { - self.bias_right(buffer) - } - } - - pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor { - if self.bias == Bias::Left { - *self - } else { - buffer.anchor_before(self) - } - } - - pub fn bias_right(&self, buffer: &BufferSnapshot) -> Anchor { - if self.bias == Bias::Right { - *self - } else { - buffer.anchor_after(self) - } - } - - pub fn summary(&self, content: &BufferSnapshot) -> D - where - D: TextDimension, - { - content.summary_for_anchor(self) - } - - /// Returns true when the [Anchor] is located inside a visible fragment. - pub fn is_valid(&self, buffer: &BufferSnapshot) -> bool { - if *self == Anchor::MIN || *self == Anchor::MAX { - true - } else { - let fragment_id = buffer.fragment_id_for_anchor(self); - let mut fragment_cursor = buffer.fragments.cursor::<(Option<&Locator>, usize)>(); - fragment_cursor.seek(&Some(fragment_id), Bias::Left, &None); - fragment_cursor - .item() - .map_or(false, |fragment| fragment.visible) - } - } -} - -pub trait OffsetRangeExt { - fn to_offset(&self, snapshot: &BufferSnapshot) -> Range; - fn to_point(&self, snapshot: &BufferSnapshot) -> Range; - fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range; -} - -impl OffsetRangeExt for Range -where - T: ToOffset, -{ - fn to_offset(&self, snapshot: &BufferSnapshot) -> Range { - self.start.to_offset(snapshot)..self.end.to_offset(snapshot) - } - - fn to_point(&self, snapshot: &BufferSnapshot) -> Range { - self.start.to_offset(snapshot).to_point(snapshot) - ..self.end.to_offset(snapshot).to_point(snapshot) - } - - fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range { - self.start.to_offset(snapshot).to_point_utf16(snapshot) - ..self.end.to_offset(snapshot).to_point_utf16(snapshot) - } -} - -pub trait AnchorRangeExt { - fn cmp(&self, b: &Range, buffer: &BufferSnapshot) -> Result; -} - -impl AnchorRangeExt for Range { - fn cmp(&self, other: &Range, buffer: &BufferSnapshot) -> Result { - Ok(match self.start.cmp(&other.start, buffer) { - Ordering::Equal => other.end.cmp(&self.end, buffer), - ord => ord, - }) - } -} diff --git a/crates/text2/src/locator.rs b/crates/text2/src/locator.rs deleted file mode 100644 index 0fb2fa5d16..0000000000 --- a/crates/text2/src/locator.rs +++ /dev/null @@ -1,125 +0,0 @@ -use lazy_static::lazy_static; -use smallvec::{smallvec, SmallVec}; -use std::iter; - -lazy_static! { - static ref MIN: Locator = Locator::min(); - static ref MAX: Locator = Locator::max(); -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Locator(SmallVec<[u64; 4]>); - -impl Locator { - pub fn min() -> Self { - Self(smallvec![u64::MIN]) - } - - pub fn max() -> Self { - Self(smallvec![u64::MAX]) - } - - pub fn min_ref() -> &'static Self { - &MIN - } - - pub fn max_ref() -> &'static Self { - &MAX - } - - pub fn assign(&mut self, other: &Self) { - self.0.resize(other.0.len(), 0); - self.0.copy_from_slice(&other.0); - } - - pub fn between(lhs: &Self, rhs: &Self) -> Self { - let lhs = lhs.0.iter().copied().chain(iter::repeat(u64::MIN)); - let rhs = rhs.0.iter().copied().chain(iter::repeat(u64::MAX)); - let mut location = SmallVec::new(); - for (lhs, rhs) in lhs.zip(rhs) { - let mid = lhs + ((rhs.saturating_sub(lhs)) >> 48); - location.push(mid); - if mid > lhs { - break; - } - } - Self(location) - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl Default for Locator { - fn default() -> Self { - Self::min() - } -} - -impl sum_tree::Item for Locator { - type Summary = Locator; - - fn summary(&self) -> Self::Summary { - self.clone() - } -} - -impl sum_tree::KeyedItem for Locator { - type Key = Locator; - - fn key(&self) -> Self::Key { - self.clone() - } -} - -impl sum_tree::Summary for Locator { - type Context = (); - - fn add_summary(&mut self, summary: &Self, _: &()) { - self.assign(summary); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use rand::prelude::*; - use std::mem; - - #[gpui::test(iterations = 100)] - fn test_locators(mut rng: StdRng) { - let mut lhs = Default::default(); - let mut rhs = Default::default(); - while lhs == rhs { - lhs = Locator( - (0..rng.gen_range(1..=5)) - .map(|_| rng.gen_range(0..=100)) - .collect(), - ); - rhs = Locator( - (0..rng.gen_range(1..=5)) - .map(|_| rng.gen_range(0..=100)) - .collect(), - ); - } - - if lhs > rhs { - mem::swap(&mut lhs, &mut rhs); - } - - let middle = Locator::between(&lhs, &rhs); - assert!(middle > lhs); - assert!(middle < rhs); - for ix in 0..middle.0.len() - 1 { - assert!( - middle.0[ix] == *lhs.0.get(ix).unwrap_or(&0) - || middle.0[ix] == *rhs.0.get(ix).unwrap_or(&0) - ); - } - } -} diff --git a/crates/text2/src/network.rs b/crates/text2/src/network.rs deleted file mode 100644 index 2f49756ca3..0000000000 --- a/crates/text2/src/network.rs +++ /dev/null @@ -1,69 +0,0 @@ -use clock::ReplicaId; - -pub struct Network { - inboxes: std::collections::BTreeMap>>, - all_messages: Vec, - rng: R, -} - -#[derive(Clone)] -struct Envelope { - message: T, -} - -impl Network { - pub fn new(rng: R) -> Self { - Network { - inboxes: Default::default(), - all_messages: Vec::new(), - rng, - } - } - - pub fn add_peer(&mut self, id: ReplicaId) { - self.inboxes.insert(id, Vec::new()); - } - - pub fn replicate(&mut self, old_replica_id: ReplicaId, new_replica_id: ReplicaId) { - self.inboxes - .insert(new_replica_id, self.inboxes[&old_replica_id].clone()); - } - - pub fn is_idle(&self) -> bool { - self.inboxes.values().all(|i| i.is_empty()) - } - - pub fn broadcast(&mut self, sender: ReplicaId, messages: Vec) { - for (replica, inbox) in self.inboxes.iter_mut() { - if *replica != sender { - for message in &messages { - // Insert one or more duplicates of this message, potentially *before* the previous - // message sent by this peer to simulate out-of-order delivery. - for _ in 0..self.rng.gen_range(1..4) { - let insertion_index = self.rng.gen_range(0..inbox.len() + 1); - inbox.insert( - insertion_index, - Envelope { - message: message.clone(), - }, - ); - } - } - } - } - self.all_messages.extend(messages); - } - - pub fn has_unreceived(&self, receiver: ReplicaId) -> bool { - !self.inboxes[&receiver].is_empty() - } - - pub fn receive(&mut self, receiver: ReplicaId) -> Vec { - let inbox = self.inboxes.get_mut(&receiver).unwrap(); - let count = self.rng.gen_range(0..inbox.len() + 1); - inbox - .drain(0..count) - .map(|envelope| envelope.message) - .collect() - } -} diff --git a/crates/text2/src/operation_queue.rs b/crates/text2/src/operation_queue.rs deleted file mode 100644 index 063f050665..0000000000 --- a/crates/text2/src/operation_queue.rs +++ /dev/null @@ -1,153 +0,0 @@ -use std::{fmt::Debug, ops::Add}; -use sum_tree::{Dimension, Edit, Item, KeyedItem, SumTree, Summary}; - -pub trait Operation: Clone + Debug { - fn lamport_timestamp(&self) -> clock::Lamport; -} - -#[derive(Clone, Debug)] -struct OperationItem(T); - -#[derive(Clone, Debug)] -pub struct OperationQueue(SumTree>); - -#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] -pub struct OperationKey(clock::Lamport); - -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct OperationSummary { - pub key: OperationKey, - pub len: usize, -} - -impl OperationKey { - pub fn new(timestamp: clock::Lamport) -> Self { - Self(timestamp) - } -} - -impl Default for OperationQueue { - fn default() -> Self { - OperationQueue::new() - } -} - -impl OperationQueue { - pub fn new() -> Self { - OperationQueue(SumTree::new()) - } - - pub fn len(&self) -> usize { - self.0.summary().len - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - pub fn insert(&mut self, mut ops: Vec) { - ops.sort_by_key(|op| op.lamport_timestamp()); - ops.dedup_by_key(|op| op.lamport_timestamp()); - self.0.edit( - ops.into_iter() - .map(|op| Edit::Insert(OperationItem(op))) - .collect(), - &(), - ); - } - - pub fn drain(&mut self) -> Self { - let clone = self.clone(); - self.0 = SumTree::new(); - clone - } - - pub fn iter(&self) -> impl Iterator { - self.0.iter().map(|i| &i.0) - } -} - -impl Summary for OperationSummary { - type Context = (); - - fn add_summary(&mut self, other: &Self, _: &()) { - assert!(self.key < other.key); - self.key = other.key; - self.len += other.len; - } -} - -impl<'a> Add<&'a Self> for OperationSummary { - type Output = Self; - - fn add(self, other: &Self) -> Self { - assert!(self.key < other.key); - OperationSummary { - key: other.key, - len: self.len + other.len, - } - } -} - -impl<'a> Dimension<'a, OperationSummary> for OperationKey { - fn add_summary(&mut self, summary: &OperationSummary, _: &()) { - assert!(*self <= summary.key); - *self = summary.key; - } -} - -impl Item for OperationItem { - type Summary = OperationSummary; - - fn summary(&self) -> Self::Summary { - OperationSummary { - key: OperationKey::new(self.0.lamport_timestamp()), - len: 1, - } - } -} - -impl KeyedItem for OperationItem { - type Key = OperationKey; - - fn key(&self) -> Self::Key { - OperationKey::new(self.0.lamport_timestamp()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_len() { - let mut clock = clock::Lamport::new(0); - - let mut queue = OperationQueue::new(); - assert_eq!(queue.len(), 0); - - queue.insert(vec![ - TestOperation(clock.tick()), - TestOperation(clock.tick()), - ]); - assert_eq!(queue.len(), 2); - - queue.insert(vec![TestOperation(clock.tick())]); - assert_eq!(queue.len(), 3); - - drop(queue.drain()); - assert_eq!(queue.len(), 0); - - queue.insert(vec![TestOperation(clock.tick())]); - assert_eq!(queue.len(), 1); - } - - #[derive(Clone, Debug, Eq, PartialEq)] - struct TestOperation(clock::Lamport); - - impl Operation for TestOperation { - fn lamport_timestamp(&self) -> clock::Lamport { - self.0 - } - } -} diff --git a/crates/text2/src/patch.rs b/crates/text2/src/patch.rs deleted file mode 100644 index f10acbc2d3..0000000000 --- a/crates/text2/src/patch.rs +++ /dev/null @@ -1,594 +0,0 @@ -use crate::Edit; -use std::{ - cmp, mem, - ops::{Add, AddAssign, Sub}, -}; - -#[derive(Clone, Default, Debug, PartialEq, Eq)] -pub struct Patch(Vec>); - -impl Patch -where - T: 'static - + Clone - + Copy - + Ord - + Sub - + Add - + AddAssign - + Default - + PartialEq, -{ - pub fn new(edits: Vec>) -> Self { - #[cfg(debug_assertions)] - { - let mut last_edit: Option<&Edit> = None; - for edit in &edits { - if let Some(last_edit) = last_edit { - assert!(edit.old.start > last_edit.old.end); - assert!(edit.new.start > last_edit.new.end); - } - last_edit = Some(edit); - } - } - Self(edits) - } - - pub fn edits(&self) -> &[Edit] { - &self.0 - } - - pub fn into_inner(self) -> Vec> { - self.0 - } - - pub fn compose(&self, new_edits_iter: impl IntoIterator>) -> Self { - let mut old_edits_iter = self.0.iter().cloned().peekable(); - let mut new_edits_iter = new_edits_iter.into_iter().peekable(); - let mut composed = Patch(Vec::new()); - - let mut old_start = T::default(); - let mut new_start = T::default(); - loop { - let old_edit = old_edits_iter.peek_mut(); - let new_edit = new_edits_iter.peek_mut(); - - // Push the old edit if its new end is before the new edit's old start. - if let Some(old_edit) = old_edit.as_ref() { - let new_edit = new_edit.as_ref(); - if new_edit.map_or(true, |new_edit| old_edit.new.end < new_edit.old.start) { - let catchup = old_edit.old.start - old_start; - old_start += catchup; - new_start += catchup; - - let old_end = old_start + old_edit.old_len(); - let new_end = new_start + old_edit.new_len(); - composed.push(Edit { - old: old_start..old_end, - new: new_start..new_end, - }); - old_start = old_end; - new_start = new_end; - old_edits_iter.next(); - continue; - } - } - - // Push the new edit if its old end is before the old edit's new start. - if let Some(new_edit) = new_edit.as_ref() { - let old_edit = old_edit.as_ref(); - if old_edit.map_or(true, |old_edit| new_edit.old.end < old_edit.new.start) { - let catchup = new_edit.new.start - new_start; - old_start += catchup; - new_start += catchup; - - let old_end = old_start + new_edit.old_len(); - let new_end = new_start + new_edit.new_len(); - composed.push(Edit { - old: old_start..old_end, - new: new_start..new_end, - }); - old_start = old_end; - new_start = new_end; - new_edits_iter.next(); - continue; - } - } - - // If we still have edits by this point then they must intersect, so we compose them. - if let Some((old_edit, new_edit)) = old_edit.zip(new_edit) { - if old_edit.new.start < new_edit.old.start { - let catchup = old_edit.old.start - old_start; - old_start += catchup; - new_start += catchup; - - let overshoot = new_edit.old.start - old_edit.new.start; - let old_end = cmp::min(old_start + overshoot, old_edit.old.end); - let new_end = new_start + overshoot; - composed.push(Edit { - old: old_start..old_end, - new: new_start..new_end, - }); - - old_edit.old.start = old_end; - old_edit.new.start += overshoot; - old_start = old_end; - new_start = new_end; - } else { - let catchup = new_edit.new.start - new_start; - old_start += catchup; - new_start += catchup; - - let overshoot = old_edit.new.start - new_edit.old.start; - let old_end = old_start + overshoot; - let new_end = cmp::min(new_start + overshoot, new_edit.new.end); - composed.push(Edit { - old: old_start..old_end, - new: new_start..new_end, - }); - - new_edit.old.start += overshoot; - new_edit.new.start = new_end; - old_start = old_end; - new_start = new_end; - } - - if old_edit.new.end > new_edit.old.end { - let old_end = old_start + cmp::min(old_edit.old_len(), new_edit.old_len()); - let new_end = new_start + new_edit.new_len(); - composed.push(Edit { - old: old_start..old_end, - new: new_start..new_end, - }); - - old_edit.old.start = old_end; - old_edit.new.start = new_edit.old.end; - old_start = old_end; - new_start = new_end; - new_edits_iter.next(); - } else { - let old_end = old_start + old_edit.old_len(); - let new_end = new_start + cmp::min(old_edit.new_len(), new_edit.new_len()); - composed.push(Edit { - old: old_start..old_end, - new: new_start..new_end, - }); - - new_edit.old.start = old_edit.new.end; - new_edit.new.start = new_end; - old_start = old_end; - new_start = new_end; - old_edits_iter.next(); - } - } else { - break; - } - } - - composed - } - - pub fn invert(&mut self) -> &mut Self { - for edit in &mut self.0 { - mem::swap(&mut edit.old, &mut edit.new); - } - self - } - - pub fn clear(&mut self) { - self.0.clear(); - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn push(&mut self, edit: Edit) { - if edit.is_empty() { - return; - } - - if let Some(last) = self.0.last_mut() { - if last.old.end >= edit.old.start { - last.old.end = edit.old.end; - last.new.end = edit.new.end; - } else { - self.0.push(edit); - } - } else { - self.0.push(edit); - } - } - - pub fn old_to_new(&self, old: T) -> T { - let ix = match self.0.binary_search_by(|probe| probe.old.start.cmp(&old)) { - Ok(ix) => ix, - Err(ix) => { - if ix == 0 { - return old; - } else { - ix - 1 - } - } - }; - if let Some(edit) = self.0.get(ix) { - if old >= edit.old.end { - edit.new.end + (old - edit.old.end) - } else { - edit.new.start - } - } else { - old - } - } -} - -impl IntoIterator for Patch { - type Item = Edit; - type IntoIter = std::vec::IntoIter>; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, T: Clone> IntoIterator for &'a Patch { - type Item = Edit; - type IntoIter = std::iter::Cloned>>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter().cloned() - } -} - -impl<'a, T: Clone> IntoIterator for &'a mut Patch { - type Item = Edit; - type IntoIter = std::iter::Cloned>>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter().cloned() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use rand::prelude::*; - use std::env; - - #[gpui::test] - fn test_one_disjoint_edit() { - assert_patch_composition( - Patch(vec![Edit { - old: 1..3, - new: 1..4, - }]), - Patch(vec![Edit { - old: 0..0, - new: 0..4, - }]), - Patch(vec![ - Edit { - old: 0..0, - new: 0..4, - }, - Edit { - old: 1..3, - new: 5..8, - }, - ]), - ); - - assert_patch_composition( - Patch(vec![Edit { - old: 1..3, - new: 1..4, - }]), - Patch(vec![Edit { - old: 5..9, - new: 5..7, - }]), - Patch(vec![ - Edit { - old: 1..3, - new: 1..4, - }, - Edit { - old: 4..8, - new: 5..7, - }, - ]), - ); - } - - #[gpui::test] - fn test_one_overlapping_edit() { - assert_patch_composition( - Patch(vec![Edit { - old: 1..3, - new: 1..4, - }]), - Patch(vec![Edit { - old: 3..5, - new: 3..6, - }]), - Patch(vec![Edit { - old: 1..4, - new: 1..6, - }]), - ); - } - - #[gpui::test] - fn test_two_disjoint_and_overlapping() { - assert_patch_composition( - Patch(vec![ - Edit { - old: 1..3, - new: 1..4, - }, - Edit { - old: 8..12, - new: 9..11, - }, - ]), - Patch(vec![ - Edit { - old: 0..0, - new: 0..4, - }, - Edit { - old: 3..10, - new: 7..9, - }, - ]), - Patch(vec![ - Edit { - old: 0..0, - new: 0..4, - }, - Edit { - old: 1..12, - new: 5..10, - }, - ]), - ); - } - - #[gpui::test] - fn test_two_new_edits_overlapping_one_old_edit() { - assert_patch_composition( - Patch(vec![Edit { - old: 0..0, - new: 0..3, - }]), - Patch(vec![ - Edit { - old: 0..0, - new: 0..1, - }, - Edit { - old: 1..2, - new: 2..2, - }, - ]), - Patch(vec![Edit { - old: 0..0, - new: 0..3, - }]), - ); - - assert_patch_composition( - Patch(vec![Edit { - old: 2..3, - new: 2..4, - }]), - Patch(vec![ - Edit { - old: 0..2, - new: 0..1, - }, - Edit { - old: 3..3, - new: 2..5, - }, - ]), - Patch(vec![Edit { - old: 0..3, - new: 0..6, - }]), - ); - - assert_patch_composition( - Patch(vec![Edit { - old: 0..0, - new: 0..2, - }]), - Patch(vec![ - Edit { - old: 0..0, - new: 0..2, - }, - Edit { - old: 2..5, - new: 4..4, - }, - ]), - Patch(vec![Edit { - old: 0..3, - new: 0..4, - }]), - ); - } - - #[gpui::test] - fn test_two_new_edits_touching_one_old_edit() { - assert_patch_composition( - Patch(vec![ - Edit { - old: 2..3, - new: 2..4, - }, - Edit { - old: 7..7, - new: 8..11, - }, - ]), - Patch(vec![ - Edit { - old: 2..3, - new: 2..2, - }, - Edit { - old: 4..4, - new: 3..4, - }, - ]), - Patch(vec![ - Edit { - old: 2..3, - new: 2..4, - }, - Edit { - old: 7..7, - new: 8..11, - }, - ]), - ); - } - - #[gpui::test] - fn test_old_to_new() { - let patch = Patch(vec![ - Edit { - old: 2..4, - new: 2..4, - }, - Edit { - old: 7..8, - new: 7..11, - }, - ]); - assert_eq!(patch.old_to_new(0), 0); - assert_eq!(patch.old_to_new(1), 1); - assert_eq!(patch.old_to_new(2), 2); - assert_eq!(patch.old_to_new(3), 2); - assert_eq!(patch.old_to_new(4), 4); - assert_eq!(patch.old_to_new(5), 5); - assert_eq!(patch.old_to_new(6), 6); - assert_eq!(patch.old_to_new(7), 7); - assert_eq!(patch.old_to_new(8), 11); - assert_eq!(patch.old_to_new(9), 12); - } - - #[gpui::test(iterations = 100)] - fn test_random_patch_compositions(mut rng: StdRng) { - let operations = env::var("OPERATIONS") - .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) - .unwrap_or(20); - - let initial_chars = (0..rng.gen_range(0..=100)) - .map(|_| rng.gen_range(b'a'..=b'z') as char) - .collect::>(); - log::info!("initial chars: {:?}", initial_chars); - - // Generate two sequential patches - let mut patches = Vec::new(); - let mut expected_chars = initial_chars.clone(); - for i in 0..2 { - log::info!("patch {}:", i); - - let mut delta = 0i32; - let mut last_edit_end = 0; - let mut edits = Vec::new(); - - for _ in 0..operations { - if last_edit_end >= expected_chars.len() { - break; - } - - let end = rng.gen_range(last_edit_end..=expected_chars.len()); - let start = rng.gen_range(last_edit_end..=end); - let old_len = end - start; - - let mut new_len = rng.gen_range(0..=3); - if start == end && new_len == 0 { - new_len += 1; - } - - last_edit_end = start + new_len + 1; - - let new_chars = (0..new_len) - .map(|_| rng.gen_range(b'A'..=b'Z') as char) - .collect::>(); - log::info!( - " editing {:?}: {:?}", - start..end, - new_chars.iter().collect::() - ); - edits.push(Edit { - old: (start as i32 - delta) as u32..(end as i32 - delta) as u32, - new: start as u32..(start + new_len) as u32, - }); - expected_chars.splice(start..end, new_chars); - - delta += new_len as i32 - old_len as i32; - } - - patches.push(Patch(edits)); - } - - log::info!("old patch: {:?}", &patches[0]); - log::info!("new patch: {:?}", &patches[1]); - log::info!("initial chars: {:?}", initial_chars); - log::info!("final chars: {:?}", expected_chars); - - // Compose the patches, and verify that it has the same effect as applying the - // two patches separately. - let composed = patches[0].compose(&patches[1]); - log::info!("composed patch: {:?}", &composed); - - let mut actual_chars = initial_chars; - for edit in composed.0 { - actual_chars.splice( - edit.new.start as usize..edit.new.start as usize + edit.old.len(), - expected_chars[edit.new.start as usize..edit.new.end as usize] - .iter() - .copied(), - ); - } - - assert_eq!(actual_chars, expected_chars); - } - - #[track_caller] - fn assert_patch_composition(old: Patch, new: Patch, composed: Patch) { - let original = ('a'..'z').collect::>(); - let inserted = ('A'..'Z').collect::>(); - - let mut expected = original.clone(); - apply_patch(&mut expected, &old, &inserted); - apply_patch(&mut expected, &new, &inserted); - - let mut actual = original; - apply_patch(&mut actual, &composed, &expected); - assert_eq!( - actual.into_iter().collect::(), - expected.into_iter().collect::(), - "expected patch is incorrect" - ); - - assert_eq!(old.compose(&new), composed); - } - - fn apply_patch(text: &mut Vec, patch: &Patch, new_text: &[char]) { - for edit in patch.0.iter().rev() { - text.splice( - edit.old.start as usize..edit.old.end as usize, - new_text[edit.new.start as usize..edit.new.end as usize] - .iter() - .copied(), - ); - } - } -} diff --git a/crates/text2/src/selection.rs b/crates/text2/src/selection.rs deleted file mode 100644 index 4f1f9a2922..0000000000 --- a/crates/text2/src/selection.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::{Anchor, BufferSnapshot, TextDimension}; -use std::cmp::Ordering; -use std::ops::Range; - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum SelectionGoal { - None, - HorizontalPosition(f32), // todo!("Can we use pixels here without adding a runtime gpui dependency?") - HorizontalRange { start: f32, end: f32 }, - WrappedHorizontalPosition((u32, f32)), -} - -#[derive(Clone, Debug, PartialEq)] -pub struct Selection { - pub id: usize, - pub start: T, - pub end: T, - pub reversed: bool, - pub goal: SelectionGoal, -} - -impl Default for SelectionGoal { - fn default() -> Self { - Self::None - } -} - -impl Selection { - pub fn head(&self) -> T { - if self.reversed { - self.start.clone() - } else { - self.end.clone() - } - } - - pub fn tail(&self) -> T { - if self.reversed { - self.end.clone() - } else { - self.start.clone() - } - } - - pub fn map(&self, f: F) -> Selection - where - F: Fn(T) -> S, - { - Selection:: { - id: self.id, - start: f(self.start.clone()), - end: f(self.end.clone()), - reversed: self.reversed, - goal: self.goal, - } - } - - pub fn collapse_to(&mut self, point: T, new_goal: SelectionGoal) { - self.start = point.clone(); - self.end = point; - self.goal = new_goal; - self.reversed = false; - } -} - -impl Selection { - pub fn is_empty(&self) -> bool { - self.start == self.end - } - - pub fn set_head(&mut self, head: T, new_goal: SelectionGoal) { - if head.cmp(&self.tail()) < Ordering::Equal { - if !self.reversed { - self.end = self.start; - self.reversed = true; - } - self.start = head; - } else { - if self.reversed { - self.start = self.end; - self.reversed = false; - } - self.end = head; - } - self.goal = new_goal; - } - - pub fn range(&self) -> Range { - self.start..self.end - } -} - -impl Selection { - #[cfg(feature = "test-support")] - pub fn from_offset(offset: usize) -> Self { - Selection { - id: 0, - start: offset, - end: offset, - goal: SelectionGoal::None, - reversed: false, - } - } - - pub fn equals(&self, offset_range: &Range) -> bool { - self.start == offset_range.start && self.end == offset_range.end - } -} - -impl Selection { - pub fn resolve<'a, D: 'a + TextDimension>( - &'a self, - snapshot: &'a BufferSnapshot, - ) -> Selection { - Selection { - id: self.id, - start: snapshot.summary_for_anchor(&self.start), - end: snapshot.summary_for_anchor(&self.end), - reversed: self.reversed, - goal: self.goal, - } - } -} diff --git a/crates/text2/src/subscription.rs b/crates/text2/src/subscription.rs deleted file mode 100644 index 878e8a2cfe..0000000000 --- a/crates/text2/src/subscription.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::{Edit, Patch}; -use parking_lot::Mutex; -use std::{ - mem, - sync::{Arc, Weak}, -}; - -#[derive(Default)] -pub struct Topic(Mutex>>>>); - -pub struct Subscription(Arc>>); - -impl Topic { - pub fn subscribe(&mut self) -> Subscription { - let subscription = Subscription(Default::default()); - self.0.get_mut().push(Arc::downgrade(&subscription.0)); - subscription - } - - pub fn publish(&self, edits: impl Clone + IntoIterator>) { - publish(&mut self.0.lock(), edits); - } - - pub fn publish_mut(&mut self, edits: impl Clone + IntoIterator>) { - publish(self.0.get_mut(), edits); - } -} - -impl Subscription { - pub fn consume(&self) -> Patch { - mem::take(&mut *self.0.lock()) - } -} - -fn publish( - subscriptions: &mut Vec>>>, - edits: impl Clone + IntoIterator>, -) { - subscriptions.retain(|subscription| { - if let Some(subscription) = subscription.upgrade() { - let mut patch = subscription.lock(); - *patch = patch.compose(edits.clone()); - true - } else { - false - } - }); -} diff --git a/crates/text2/src/tests.rs b/crates/text2/src/tests.rs deleted file mode 100644 index 7e26e0a296..0000000000 --- a/crates/text2/src/tests.rs +++ /dev/null @@ -1,764 +0,0 @@ -use super::{network::Network, *}; -use clock::ReplicaId; -use rand::prelude::*; -use std::{ - cmp::Ordering, - env, - iter::Iterator, - time::{Duration, Instant}, -}; - -#[cfg(test)] -#[ctor::ctor] -fn init_logger() { - if std::env::var("RUST_LOG").is_ok() { - env_logger::init(); - } -} - -#[test] -fn test_edit() { - let mut buffer = Buffer::new(0, 0, "abc".into()); - assert_eq!(buffer.text(), "abc"); - buffer.edit([(3..3, "def")]); - assert_eq!(buffer.text(), "abcdef"); - buffer.edit([(0..0, "ghi")]); - assert_eq!(buffer.text(), "ghiabcdef"); - buffer.edit([(5..5, "jkl")]); - assert_eq!(buffer.text(), "ghiabjklcdef"); - buffer.edit([(6..7, "")]); - assert_eq!(buffer.text(), "ghiabjlcdef"); - buffer.edit([(4..9, "mno")]); - assert_eq!(buffer.text(), "ghiamnoef"); -} - -#[gpui::test(iterations = 100)] -fn test_random_edits(mut rng: StdRng) { - let operations = env::var("OPERATIONS") - .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) - .unwrap_or(10); - - let reference_string_len = rng.gen_range(0..3); - let mut reference_string = RandomCharIter::new(&mut rng) - .take(reference_string_len) - .collect::(); - let mut buffer = Buffer::new(0, 0, reference_string.clone()); - LineEnding::normalize(&mut reference_string); - - buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200))); - let mut buffer_versions = Vec::new(); - log::info!( - "buffer text {:?}, version: {:?}", - buffer.text(), - buffer.version() - ); - - for _i in 0..operations { - let (edits, _) = buffer.randomly_edit(&mut rng, 5); - for (old_range, new_text) in edits.iter().rev() { - reference_string.replace_range(old_range.clone(), new_text); - } - - assert_eq!(buffer.text(), reference_string); - log::info!( - "buffer text {:?}, version: {:?}", - buffer.text(), - buffer.version() - ); - - if rng.gen_bool(0.25) { - buffer.randomly_undo_redo(&mut rng); - reference_string = buffer.text(); - log::info!( - "buffer text {:?}, version: {:?}", - buffer.text(), - buffer.version() - ); - } - - let range = buffer.random_byte_range(0, &mut rng); - assert_eq!( - buffer.text_summary_for_range::(range.clone()), - TextSummary::from(&reference_string[range]) - ); - - buffer.check_invariants(); - - if rng.gen_bool(0.3) { - buffer_versions.push((buffer.clone(), buffer.subscribe())); - } - } - - for (old_buffer, subscription) in buffer_versions { - let edits = buffer - .edits_since::(&old_buffer.version) - .collect::>(); - - log::info!( - "applying edits since version {:?} to old text: {:?}: {:?}", - old_buffer.version(), - old_buffer.text(), - edits, - ); - - let mut text = old_buffer.visible_text.clone(); - for edit in edits { - let new_text: String = buffer.text_for_range(edit.new.clone()).collect(); - text.replace(edit.new.start..edit.new.start + edit.old.len(), &new_text); - } - assert_eq!(text.to_string(), buffer.text()); - - for _ in 0..5 { - let end_ix = old_buffer.clip_offset(rng.gen_range(0..=old_buffer.len()), Bias::Right); - let start_ix = old_buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); - let range = old_buffer.anchor_before(start_ix)..old_buffer.anchor_after(end_ix); - let mut old_text = old_buffer.text_for_range(range.clone()).collect::(); - let edits = buffer - .edits_since_in_range::(&old_buffer.version, range.clone()) - .collect::>(); - log::info!( - "applying edits since version {:?} to old text in range {:?}: {:?}: {:?}", - old_buffer.version(), - start_ix..end_ix, - old_text, - edits, - ); - - let new_text = buffer.text_for_range(range).collect::(); - for edit in edits { - old_text.replace_range( - edit.new.start..edit.new.start + edit.old_len(), - &new_text[edit.new], - ); - } - assert_eq!(old_text, new_text); - } - - let subscription_edits = subscription.consume(); - log::info!( - "applying subscription edits since version {:?} to old text: {:?}: {:?}", - old_buffer.version(), - old_buffer.text(), - subscription_edits, - ); - - let mut text = old_buffer.visible_text.clone(); - for edit in subscription_edits.into_inner() { - let new_text: String = buffer.text_for_range(edit.new.clone()).collect(); - text.replace(edit.new.start..edit.new.start + edit.old.len(), &new_text); - } - assert_eq!(text.to_string(), buffer.text()); - } -} - -#[test] -fn test_line_endings() { - assert_eq!(LineEnding::detect(&"🍐✅\n".repeat(1000)), LineEnding::Unix); - assert_eq!(LineEnding::detect(&"abcd\n".repeat(1000)), LineEnding::Unix); - assert_eq!( - LineEnding::detect(&"🍐✅\r\n".repeat(1000)), - LineEnding::Windows - ); - assert_eq!( - LineEnding::detect(&"abcd\r\n".repeat(1000)), - LineEnding::Windows - ); - - let mut buffer = Buffer::new(0, 0, "one\r\ntwo\rthree".into()); - assert_eq!(buffer.text(), "one\ntwo\nthree"); - assert_eq!(buffer.line_ending(), LineEnding::Windows); - buffer.check_invariants(); - - buffer.edit([(buffer.len()..buffer.len(), "\r\nfour")]); - buffer.edit([(0..0, "zero\r\n")]); - assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour"); - assert_eq!(buffer.line_ending(), LineEnding::Windows); - buffer.check_invariants(); -} - -#[test] -fn test_line_len() { - let mut buffer = Buffer::new(0, 0, "".into()); - buffer.edit([(0..0, "abcd\nefg\nhij")]); - buffer.edit([(12..12, "kl\nmno")]); - buffer.edit([(18..18, "\npqrs\n")]); - buffer.edit([(18..21, "\nPQ")]); - - assert_eq!(buffer.line_len(0), 4); - assert_eq!(buffer.line_len(1), 3); - assert_eq!(buffer.line_len(2), 5); - assert_eq!(buffer.line_len(3), 3); - assert_eq!(buffer.line_len(4), 4); - assert_eq!(buffer.line_len(5), 0); -} - -#[test] -fn test_common_prefix_at_position() { - let text = "a = str; b = δα"; - let buffer = Buffer::new(0, 0, text.into()); - - let offset1 = offset_after(text, "str"); - let offset2 = offset_after(text, "δα"); - - // the preceding word is a prefix of the suggestion - assert_eq!( - buffer.common_prefix_at(offset1, "string"), - range_of(text, "str"), - ); - // a suffix of the preceding word is a prefix of the suggestion - assert_eq!( - buffer.common_prefix_at(offset1, "tree"), - range_of(text, "tr"), - ); - // the preceding word is a substring of the suggestion, but not a prefix - assert_eq!( - buffer.common_prefix_at(offset1, "astro"), - empty_range_after(text, "str"), - ); - - // prefix matching is case insensitive. - assert_eq!( - buffer.common_prefix_at(offset1, "Strαngε"), - range_of(text, "str"), - ); - assert_eq!( - buffer.common_prefix_at(offset2, "ΔΑΜΝ"), - range_of(text, "δα"), - ); - - fn offset_after(text: &str, part: &str) -> usize { - text.find(part).unwrap() + part.len() - } - - fn empty_range_after(text: &str, part: &str) -> Range { - let offset = offset_after(text, part); - offset..offset - } - - fn range_of(text: &str, part: &str) -> Range { - let start = text.find(part).unwrap(); - start..start + part.len() - } -} - -#[test] -fn test_text_summary_for_range() { - let buffer = Buffer::new(0, 0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz".into()); - assert_eq!( - buffer.text_summary_for_range::(1..3), - TextSummary { - len: 2, - len_utf16: OffsetUtf16(2), - lines: Point::new(1, 0), - first_line_chars: 1, - last_line_chars: 0, - last_line_len_utf16: 0, - longest_row: 0, - longest_row_chars: 1, - } - ); - assert_eq!( - buffer.text_summary_for_range::(1..12), - TextSummary { - len: 11, - len_utf16: OffsetUtf16(11), - lines: Point::new(3, 0), - first_line_chars: 1, - last_line_chars: 0, - last_line_len_utf16: 0, - longest_row: 2, - longest_row_chars: 4, - } - ); - assert_eq!( - buffer.text_summary_for_range::(0..20), - TextSummary { - len: 20, - len_utf16: OffsetUtf16(20), - lines: Point::new(4, 1), - first_line_chars: 2, - last_line_chars: 1, - last_line_len_utf16: 1, - longest_row: 3, - longest_row_chars: 6, - } - ); - assert_eq!( - buffer.text_summary_for_range::(0..22), - TextSummary { - len: 22, - len_utf16: OffsetUtf16(22), - lines: Point::new(4, 3), - first_line_chars: 2, - last_line_chars: 3, - last_line_len_utf16: 3, - longest_row: 3, - longest_row_chars: 6, - } - ); - assert_eq!( - buffer.text_summary_for_range::(7..22), - TextSummary { - len: 15, - len_utf16: OffsetUtf16(15), - lines: Point::new(2, 3), - first_line_chars: 4, - last_line_chars: 3, - last_line_len_utf16: 3, - longest_row: 1, - longest_row_chars: 6, - } - ); -} - -#[test] -fn test_chars_at() { - let mut buffer = Buffer::new(0, 0, "".into()); - buffer.edit([(0..0, "abcd\nefgh\nij")]); - buffer.edit([(12..12, "kl\nmno")]); - buffer.edit([(18..18, "\npqrs")]); - buffer.edit([(18..21, "\nPQ")]); - - let chars = buffer.chars_at(Point::new(0, 0)); - assert_eq!(chars.collect::(), "abcd\nefgh\nijkl\nmno\nPQrs"); - - let chars = buffer.chars_at(Point::new(1, 0)); - assert_eq!(chars.collect::(), "efgh\nijkl\nmno\nPQrs"); - - let chars = buffer.chars_at(Point::new(2, 0)); - assert_eq!(chars.collect::(), "ijkl\nmno\nPQrs"); - - let chars = buffer.chars_at(Point::new(3, 0)); - assert_eq!(chars.collect::(), "mno\nPQrs"); - - let chars = buffer.chars_at(Point::new(4, 0)); - assert_eq!(chars.collect::(), "PQrs"); - - // Regression test: - let mut buffer = Buffer::new(0, 0, "".into()); - buffer.edit([(0..0, "[workspace]\nmembers = [\n \"xray_core\",\n \"xray_server\",\n \"xray_cli\",\n \"xray_wasm\",\n]\n")]); - buffer.edit([(60..60, "\n")]); - - let chars = buffer.chars_at(Point::new(6, 0)); - assert_eq!(chars.collect::(), " \"xray_wasm\",\n]\n"); -} - -#[test] -fn test_anchors() { - let mut buffer = Buffer::new(0, 0, "".into()); - buffer.edit([(0..0, "abc")]); - let left_anchor = buffer.anchor_before(2); - let right_anchor = buffer.anchor_after(2); - - buffer.edit([(1..1, "def\n")]); - assert_eq!(buffer.text(), "adef\nbc"); - assert_eq!(left_anchor.to_offset(&buffer), 6); - assert_eq!(right_anchor.to_offset(&buffer), 6); - assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 }); - assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 1 }); - - buffer.edit([(2..3, "")]); - assert_eq!(buffer.text(), "adf\nbc"); - assert_eq!(left_anchor.to_offset(&buffer), 5); - assert_eq!(right_anchor.to_offset(&buffer), 5); - assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 }); - assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 1 }); - - buffer.edit([(5..5, "ghi\n")]); - assert_eq!(buffer.text(), "adf\nbghi\nc"); - assert_eq!(left_anchor.to_offset(&buffer), 5); - assert_eq!(right_anchor.to_offset(&buffer), 9); - assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 }); - assert_eq!(right_anchor.to_point(&buffer), Point { row: 2, column: 0 }); - - buffer.edit([(7..9, "")]); - assert_eq!(buffer.text(), "adf\nbghc"); - assert_eq!(left_anchor.to_offset(&buffer), 5); - assert_eq!(right_anchor.to_offset(&buffer), 7); - assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 },); - assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 3 }); - - // Ensure anchoring to a point is equivalent to anchoring to an offset. - assert_eq!( - buffer.anchor_before(Point { row: 0, column: 0 }), - buffer.anchor_before(0) - ); - assert_eq!( - buffer.anchor_before(Point { row: 0, column: 1 }), - buffer.anchor_before(1) - ); - assert_eq!( - buffer.anchor_before(Point { row: 0, column: 2 }), - buffer.anchor_before(2) - ); - assert_eq!( - buffer.anchor_before(Point { row: 0, column: 3 }), - buffer.anchor_before(3) - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 0 }), - buffer.anchor_before(4) - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 1 }), - buffer.anchor_before(5) - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 2 }), - buffer.anchor_before(6) - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 3 }), - buffer.anchor_before(7) - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 4 }), - buffer.anchor_before(8) - ); - - // Comparison between anchors. - let anchor_at_offset_0 = buffer.anchor_before(0); - let anchor_at_offset_1 = buffer.anchor_before(1); - let anchor_at_offset_2 = buffer.anchor_before(2); - - assert_eq!( - anchor_at_offset_0.cmp(&anchor_at_offset_0, &buffer), - Ordering::Equal - ); - assert_eq!( - anchor_at_offset_1.cmp(&anchor_at_offset_1, &buffer), - Ordering::Equal - ); - assert_eq!( - anchor_at_offset_2.cmp(&anchor_at_offset_2, &buffer), - Ordering::Equal - ); - - assert_eq!( - anchor_at_offset_0.cmp(&anchor_at_offset_1, &buffer), - Ordering::Less - ); - assert_eq!( - anchor_at_offset_1.cmp(&anchor_at_offset_2, &buffer), - Ordering::Less - ); - assert_eq!( - anchor_at_offset_0.cmp(&anchor_at_offset_2, &buffer), - Ordering::Less - ); - - assert_eq!( - anchor_at_offset_1.cmp(&anchor_at_offset_0, &buffer), - Ordering::Greater - ); - assert_eq!( - anchor_at_offset_2.cmp(&anchor_at_offset_1, &buffer), - Ordering::Greater - ); - assert_eq!( - anchor_at_offset_2.cmp(&anchor_at_offset_0, &buffer), - Ordering::Greater - ); -} - -#[test] -fn test_anchors_at_start_and_end() { - let mut buffer = Buffer::new(0, 0, "".into()); - let before_start_anchor = buffer.anchor_before(0); - let after_end_anchor = buffer.anchor_after(0); - - buffer.edit([(0..0, "abc")]); - assert_eq!(buffer.text(), "abc"); - assert_eq!(before_start_anchor.to_offset(&buffer), 0); - assert_eq!(after_end_anchor.to_offset(&buffer), 3); - - let after_start_anchor = buffer.anchor_after(0); - let before_end_anchor = buffer.anchor_before(3); - - buffer.edit([(3..3, "def")]); - buffer.edit([(0..0, "ghi")]); - assert_eq!(buffer.text(), "ghiabcdef"); - assert_eq!(before_start_anchor.to_offset(&buffer), 0); - assert_eq!(after_start_anchor.to_offset(&buffer), 3); - assert_eq!(before_end_anchor.to_offset(&buffer), 6); - assert_eq!(after_end_anchor.to_offset(&buffer), 9); -} - -#[test] -fn test_undo_redo() { - let mut buffer = Buffer::new(0, 0, "1234".into()); - // Set group interval to zero so as to not group edits in the undo stack. - buffer.set_group_interval(Duration::from_secs(0)); - - buffer.edit([(1..1, "abx")]); - buffer.edit([(3..4, "yzef")]); - buffer.edit([(3..5, "cd")]); - assert_eq!(buffer.text(), "1abcdef234"); - - let entries = buffer.history.undo_stack.clone(); - assert_eq!(entries.len(), 3); - - buffer.undo_or_redo(entries[0].transaction.clone()).unwrap(); - assert_eq!(buffer.text(), "1cdef234"); - buffer.undo_or_redo(entries[0].transaction.clone()).unwrap(); - assert_eq!(buffer.text(), "1abcdef234"); - - buffer.undo_or_redo(entries[1].transaction.clone()).unwrap(); - assert_eq!(buffer.text(), "1abcdx234"); - buffer.undo_or_redo(entries[2].transaction.clone()).unwrap(); - assert_eq!(buffer.text(), "1abx234"); - buffer.undo_or_redo(entries[1].transaction.clone()).unwrap(); - assert_eq!(buffer.text(), "1abyzef234"); - buffer.undo_or_redo(entries[2].transaction.clone()).unwrap(); - assert_eq!(buffer.text(), "1abcdef234"); - - buffer.undo_or_redo(entries[2].transaction.clone()).unwrap(); - assert_eq!(buffer.text(), "1abyzef234"); - buffer.undo_or_redo(entries[0].transaction.clone()).unwrap(); - assert_eq!(buffer.text(), "1yzef234"); - buffer.undo_or_redo(entries[1].transaction.clone()).unwrap(); - assert_eq!(buffer.text(), "1234"); -} - -#[test] -fn test_history() { - let mut now = Instant::now(); - let mut buffer = Buffer::new(0, 0, "123456".into()); - buffer.set_group_interval(Duration::from_millis(300)); - - let transaction_1 = buffer.start_transaction_at(now).unwrap(); - buffer.edit([(2..4, "cd")]); - buffer.end_transaction_at(now); - assert_eq!(buffer.text(), "12cd56"); - - buffer.start_transaction_at(now); - buffer.edit([(4..5, "e")]); - buffer.end_transaction_at(now).unwrap(); - assert_eq!(buffer.text(), "12cde6"); - - now += buffer.transaction_group_interval() + Duration::from_millis(1); - buffer.start_transaction_at(now); - buffer.edit([(0..1, "a")]); - buffer.edit([(1..1, "b")]); - buffer.end_transaction_at(now).unwrap(); - assert_eq!(buffer.text(), "ab2cde6"); - - // Last transaction happened past the group interval, undo it on its own. - buffer.undo(); - assert_eq!(buffer.text(), "12cde6"); - - // First two transactions happened within the group interval, undo them together. - buffer.undo(); - assert_eq!(buffer.text(), "123456"); - - // Redo the first two transactions together. - buffer.redo(); - assert_eq!(buffer.text(), "12cde6"); - - // Redo the last transaction on its own. - buffer.redo(); - assert_eq!(buffer.text(), "ab2cde6"); - - buffer.start_transaction_at(now); - assert!(buffer.end_transaction_at(now).is_none()); - buffer.undo(); - assert_eq!(buffer.text(), "12cde6"); - - // Redo stack gets cleared after performing an edit. - buffer.start_transaction_at(now); - buffer.edit([(0..0, "X")]); - buffer.end_transaction_at(now); - 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"); - - // Transactions can be grouped manually. - buffer.redo(); - buffer.redo(); - assert_eq!(buffer.text(), "X12cde6"); - buffer.group_until_transaction(transaction_1); - buffer.undo(); - assert_eq!(buffer.text(), "123456"); - buffer.redo(); - assert_eq!(buffer.text(), "X12cde6"); -} - -#[test] -fn test_finalize_last_transaction() { - let now = Instant::now(); - let mut buffer = Buffer::new(0, 0, "123456".into()); - - buffer.start_transaction_at(now); - buffer.edit([(2..4, "cd")]); - buffer.end_transaction_at(now); - assert_eq!(buffer.text(), "12cd56"); - - buffer.finalize_last_transaction(); - buffer.start_transaction_at(now); - buffer.edit([(4..5, "e")]); - buffer.end_transaction_at(now).unwrap(); - assert_eq!(buffer.text(), "12cde6"); - - buffer.start_transaction_at(now); - buffer.edit([(0..1, "a")]); - buffer.edit([(1..1, "b")]); - buffer.end_transaction_at(now).unwrap(); - assert_eq!(buffer.text(), "ab2cde6"); - - buffer.undo(); - assert_eq!(buffer.text(), "12cd56"); - - buffer.undo(); - assert_eq!(buffer.text(), "123456"); - - buffer.redo(); - assert_eq!(buffer.text(), "12cd56"); - - buffer.redo(); - assert_eq!(buffer.text(), "ab2cde6"); -} - -#[test] -fn test_edited_ranges_for_transaction() { - let now = Instant::now(); - let mut buffer = Buffer::new(0, 0, "1234567".into()); - - buffer.start_transaction_at(now); - buffer.edit([(2..4, "cd")]); - buffer.edit([(6..6, "efg")]); - buffer.end_transaction_at(now); - assert_eq!(buffer.text(), "12cd56efg7"); - - let tx = buffer.finalize_last_transaction().unwrap().clone(); - assert_eq!( - buffer - .edited_ranges_for_transaction::(&tx) - .collect::>(), - [2..4, 6..9] - ); - - buffer.edit([(5..5, "hijk")]); - assert_eq!(buffer.text(), "12cd5hijk6efg7"); - assert_eq!( - buffer - .edited_ranges_for_transaction::(&tx) - .collect::>(), - [2..4, 10..13] - ); - - buffer.edit([(4..4, "l")]); - assert_eq!(buffer.text(), "12cdl5hijk6efg7"); - assert_eq!( - buffer - .edited_ranges_for_transaction::(&tx) - .collect::>(), - [2..4, 11..14] - ); -} - -#[test] -fn test_concurrent_edits() { - let text = "abcdef"; - - let mut buffer1 = Buffer::new(1, 0, text.into()); - let mut buffer2 = Buffer::new(2, 0, text.into()); - let mut buffer3 = Buffer::new(3, 0, text.into()); - - let buf1_op = buffer1.edit([(1..2, "12")]); - assert_eq!(buffer1.text(), "a12cdef"); - let buf2_op = buffer2.edit([(3..4, "34")]); - assert_eq!(buffer2.text(), "abc34ef"); - let buf3_op = buffer3.edit([(5..6, "56")]); - assert_eq!(buffer3.text(), "abcde56"); - - buffer1.apply_op(buf2_op.clone()).unwrap(); - buffer1.apply_op(buf3_op.clone()).unwrap(); - buffer2.apply_op(buf1_op.clone()).unwrap(); - buffer2.apply_op(buf3_op).unwrap(); - buffer3.apply_op(buf1_op).unwrap(); - buffer3.apply_op(buf2_op).unwrap(); - - assert_eq!(buffer1.text(), "a12c34e56"); - assert_eq!(buffer2.text(), "a12c34e56"); - assert_eq!(buffer3.text(), "a12c34e56"); -} - -#[gpui::test(iterations = 100)] -fn test_random_concurrent_edits(mut rng: StdRng) { - let peers = env::var("PEERS") - .map(|i| i.parse().expect("invalid `PEERS` variable")) - .unwrap_or(5); - let operations = env::var("OPERATIONS") - .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) - .unwrap_or(10); - - let base_text_len = rng.gen_range(0..10); - let base_text = RandomCharIter::new(&mut rng) - .take(base_text_len) - .collect::(); - let mut replica_ids = Vec::new(); - let mut buffers = Vec::new(); - let mut network = Network::new(rng.clone()); - - for i in 0..peers { - let mut buffer = Buffer::new(i as ReplicaId, 0, base_text.clone()); - buffer.history.group_interval = Duration::from_millis(rng.gen_range(0..=200)); - buffers.push(buffer); - replica_ids.push(i as u16); - network.add_peer(i as u16); - } - - log::info!("initial text: {:?}", base_text); - - let mut mutation_count = operations; - loop { - let replica_index = rng.gen_range(0..peers); - let replica_id = replica_ids[replica_index]; - let buffer = &mut buffers[replica_index]; - match rng.gen_range(0..=100) { - 0..=50 if mutation_count != 0 => { - let op = buffer.randomly_edit(&mut rng, 5).1; - network.broadcast(buffer.replica_id, vec![op]); - log::info!("buffer {} text: {:?}", buffer.replica_id, buffer.text()); - mutation_count -= 1; - } - 51..=70 if mutation_count != 0 => { - let ops = buffer.randomly_undo_redo(&mut rng); - network.broadcast(buffer.replica_id, ops); - mutation_count -= 1; - } - 71..=100 if network.has_unreceived(replica_id) => { - let ops = network.receive(replica_id); - if !ops.is_empty() { - log::info!( - "peer {} applying {} ops from the network.", - replica_id, - ops.len() - ); - buffer.apply_ops(ops).unwrap(); - } - } - _ => {} - } - buffer.check_invariants(); - - if mutation_count == 0 && network.is_idle() { - break; - } - } - - let first_buffer = &buffers[0]; - for buffer in &buffers[1..] { - assert_eq!( - buffer.text(), - first_buffer.text(), - "Replica {} text != Replica 0 text", - buffer.replica_id - ); - buffer.check_invariants(); - } -} diff --git a/crates/text2/src/text2.rs b/crates/text2/src/text2.rs deleted file mode 100644 index fd23d3dca4..0000000000 --- a/crates/text2/src/text2.rs +++ /dev/null @@ -1,2679 +0,0 @@ -mod anchor; -pub mod locator; -#[cfg(any(test, feature = "test-support"))] -pub mod network; -pub mod operation_queue; -mod patch; -mod selection; -pub mod subscription; -#[cfg(test)] -mod tests; -mod undo_map; - -pub use anchor::*; -use anyhow::{anyhow, Result}; -pub use clock::ReplicaId; -use collections::{HashMap, HashSet}; -use locator::Locator; -use operation_queue::OperationQueue; -pub use patch::Patch; -use postage::{oneshot, prelude::*}; - -use lazy_static::lazy_static; -use regex::Regex; -pub use rope::*; -pub use selection::*; -use std::{ - borrow::Cow, - cmp::{self, Ordering, Reverse}, - future::Future, - iter::Iterator, - ops::{self, Deref, Range, Sub}, - str, - sync::Arc, - time::{Duration, Instant}, -}; -pub use subscription::*; -pub use sum_tree::Bias; -use sum_tree::{FilterCursor, SumTree, TreeMap}; -use undo_map::UndoMap; -use util::ResultExt; - -#[cfg(any(test, feature = "test-support"))] -use util::RandomCharIter; - -lazy_static! { - static ref LINE_SEPARATORS_REGEX: Regex = Regex::new("\r\n|\r|\u{2028}|\u{2029}").unwrap(); -} - -pub type TransactionId = clock::Lamport; - -pub struct Buffer { - snapshot: BufferSnapshot, - history: History, - deferred_ops: OperationQueue, - deferred_replicas: HashSet, - pub lamport_clock: clock::Lamport, - subscriptions: Topic, - edit_id_resolvers: HashMap>>, - wait_for_version_txs: Vec<(clock::Global, oneshot::Sender<()>)>, -} - -#[derive(Clone)] -pub struct BufferSnapshot { - replica_id: ReplicaId, - remote_id: u64, - visible_text: Rope, - deleted_text: Rope, - line_ending: LineEnding, - undo_map: UndoMap, - fragments: SumTree, - insertions: SumTree, - pub version: clock::Global, -} - -#[derive(Clone, Debug)] -pub struct HistoryEntry { - transaction: Transaction, - first_edit_at: Instant, - last_edit_at: Instant, - suppress_grouping: bool, -} - -#[derive(Clone, Debug)] -pub struct Transaction { - pub id: TransactionId, - pub edit_ids: Vec, - pub start: clock::Global, -} - -impl HistoryEntry { - pub fn transaction_id(&self) -> TransactionId { - self.transaction.id - } -} - -struct History { - base_text: Rope, - operations: TreeMap, - insertion_slices: HashMap>, - undo_stack: Vec, - redo_stack: Vec, - transaction_depth: usize, - group_interval: Duration, -} - -#[derive(Clone, Debug)] -struct InsertionSlice { - insertion_id: clock::Lamport, - range: Range, -} - -impl History { - pub fn new(base_text: Rope) -> Self { - Self { - base_text, - operations: Default::default(), - insertion_slices: Default::default(), - undo_stack: Vec::new(), - redo_stack: Vec::new(), - transaction_depth: 0, - // Don't group transactions in tests unless we opt in, because it's a footgun. - #[cfg(any(test, feature = "test-support"))] - group_interval: Duration::ZERO, - #[cfg(not(any(test, feature = "test-support")))] - group_interval: Duration::from_millis(300), - } - } - - fn push(&mut self, op: Operation) { - self.operations.insert(op.timestamp(), op); - } - - fn start_transaction( - &mut self, - start: clock::Global, - now: Instant, - clock: &mut clock::Lamport, - ) -> Option { - self.transaction_depth += 1; - if self.transaction_depth == 1 { - let id = clock.tick(); - self.undo_stack.push(HistoryEntry { - transaction: Transaction { - id, - start, - edit_ids: Default::default(), - }, - first_edit_at: now, - last_edit_at: now, - suppress_grouping: false, - }); - Some(id) - } else { - None - } - } - - fn end_transaction(&mut self, now: Instant) -> Option<&HistoryEntry> { - assert_ne!(self.transaction_depth, 0); - self.transaction_depth -= 1; - if self.transaction_depth == 0 { - if self - .undo_stack - .last() - .unwrap() - .transaction - .edit_ids - .is_empty() - { - 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) - } - } else { - None - } - } - - fn group(&mut self) -> Option { - let mut count = 0; - let mut entries = self.undo_stack.iter(); - if let Some(mut entry) = entries.next_back() { - while let Some(prev_entry) = entries.next_back() { - if !prev_entry.suppress_grouping - && entry.first_edit_at - prev_entry.last_edit_at <= self.group_interval - { - entry = prev_entry; - count += 1; - } else { - break; - } - } - } - self.group_trailing(count) - } - - fn group_until(&mut self, transaction_id: TransactionId) { - let mut count = 0; - for entry in self.undo_stack.iter().rev() { - if entry.transaction_id() == transaction_id { - self.group_trailing(count); - break; - } else if entry.suppress_grouping { - break; - } else { - count += 1; - } - } - } - - fn group_trailing(&mut self, n: usize) -> Option { - let new_len = self.undo_stack.len() - n; - let (entries_to_keep, entries_to_merge) = self.undo_stack.split_at_mut(new_len); - if let Some(last_entry) = entries_to_keep.last_mut() { - for entry in &*entries_to_merge { - for edit_id in &entry.transaction.edit_ids { - last_entry.transaction.edit_ids.push(*edit_id); - } - } - - if let Some(entry) = entries_to_merge.last_mut() { - last_entry.last_edit_at = entry.last_edit_at; - } - } - - self.undo_stack.truncate(new_len); - self.undo_stack.last().map(|e| e.transaction.id) - } - - fn finalize_last_transaction(&mut self) -> Option<&Transaction> { - self.undo_stack.last_mut().map(|entry| { - entry.suppress_grouping = true; - &entry.transaction - }) - } - - fn push_transaction(&mut self, transaction: Transaction, now: Instant) { - assert_eq!(self.transaction_depth, 0); - self.undo_stack.push(HistoryEntry { - transaction, - first_edit_at: now, - last_edit_at: now, - suppress_grouping: false, - }); - self.redo_stack.clear(); - } - - fn push_undo(&mut self, op_id: clock::Lamport) { - assert_ne!(self.transaction_depth, 0); - if let Some(Operation::Edit(_)) = self.operations.get(&op_id) { - let last_transaction = self.undo_stack.last_mut().unwrap(); - last_transaction.transaction.edit_ids.push(op_id); - } - } - - fn pop_undo(&mut self) -> Option<&HistoryEntry> { - assert_eq!(self.transaction_depth, 0); - if let Some(entry) = self.undo_stack.pop() { - self.redo_stack.push(entry); - self.redo_stack.last() - } else { - None - } - } - - fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&HistoryEntry> { - assert_eq!(self.transaction_depth, 0); - - let entry_ix = self - .undo_stack - .iter() - .rposition(|entry| entry.transaction.id == transaction_id)?; - let entry = self.undo_stack.remove(entry_ix); - self.redo_stack.push(entry); - self.redo_stack.last() - } - - fn remove_from_undo_until(&mut self, transaction_id: TransactionId) -> &[HistoryEntry] { - assert_eq!(self.transaction_depth, 0); - - let redo_stack_start_len = self.redo_stack.len(); - if let Some(entry_ix) = self - .undo_stack - .iter() - .rposition(|entry| entry.transaction.id == transaction_id) - { - self.redo_stack - .extend(self.undo_stack.drain(entry_ix..).rev()); - } - &self.redo_stack[redo_stack_start_len..] - } - - fn forget(&mut self, transaction_id: TransactionId) -> Option { - assert_eq!(self.transaction_depth, 0); - if let Some(entry_ix) = self - .undo_stack - .iter() - .rposition(|entry| entry.transaction.id == transaction_id) - { - Some(self.undo_stack.remove(entry_ix).transaction) - } else if let Some(entry_ix) = self - .redo_stack - .iter() - .rposition(|entry| entry.transaction.id == transaction_id) - { - Some(self.redo_stack.remove(entry_ix).transaction) - } else { - None - } - } - - fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> { - let entry = self - .undo_stack - .iter_mut() - .rfind(|entry| entry.transaction.id == transaction_id) - .or_else(|| { - self.redo_stack - .iter_mut() - .rfind(|entry| entry.transaction.id == transaction_id) - })?; - Some(&mut entry.transaction) - } - - fn merge_transactions(&mut self, transaction: TransactionId, destination: TransactionId) { - if let Some(transaction) = self.forget(transaction) { - if let Some(destination) = self.transaction_mut(destination) { - destination.edit_ids.extend(transaction.edit_ids); - } - } - } - - fn pop_redo(&mut self) -> Option<&HistoryEntry> { - assert_eq!(self.transaction_depth, 0); - if let Some(entry) = self.redo_stack.pop() { - self.undo_stack.push(entry); - self.undo_stack.last() - } else { - None - } - } - - fn remove_from_redo(&mut self, transaction_id: TransactionId) -> &[HistoryEntry] { - assert_eq!(self.transaction_depth, 0); - - let undo_stack_start_len = self.undo_stack.len(); - if let Some(entry_ix) = self - .redo_stack - .iter() - .rposition(|entry| entry.transaction.id == transaction_id) - { - self.undo_stack - .extend(self.redo_stack.drain(entry_ix..).rev()); - } - &self.undo_stack[undo_stack_start_len..] - } -} - -struct Edits<'a, D: TextDimension, F: FnMut(&FragmentSummary) -> bool> { - visible_cursor: rope::Cursor<'a>, - deleted_cursor: rope::Cursor<'a>, - fragments_cursor: Option>, - undos: &'a UndoMap, - since: &'a clock::Global, - old_end: D, - new_end: D, - range: Range<(&'a Locator, usize)>, - buffer_id: u64, -} - -#[derive(Clone, Debug, Default, Eq, PartialEq)] -pub struct Edit { - pub old: Range, - pub new: Range, -} - -impl Edit -where - D: Sub + PartialEq + Copy, -{ - pub fn old_len(&self) -> D { - self.old.end - self.old.start - } - - pub fn new_len(&self) -> D { - self.new.end - self.new.start - } - - pub fn is_empty(&self) -> bool { - self.old.start == self.old.end && self.new.start == self.new.end - } -} - -impl Edit<(D1, D2)> { - pub fn flatten(self) -> (Edit, Edit) { - ( - Edit { - old: self.old.start.0..self.old.end.0, - new: self.new.start.0..self.new.end.0, - }, - Edit { - old: self.old.start.1..self.old.end.1, - new: self.new.start.1..self.new.end.1, - }, - ) - } -} - -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct Fragment { - pub id: Locator, - pub timestamp: clock::Lamport, - pub insertion_offset: usize, - pub len: usize, - pub visible: bool, - pub deletions: HashSet, - pub max_undos: clock::Global, -} - -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct FragmentSummary { - text: FragmentTextSummary, - max_id: Locator, - max_version: clock::Global, - min_insertion_version: clock::Global, - max_insertion_version: clock::Global, -} - -#[derive(Copy, Default, Clone, Debug, PartialEq, Eq)] -struct FragmentTextSummary { - visible: usize, - deleted: usize, -} - -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentTextSummary { - fn add_summary(&mut self, summary: &'a FragmentSummary, _: &Option) { - self.visible += summary.text.visible; - self.deleted += summary.text.deleted; - } -} - -#[derive(Eq, PartialEq, Clone, Debug)] -struct InsertionFragment { - timestamp: clock::Lamport, - split_offset: usize, - fragment_id: Locator, -} - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] -struct InsertionFragmentKey { - timestamp: clock::Lamport, - split_offset: usize, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum Operation { - Edit(EditOperation), - Undo(UndoOperation), -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EditOperation { - pub timestamp: clock::Lamport, - pub version: clock::Global, - pub ranges: Vec>, - pub new_text: Vec>, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UndoOperation { - pub timestamp: clock::Lamport, - pub version: clock::Global, - pub counts: HashMap, -} - -impl Buffer { - pub fn new(replica_id: u16, remote_id: u64, mut base_text: String) -> Buffer { - let line_ending = LineEnding::detect(&base_text); - LineEnding::normalize(&mut base_text); - - let history = History::new(Rope::from(base_text.as_ref())); - let mut fragments = SumTree::new(); - let mut insertions = SumTree::new(); - - let mut lamport_clock = clock::Lamport::new(replica_id); - let mut version = clock::Global::new(); - - let visible_text = history.base_text.clone(); - if !visible_text.is_empty() { - let insertion_timestamp = clock::Lamport { - replica_id: 0, - value: 1, - }; - lamport_clock.observe(insertion_timestamp); - version.observe(insertion_timestamp); - let fragment_id = Locator::between(&Locator::min(), &Locator::max()); - let fragment = Fragment { - id: fragment_id, - timestamp: insertion_timestamp, - insertion_offset: 0, - len: visible_text.len(), - visible: true, - deletions: Default::default(), - max_undos: Default::default(), - }; - insertions.push(InsertionFragment::new(&fragment), &()); - fragments.push(fragment, &None); - } - - Buffer { - snapshot: BufferSnapshot { - replica_id, - remote_id, - visible_text, - deleted_text: Rope::new(), - line_ending, - fragments, - insertions, - version, - undo_map: Default::default(), - }, - history, - deferred_ops: OperationQueue::new(), - deferred_replicas: HashSet::default(), - lamport_clock, - subscriptions: Default::default(), - edit_id_resolvers: Default::default(), - wait_for_version_txs: Default::default(), - } - } - - pub fn version(&self) -> clock::Global { - self.version.clone() - } - - pub fn snapshot(&self) -> BufferSnapshot { - self.snapshot.clone() - } - - pub fn replica_id(&self) -> ReplicaId { - self.lamport_clock.replica_id - } - - pub fn remote_id(&self) -> u64 { - self.remote_id - } - - pub fn deferred_ops_len(&self) -> usize { - self.deferred_ops.len() - } - - pub fn transaction_group_interval(&self) -> Duration { - self.history.group_interval - } - - pub fn edit(&mut self, edits: R) -> Operation - where - R: IntoIterator, - I: ExactSizeIterator, T)>, - S: ToOffset, - T: Into>, - { - let edits = edits - .into_iter() - .map(|(range, new_text)| (range, new_text.into())); - - self.start_transaction(); - let timestamp = self.lamport_clock.tick(); - let operation = Operation::Edit(self.apply_local_edit(edits, timestamp)); - - self.history.push(operation.clone()); - self.history.push_undo(operation.timestamp()); - self.snapshot.version.observe(operation.timestamp()); - self.end_transaction(); - operation - } - - fn apply_local_edit>>( - &mut self, - edits: impl ExactSizeIterator, T)>, - timestamp: clock::Lamport, - ) -> EditOperation { - let mut edits_patch = Patch::default(); - let mut edit_op = EditOperation { - timestamp, - version: self.version(), - ranges: Vec::with_capacity(edits.len()), - new_text: Vec::with_capacity(edits.len()), - }; - let mut new_insertions = Vec::new(); - let mut insertion_offset = 0; - let mut insertion_slices = Vec::new(); - - let mut edits = edits - .map(|(range, new_text)| (range.to_offset(&*self), new_text)) - .peekable(); - - let mut new_ropes = - RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0)); - let mut old_fragments = self.fragments.cursor::(); - let mut new_fragments = - old_fragments.slice(&edits.peek().unwrap().0.start, Bias::Right, &None); - new_ropes.append(new_fragments.summary().text); - - let mut fragment_start = old_fragments.start().visible; - for (range, new_text) in edits { - let new_text = LineEnding::normalize_arc(new_text.into()); - let fragment_end = old_fragments.end(&None).visible; - - // If the current fragment ends before this range, then jump ahead to the first fragment - // that extends past the start of this range, reusing any intervening fragments. - if fragment_end < range.start { - // If the current fragment has been partially consumed, then consume the rest of it - // and advance to the next fragment before slicing. - if fragment_start > old_fragments.start().visible { - if fragment_end > fragment_start { - let mut suffix = old_fragments.item().unwrap().clone(); - suffix.len = fragment_end - fragment_start; - suffix.insertion_offset += fragment_start - old_fragments.start().visible; - new_insertions.push(InsertionFragment::insert_new(&suffix)); - new_ropes.push_fragment(&suffix, suffix.visible); - new_fragments.push(suffix, &None); - } - old_fragments.next(&None); - } - - let slice = old_fragments.slice(&range.start, Bias::Right, &None); - new_ropes.append(slice.summary().text); - new_fragments.append(slice, &None); - fragment_start = old_fragments.start().visible; - } - - let full_range_start = FullOffset(range.start + old_fragments.start().deleted); - - // Preserve any portion of the current fragment that precedes this range. - if fragment_start < range.start { - let mut prefix = old_fragments.item().unwrap().clone(); - prefix.len = range.start - fragment_start; - prefix.insertion_offset += fragment_start - old_fragments.start().visible; - prefix.id = Locator::between(&new_fragments.summary().max_id, &prefix.id); - new_insertions.push(InsertionFragment::insert_new(&prefix)); - new_ropes.push_fragment(&prefix, prefix.visible); - new_fragments.push(prefix, &None); - fragment_start = range.start; - } - - // Insert the new text before any existing fragments within the range. - if !new_text.is_empty() { - let new_start = new_fragments.summary().text.visible; - - let fragment = Fragment { - id: Locator::between( - &new_fragments.summary().max_id, - old_fragments - .item() - .map_or(&Locator::max(), |old_fragment| &old_fragment.id), - ), - timestamp, - insertion_offset, - len: new_text.len(), - deletions: Default::default(), - max_undos: Default::default(), - visible: true, - }; - edits_patch.push(Edit { - old: fragment_start..fragment_start, - new: new_start..new_start + new_text.len(), - }); - insertion_slices.push(fragment.insertion_slice()); - new_insertions.push(InsertionFragment::insert_new(&fragment)); - new_ropes.push_str(new_text.as_ref()); - new_fragments.push(fragment, &None); - insertion_offset += new_text.len(); - } - - // Advance through every fragment that intersects this range, marking the intersecting - // portions as deleted. - while fragment_start < range.end { - let fragment = old_fragments.item().unwrap(); - let fragment_end = old_fragments.end(&None).visible; - let mut intersection = fragment.clone(); - let intersection_end = cmp::min(range.end, fragment_end); - if fragment.visible { - intersection.len = intersection_end - fragment_start; - intersection.insertion_offset += fragment_start - old_fragments.start().visible; - intersection.id = - Locator::between(&new_fragments.summary().max_id, &intersection.id); - intersection.deletions.insert(timestamp); - intersection.visible = false; - } - if intersection.len > 0 { - if fragment.visible && !intersection.visible { - let new_start = new_fragments.summary().text.visible; - edits_patch.push(Edit { - old: fragment_start..intersection_end, - new: new_start..new_start, - }); - insertion_slices.push(intersection.insertion_slice()); - } - new_insertions.push(InsertionFragment::insert_new(&intersection)); - new_ropes.push_fragment(&intersection, fragment.visible); - new_fragments.push(intersection, &None); - fragment_start = intersection_end; - } - if fragment_end <= range.end { - old_fragments.next(&None); - } - } - - let full_range_end = FullOffset(range.end + old_fragments.start().deleted); - edit_op.ranges.push(full_range_start..full_range_end); - edit_op.new_text.push(new_text); - } - - // If the current fragment has been partially consumed, then consume the rest of it - // and advance to the next fragment before slicing. - if fragment_start > old_fragments.start().visible { - let fragment_end = old_fragments.end(&None).visible; - if fragment_end > fragment_start { - let mut suffix = old_fragments.item().unwrap().clone(); - suffix.len = fragment_end - fragment_start; - suffix.insertion_offset += fragment_start - old_fragments.start().visible; - new_insertions.push(InsertionFragment::insert_new(&suffix)); - new_ropes.push_fragment(&suffix, suffix.visible); - new_fragments.push(suffix, &None); - } - old_fragments.next(&None); - } - - let suffix = old_fragments.suffix(&None); - new_ropes.append(suffix.summary().text); - new_fragments.append(suffix, &None); - let (visible_text, deleted_text) = new_ropes.finish(); - drop(old_fragments); - - self.snapshot.fragments = new_fragments; - self.snapshot.insertions.edit(new_insertions, &()); - self.snapshot.visible_text = visible_text; - self.snapshot.deleted_text = deleted_text; - self.subscriptions.publish_mut(&edits_patch); - self.history - .insertion_slices - .insert(timestamp, insertion_slices); - edit_op - } - - pub fn set_line_ending(&mut self, line_ending: LineEnding) { - self.snapshot.line_ending = line_ending; - } - - pub fn apply_ops>(&mut self, ops: I) -> Result<()> { - let mut deferred_ops = Vec::new(); - for op in ops { - self.history.push(op.clone()); - if self.can_apply_op(&op) { - self.apply_op(op)?; - } else { - self.deferred_replicas.insert(op.replica_id()); - deferred_ops.push(op); - } - } - self.deferred_ops.insert(deferred_ops); - self.flush_deferred_ops()?; - Ok(()) - } - - fn apply_op(&mut self, op: Operation) -> Result<()> { - match op { - Operation::Edit(edit) => { - if !self.version.observed(edit.timestamp) { - self.apply_remote_edit( - &edit.version, - &edit.ranges, - &edit.new_text, - edit.timestamp, - ); - self.snapshot.version.observe(edit.timestamp); - self.lamport_clock.observe(edit.timestamp); - self.resolve_edit(edit.timestamp); - } - } - Operation::Undo(undo) => { - if !self.version.observed(undo.timestamp) { - self.apply_undo(&undo)?; - self.snapshot.version.observe(undo.timestamp); - self.lamport_clock.observe(undo.timestamp); - } - } - } - self.wait_for_version_txs.retain_mut(|(version, tx)| { - if self.snapshot.version().observed_all(version) { - tx.try_send(()).ok(); - false - } else { - true - } - }); - Ok(()) - } - - fn apply_remote_edit( - &mut self, - version: &clock::Global, - ranges: &[Range], - new_text: &[Arc], - timestamp: clock::Lamport, - ) { - if ranges.is_empty() { - return; - } - - let edits = ranges.iter().zip(new_text.iter()); - let mut edits_patch = Patch::default(); - let mut insertion_slices = Vec::new(); - let cx = Some(version.clone()); - let mut new_insertions = Vec::new(); - let mut insertion_offset = 0; - let mut new_ropes = - RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0)); - let mut old_fragments = self.fragments.cursor::<(VersionedFullOffset, usize)>(); - let mut new_fragments = old_fragments.slice( - &VersionedFullOffset::Offset(ranges[0].start), - Bias::Left, - &cx, - ); - new_ropes.append(new_fragments.summary().text); - - let mut fragment_start = old_fragments.start().0.full_offset(); - for (range, new_text) in edits { - let fragment_end = old_fragments.end(&cx).0.full_offset(); - - // If the current fragment ends before this range, then jump ahead to the first fragment - // that extends past the start of this range, reusing any intervening fragments. - if fragment_end < range.start { - // If the current fragment has been partially consumed, then consume the rest of it - // and advance to the next fragment before slicing. - if fragment_start > old_fragments.start().0.full_offset() { - if fragment_end > fragment_start { - let mut suffix = old_fragments.item().unwrap().clone(); - suffix.len = fragment_end.0 - fragment_start.0; - suffix.insertion_offset += - fragment_start - old_fragments.start().0.full_offset(); - new_insertions.push(InsertionFragment::insert_new(&suffix)); - new_ropes.push_fragment(&suffix, suffix.visible); - new_fragments.push(suffix, &None); - } - old_fragments.next(&cx); - } - - let slice = - old_fragments.slice(&VersionedFullOffset::Offset(range.start), Bias::Left, &cx); - new_ropes.append(slice.summary().text); - new_fragments.append(slice, &None); - fragment_start = old_fragments.start().0.full_offset(); - } - - // If we are at the end of a non-concurrent fragment, advance to the next one. - let fragment_end = old_fragments.end(&cx).0.full_offset(); - if fragment_end == range.start && fragment_end > fragment_start { - let mut fragment = old_fragments.item().unwrap().clone(); - fragment.len = fragment_end.0 - fragment_start.0; - fragment.insertion_offset += fragment_start - old_fragments.start().0.full_offset(); - new_insertions.push(InsertionFragment::insert_new(&fragment)); - new_ropes.push_fragment(&fragment, fragment.visible); - new_fragments.push(fragment, &None); - old_fragments.next(&cx); - fragment_start = old_fragments.start().0.full_offset(); - } - - // Skip over insertions that are concurrent to this edit, but have a lower lamport - // timestamp. - while let Some(fragment) = old_fragments.item() { - if fragment_start == range.start && fragment.timestamp > timestamp { - new_ropes.push_fragment(fragment, fragment.visible); - new_fragments.push(fragment.clone(), &None); - old_fragments.next(&cx); - debug_assert_eq!(fragment_start, range.start); - } else { - break; - } - } - debug_assert!(fragment_start <= range.start); - - // Preserve any portion of the current fragment that precedes this range. - if fragment_start < range.start { - let mut prefix = old_fragments.item().unwrap().clone(); - prefix.len = range.start.0 - fragment_start.0; - prefix.insertion_offset += fragment_start - old_fragments.start().0.full_offset(); - prefix.id = Locator::between(&new_fragments.summary().max_id, &prefix.id); - new_insertions.push(InsertionFragment::insert_new(&prefix)); - fragment_start = range.start; - new_ropes.push_fragment(&prefix, prefix.visible); - new_fragments.push(prefix, &None); - } - - // Insert the new text before any existing fragments within the range. - if !new_text.is_empty() { - let mut old_start = old_fragments.start().1; - if old_fragments.item().map_or(false, |f| f.visible) { - old_start += fragment_start.0 - old_fragments.start().0.full_offset().0; - } - let new_start = new_fragments.summary().text.visible; - let fragment = Fragment { - id: Locator::between( - &new_fragments.summary().max_id, - old_fragments - .item() - .map_or(&Locator::max(), |old_fragment| &old_fragment.id), - ), - timestamp, - insertion_offset, - len: new_text.len(), - deletions: Default::default(), - max_undos: Default::default(), - visible: true, - }; - edits_patch.push(Edit { - old: old_start..old_start, - new: new_start..new_start + new_text.len(), - }); - insertion_slices.push(fragment.insertion_slice()); - new_insertions.push(InsertionFragment::insert_new(&fragment)); - new_ropes.push_str(new_text); - new_fragments.push(fragment, &None); - insertion_offset += new_text.len(); - } - - // Advance through every fragment that intersects this range, marking the intersecting - // portions as deleted. - while fragment_start < range.end { - let fragment = old_fragments.item().unwrap(); - let fragment_end = old_fragments.end(&cx).0.full_offset(); - let mut intersection = fragment.clone(); - let intersection_end = cmp::min(range.end, fragment_end); - if fragment.was_visible(version, &self.undo_map) { - intersection.len = intersection_end.0 - fragment_start.0; - intersection.insertion_offset += - fragment_start - old_fragments.start().0.full_offset(); - intersection.id = - Locator::between(&new_fragments.summary().max_id, &intersection.id); - intersection.deletions.insert(timestamp); - intersection.visible = false; - insertion_slices.push(intersection.insertion_slice()); - } - if intersection.len > 0 { - if fragment.visible && !intersection.visible { - let old_start = old_fragments.start().1 - + (fragment_start.0 - old_fragments.start().0.full_offset().0); - let new_start = new_fragments.summary().text.visible; - edits_patch.push(Edit { - old: old_start..old_start + intersection.len, - new: new_start..new_start, - }); - } - new_insertions.push(InsertionFragment::insert_new(&intersection)); - new_ropes.push_fragment(&intersection, fragment.visible); - new_fragments.push(intersection, &None); - fragment_start = intersection_end; - } - if fragment_end <= range.end { - old_fragments.next(&cx); - } - } - } - - // If the current fragment has been partially consumed, then consume the rest of it - // and advance to the next fragment before slicing. - if fragment_start > old_fragments.start().0.full_offset() { - let fragment_end = old_fragments.end(&cx).0.full_offset(); - if fragment_end > fragment_start { - let mut suffix = old_fragments.item().unwrap().clone(); - suffix.len = fragment_end.0 - fragment_start.0; - suffix.insertion_offset += fragment_start - old_fragments.start().0.full_offset(); - new_insertions.push(InsertionFragment::insert_new(&suffix)); - new_ropes.push_fragment(&suffix, suffix.visible); - new_fragments.push(suffix, &None); - } - old_fragments.next(&cx); - } - - let suffix = old_fragments.suffix(&cx); - new_ropes.append(suffix.summary().text); - new_fragments.append(suffix, &None); - let (visible_text, deleted_text) = new_ropes.finish(); - drop(old_fragments); - - self.snapshot.fragments = new_fragments; - self.snapshot.visible_text = visible_text; - self.snapshot.deleted_text = deleted_text; - self.snapshot.insertions.edit(new_insertions, &()); - self.history - .insertion_slices - .insert(timestamp, insertion_slices); - self.subscriptions.publish_mut(&edits_patch) - } - - fn fragment_ids_for_edits<'a>( - &'a self, - edit_ids: impl Iterator, - ) -> Vec<&'a Locator> { - // Get all of the insertion slices changed by the given edits. - let mut insertion_slices = Vec::new(); - for edit_id in edit_ids { - if let Some(slices) = self.history.insertion_slices.get(edit_id) { - insertion_slices.extend_from_slice(slices) - } - } - insertion_slices - .sort_unstable_by_key(|s| (s.insertion_id, s.range.start, Reverse(s.range.end))); - - // Get all of the fragments corresponding to these insertion slices. - let mut fragment_ids = Vec::new(); - let mut insertions_cursor = self.insertions.cursor::(); - for insertion_slice in &insertion_slices { - if insertion_slice.insertion_id != insertions_cursor.start().timestamp - || insertion_slice.range.start > insertions_cursor.start().split_offset - { - insertions_cursor.seek_forward( - &InsertionFragmentKey { - timestamp: insertion_slice.insertion_id, - split_offset: insertion_slice.range.start, - }, - Bias::Left, - &(), - ); - } - while let Some(item) = insertions_cursor.item() { - if item.timestamp != insertion_slice.insertion_id - || item.split_offset >= insertion_slice.range.end - { - break; - } - fragment_ids.push(&item.fragment_id); - insertions_cursor.next(&()); - } - } - fragment_ids.sort_unstable(); - fragment_ids - } - - fn apply_undo(&mut self, undo: &UndoOperation) -> Result<()> { - self.snapshot.undo_map.insert(undo); - - let mut edits = Patch::default(); - let mut old_fragments = self.fragments.cursor::<(Option<&Locator>, usize)>(); - let mut new_fragments = SumTree::new(); - let mut new_ropes = - RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0)); - - for fragment_id in self.fragment_ids_for_edits(undo.counts.keys()) { - let preceding_fragments = old_fragments.slice(&Some(fragment_id), Bias::Left, &None); - new_ropes.append(preceding_fragments.summary().text); - new_fragments.append(preceding_fragments, &None); - - if let Some(fragment) = old_fragments.item() { - let mut fragment = fragment.clone(); - let fragment_was_visible = fragment.visible; - - fragment.visible = fragment.is_visible(&self.undo_map); - fragment.max_undos.observe(undo.timestamp); - - let old_start = old_fragments.start().1; - let new_start = new_fragments.summary().text.visible; - if fragment_was_visible && !fragment.visible { - edits.push(Edit { - old: old_start..old_start + fragment.len, - new: new_start..new_start, - }); - } else if !fragment_was_visible && fragment.visible { - edits.push(Edit { - old: old_start..old_start, - new: new_start..new_start + fragment.len, - }); - } - new_ropes.push_fragment(&fragment, fragment_was_visible); - new_fragments.push(fragment, &None); - - old_fragments.next(&None); - } - } - - let suffix = old_fragments.suffix(&None); - new_ropes.append(suffix.summary().text); - new_fragments.append(suffix, &None); - - drop(old_fragments); - let (visible_text, deleted_text) = new_ropes.finish(); - self.snapshot.fragments = new_fragments; - self.snapshot.visible_text = visible_text; - self.snapshot.deleted_text = deleted_text; - self.subscriptions.publish_mut(&edits); - Ok(()) - } - - fn flush_deferred_ops(&mut self) -> Result<()> { - self.deferred_replicas.clear(); - let mut deferred_ops = Vec::new(); - for op in self.deferred_ops.drain().iter().cloned() { - if self.can_apply_op(&op) { - self.apply_op(op)?; - } else { - self.deferred_replicas.insert(op.replica_id()); - deferred_ops.push(op); - } - } - self.deferred_ops.insert(deferred_ops); - Ok(()) - } - - fn can_apply_op(&self, op: &Operation) -> bool { - if self.deferred_replicas.contains(&op.replica_id()) { - false - } else { - self.version.observed_all(match op { - Operation::Edit(edit) => &edit.version, - Operation::Undo(undo) => &undo.version, - }) - } - } - - pub fn peek_undo_stack(&self) -> Option<&HistoryEntry> { - self.history.undo_stack.last() - } - - pub fn peek_redo_stack(&self) -> Option<&HistoryEntry> { - self.history.redo_stack.last() - } - - pub fn start_transaction(&mut self) -> Option { - self.start_transaction_at(Instant::now()) - } - - pub fn start_transaction_at(&mut self, now: Instant) -> Option { - self.history - .start_transaction(self.version.clone(), now, &mut self.lamport_clock) - } - - pub fn end_transaction(&mut self) -> Option<(TransactionId, clock::Global)> { - self.end_transaction_at(Instant::now()) - } - - pub fn end_transaction_at(&mut self, now: Instant) -> Option<(TransactionId, clock::Global)> { - if let Some(entry) = self.history.end_transaction(now) { - let since = entry.transaction.start.clone(); - let id = self.history.group().unwrap(); - Some((id, since)) - } else { - None - } - } - - pub fn finalize_last_transaction(&mut self) -> Option<&Transaction> { - self.history.finalize_last_transaction() - } - - pub fn group_until_transaction(&mut self, transaction_id: TransactionId) { - self.history.group_until(transaction_id); - } - - pub fn base_text(&self) -> &Rope { - &self.history.base_text - } - - pub fn operations(&self) -> &TreeMap { - &self.history.operations - } - - pub fn undo(&mut self) -> Option<(TransactionId, Operation)> { - if let Some(entry) = self.history.pop_undo() { - let transaction = entry.transaction.clone(); - let transaction_id = transaction.id; - let op = self.undo_or_redo(transaction).unwrap(); - Some((transaction_id, op)) - } else { - None - } - } - - pub fn undo_transaction(&mut self, transaction_id: TransactionId) -> Option { - let transaction = self - .history - .remove_from_undo(transaction_id)? - .transaction - .clone(); - self.undo_or_redo(transaction).log_err() - } - - pub fn undo_to_transaction(&mut self, transaction_id: TransactionId) -> Vec { - let transactions = self - .history - .remove_from_undo_until(transaction_id) - .iter() - .map(|entry| entry.transaction.clone()) - .collect::>(); - - transactions - .into_iter() - .map(|transaction| self.undo_or_redo(transaction).unwrap()) - .collect() - } - - pub fn forget_transaction(&mut self, transaction_id: TransactionId) { - self.history.forget(transaction_id); - } - - pub fn merge_transactions(&mut self, transaction: TransactionId, destination: TransactionId) { - self.history.merge_transactions(transaction, destination); - } - - pub fn redo(&mut self) -> Option<(TransactionId, Operation)> { - if let Some(entry) = self.history.pop_redo() { - let transaction = entry.transaction.clone(); - let transaction_id = transaction.id; - let op = self.undo_or_redo(transaction).unwrap(); - Some((transaction_id, op)) - } else { - None - } - } - - pub fn redo_to_transaction(&mut self, transaction_id: TransactionId) -> Vec { - let transactions = self - .history - .remove_from_redo(transaction_id) - .iter() - .map(|entry| entry.transaction.clone()) - .collect::>(); - - transactions - .into_iter() - .map(|transaction| self.undo_or_redo(transaction).unwrap()) - .collect() - } - - fn undo_or_redo(&mut self, transaction: Transaction) -> Result { - let mut counts = HashMap::default(); - for edit_id in transaction.edit_ids { - counts.insert(edit_id, self.undo_map.undo_count(edit_id) + 1); - } - - let undo = UndoOperation { - timestamp: self.lamport_clock.tick(), - version: self.version(), - counts, - }; - self.apply_undo(&undo)?; - self.snapshot.version.observe(undo.timestamp); - let operation = Operation::Undo(undo); - self.history.push(operation.clone()); - Ok(operation) - } - - pub fn push_transaction(&mut self, transaction: Transaction, now: Instant) { - self.history.push_transaction(transaction, now); - self.history.finalize_last_transaction(); - } - - pub fn edited_ranges_for_transaction<'a, D>( - &'a self, - transaction: &'a Transaction, - ) -> impl 'a + Iterator> - where - D: TextDimension, - { - // get fragment ranges - let mut cursor = self.fragments.cursor::<(Option<&Locator>, usize)>(); - let offset_ranges = self - .fragment_ids_for_edits(transaction.edit_ids.iter()) - .into_iter() - .filter_map(move |fragment_id| { - cursor.seek_forward(&Some(fragment_id), Bias::Left, &None); - let fragment = cursor.item()?; - let start_offset = cursor.start().1; - let end_offset = start_offset + if fragment.visible { fragment.len } else { 0 }; - Some(start_offset..end_offset) - }); - - // combine adjacent ranges - let mut prev_range: Option> = None; - let disjoint_ranges = offset_ranges - .map(Some) - .chain([None]) - .filter_map(move |range| { - if let Some((range, prev_range)) = range.as_ref().zip(prev_range.as_mut()) { - if prev_range.end == range.start { - prev_range.end = range.end; - return None; - } - } - let result = prev_range.clone(); - prev_range = range; - result - }); - - // convert to the desired text dimension. - let mut position = D::default(); - let mut rope_cursor = self.visible_text.cursor(0); - disjoint_ranges.map(move |range| { - position.add_assign(&rope_cursor.summary(range.start)); - let start = position.clone(); - position.add_assign(&rope_cursor.summary(range.end)); - let end = position.clone(); - start..end - }) - } - - pub fn subscribe(&mut self) -> Subscription { - self.subscriptions.subscribe() - } - - pub fn wait_for_edits( - &mut self, - edit_ids: impl IntoIterator, - ) -> impl 'static + Future> { - let mut futures = Vec::new(); - for edit_id in edit_ids { - if !self.version.observed(edit_id) { - let (tx, rx) = oneshot::channel(); - self.edit_id_resolvers.entry(edit_id).or_default().push(tx); - futures.push(rx); - } - } - - async move { - for mut future in futures { - if future.recv().await.is_none() { - Err(anyhow!("gave up waiting for edits"))?; - } - } - Ok(()) - } - } - - pub fn wait_for_anchors( - &mut self, - anchors: impl IntoIterator, - ) -> impl 'static + Future> { - let mut futures = Vec::new(); - for anchor in anchors { - if !self.version.observed(anchor.timestamp) - && anchor != Anchor::MAX - && anchor != Anchor::MIN - { - let (tx, rx) = oneshot::channel(); - self.edit_id_resolvers - .entry(anchor.timestamp) - .or_default() - .push(tx); - futures.push(rx); - } - } - - async move { - for mut future in futures { - if future.recv().await.is_none() { - Err(anyhow!("gave up waiting for anchors"))?; - } - } - Ok(()) - } - } - - pub fn wait_for_version(&mut self, version: clock::Global) -> impl Future> { - let mut rx = None; - if !self.snapshot.version.observed_all(&version) { - let channel = oneshot::channel(); - self.wait_for_version_txs.push((version, channel.0)); - rx = Some(channel.1); - } - async move { - if let Some(mut rx) = rx { - if rx.recv().await.is_none() { - Err(anyhow!("gave up waiting for version"))?; - } - } - Ok(()) - } - } - - pub fn give_up_waiting(&mut self) { - self.edit_id_resolvers.clear(); - self.wait_for_version_txs.clear(); - } - - fn resolve_edit(&mut self, edit_id: clock::Lamport) { - for mut tx in self - .edit_id_resolvers - .remove(&edit_id) - .into_iter() - .flatten() - { - tx.try_send(()).ok(); - } - } -} - -#[cfg(any(test, feature = "test-support"))] -impl Buffer { - pub fn edit_via_marked_text(&mut self, marked_string: &str) { - let edits = self.edits_for_marked_text(marked_string); - self.edit(edits); - } - - pub fn edits_for_marked_text(&self, marked_string: &str) -> Vec<(Range, String)> { - let old_text = self.text(); - let (new_text, mut ranges) = util::test::marked_text_ranges(marked_string, false); - if ranges.is_empty() { - ranges.push(0..new_text.len()); - } - - assert_eq!( - old_text[..ranges[0].start], - new_text[..ranges[0].start], - "invalid edit" - ); - - let mut delta = 0; - let mut edits = Vec::new(); - let mut ranges = ranges.into_iter().peekable(); - - while let Some(inserted_range) = ranges.next() { - let new_start = inserted_range.start; - let old_start = (new_start as isize - delta) as usize; - - let following_text = if let Some(next_range) = ranges.peek() { - &new_text[inserted_range.end..next_range.start] - } else { - &new_text[inserted_range.end..] - }; - - let inserted_len = inserted_range.len(); - let deleted_len = old_text[old_start..] - .find(following_text) - .expect("invalid edit"); - - let old_range = old_start..old_start + deleted_len; - edits.push((old_range, new_text[inserted_range].to_string())); - delta += inserted_len as isize - deleted_len as isize; - } - - assert_eq!( - old_text.len() as isize + delta, - new_text.len() as isize, - "invalid edit" - ); - - edits - } - - pub fn check_invariants(&self) { - // Ensure every fragment is ordered by locator in the fragment tree and corresponds - // to an insertion fragment in the insertions tree. - let mut prev_fragment_id = Locator::min(); - for fragment in self.snapshot.fragments.items(&None) { - assert!(fragment.id > prev_fragment_id); - prev_fragment_id = fragment.id.clone(); - - let insertion_fragment = self - .snapshot - .insertions - .get( - &InsertionFragmentKey { - timestamp: fragment.timestamp, - split_offset: fragment.insertion_offset, - }, - &(), - ) - .unwrap(); - assert_eq!( - insertion_fragment.fragment_id, fragment.id, - "fragment: {:?}\ninsertion: {:?}", - fragment, insertion_fragment - ); - } - - let mut cursor = self.snapshot.fragments.cursor::>(); - for insertion_fragment in self.snapshot.insertions.cursor::<()>() { - cursor.seek(&Some(&insertion_fragment.fragment_id), Bias::Left, &None); - let fragment = cursor.item().unwrap(); - assert_eq!(insertion_fragment.fragment_id, fragment.id); - assert_eq!(insertion_fragment.split_offset, fragment.insertion_offset); - } - - let fragment_summary = self.snapshot.fragments.summary(); - assert_eq!( - fragment_summary.text.visible, - self.snapshot.visible_text.len() - ); - assert_eq!( - fragment_summary.text.deleted, - self.snapshot.deleted_text.len() - ); - - assert!(!self.text().contains("\r\n")); - } - - pub fn set_group_interval(&mut self, group_interval: Duration) { - self.history.group_interval = group_interval; - } - - pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range { - let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right); - let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right); - start..end - } - - pub fn get_random_edits( - &self, - rng: &mut T, - edit_count: usize, - ) -> Vec<(Range, Arc)> - where - T: rand::Rng, - { - let mut edits: Vec<(Range, Arc)> = Vec::new(); - let mut last_end = None; - for _ in 0..edit_count { - if last_end.map_or(false, |last_end| last_end >= self.len()) { - break; - } - let new_start = last_end.map_or(0, |last_end| last_end + 1); - let range = self.random_byte_range(new_start, rng); - last_end = Some(range.end); - - let new_text_len = rng.gen_range(0..10); - let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect(); - - edits.push((range, new_text.into())); - } - edits - } - - pub fn randomly_edit( - &mut self, - rng: &mut T, - edit_count: usize, - ) -> (Vec<(Range, Arc)>, Operation) - where - T: rand::Rng, - { - let mut edits = self.get_random_edits(rng, edit_count); - log::info!("mutating buffer {} with {:?}", self.replica_id, edits); - - let op = self.edit(edits.iter().cloned()); - if let Operation::Edit(edit) = &op { - assert_eq!(edits.len(), edit.new_text.len()); - for (edit, new_text) in edits.iter_mut().zip(&edit.new_text) { - edit.1 = new_text.clone(); - } - } else { - unreachable!() - } - - (edits, op) - } - - pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng) -> Vec { - use rand::prelude::*; - - let mut ops = Vec::new(); - for _ in 0..rng.gen_range(1..=5) { - if let Some(entry) = self.history.undo_stack.choose(rng) { - let transaction = entry.transaction.clone(); - log::info!( - "undoing buffer {} transaction {:?}", - self.replica_id, - transaction - ); - ops.push(self.undo_or_redo(transaction).unwrap()); - } - } - ops - } -} - -impl Deref for Buffer { - type Target = BufferSnapshot; - - fn deref(&self) -> &Self::Target { - &self.snapshot - } -} - -impl BufferSnapshot { - pub fn as_rope(&self) -> &Rope { - &self.visible_text - } - - pub fn remote_id(&self) -> u64 { - self.remote_id - } - - pub fn replica_id(&self) -> ReplicaId { - self.replica_id - } - - pub fn row_count(&self) -> u32 { - self.max_point().row + 1 - } - - pub fn len(&self) -> usize { - self.visible_text.len() - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - pub fn chars(&self) -> impl Iterator + '_ { - self.chars_at(0) - } - - pub fn chars_for_range(&self, range: Range) -> impl Iterator + '_ { - self.text_for_range(range).flat_map(str::chars) - } - - pub fn reversed_chars_for_range( - &self, - range: Range, - ) -> impl Iterator + '_ { - self.reversed_chunks_in_range(range) - .flat_map(|chunk| chunk.chars().rev()) - } - - pub fn contains_str_at(&self, position: T, needle: &str) -> bool - where - T: ToOffset, - { - let position = position.to_offset(self); - position == self.clip_offset(position, Bias::Left) - && self - .bytes_in_range(position..self.len()) - .flatten() - .copied() - .take(needle.len()) - .eq(needle.bytes()) - } - - pub fn common_prefix_at(&self, position: T, needle: &str) -> Range - where - T: ToOffset + TextDimension, - { - let offset = position.to_offset(self); - let common_prefix_len = needle - .char_indices() - .map(|(index, _)| index) - .chain([needle.len()]) - .take_while(|&len| len <= offset) - .filter(|&len| { - let left = self - .chars_for_range(offset - len..offset) - .flat_map(char::to_lowercase); - let right = needle[..len].chars().flat_map(char::to_lowercase); - left.eq(right) - }) - .last() - .unwrap_or(0); - let start_offset = offset - common_prefix_len; - let start = self.text_summary_for_range(0..start_offset); - start..position - } - - pub fn text(&self) -> String { - self.visible_text.to_string() - } - - pub fn line_ending(&self) -> LineEnding { - self.line_ending - } - - pub fn deleted_text(&self) -> String { - self.deleted_text.to_string() - } - - pub fn fragments(&self) -> impl Iterator { - self.fragments.iter() - } - - pub fn text_summary(&self) -> TextSummary { - self.visible_text.summary() - } - - pub fn max_point(&self) -> Point { - self.visible_text.max_point() - } - - pub fn max_point_utf16(&self) -> PointUtf16 { - self.visible_text.max_point_utf16() - } - - pub fn point_to_offset(&self, point: Point) -> usize { - self.visible_text.point_to_offset(point) - } - - pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize { - self.visible_text.point_utf16_to_offset(point) - } - - pub fn unclipped_point_utf16_to_offset(&self, point: Unclipped) -> usize { - self.visible_text.unclipped_point_utf16_to_offset(point) - } - - pub fn unclipped_point_utf16_to_point(&self, point: Unclipped) -> Point { - self.visible_text.unclipped_point_utf16_to_point(point) - } - - pub fn offset_utf16_to_offset(&self, offset: OffsetUtf16) -> usize { - self.visible_text.offset_utf16_to_offset(offset) - } - - pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 { - self.visible_text.offset_to_offset_utf16(offset) - } - - pub fn offset_to_point(&self, offset: usize) -> Point { - self.visible_text.offset_to_point(offset) - } - - pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 { - self.visible_text.offset_to_point_utf16(offset) - } - - pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 { - self.visible_text.point_to_point_utf16(point) - } - - pub fn version(&self) -> &clock::Global { - &self.version - } - - pub fn chars_at(&self, position: T) -> impl Iterator + '_ { - let offset = position.to_offset(self); - self.visible_text.chars_at(offset) - } - - pub fn reversed_chars_at(&self, position: T) -> impl Iterator + '_ { - let offset = position.to_offset(self); - self.visible_text.reversed_chars_at(offset) - } - - pub fn reversed_chunks_in_range(&self, range: Range) -> rope::Chunks { - let range = range.start.to_offset(self)..range.end.to_offset(self); - self.visible_text.reversed_chunks_in_range(range) - } - - pub fn bytes_in_range(&self, range: Range) -> rope::Bytes<'_> { - let start = range.start.to_offset(self); - let end = range.end.to_offset(self); - self.visible_text.bytes_in_range(start..end) - } - - pub fn reversed_bytes_in_range(&self, range: Range) -> rope::Bytes<'_> { - let start = range.start.to_offset(self); - let end = range.end.to_offset(self); - self.visible_text.reversed_bytes_in_range(start..end) - } - - pub fn text_for_range(&self, range: Range) -> Chunks<'_> { - let start = range.start.to_offset(self); - let end = range.end.to_offset(self); - self.visible_text.chunks_in_range(start..end) - } - - pub fn line_len(&self, row: u32) -> u32 { - let row_start_offset = Point::new(row, 0).to_offset(self); - let row_end_offset = if row >= self.max_point().row { - self.len() - } else { - Point::new(row + 1, 0).to_offset(self) - 1 - }; - (row_end_offset - row_start_offset) as u32 - } - - pub fn is_line_blank(&self, row: u32) -> bool { - self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row))) - .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none()) - } - - pub fn text_summary_for_range(&self, range: Range) -> D - where - D: TextDimension, - { - self.visible_text - .cursor(range.start.to_offset(self)) - .summary(range.end.to_offset(self)) - } - - pub fn summaries_for_anchors<'a, D, A>(&'a self, anchors: A) -> impl 'a + Iterator - where - D: 'a + TextDimension, - A: 'a + IntoIterator, - { - let anchors = anchors.into_iter(); - self.summaries_for_anchors_with_payload::(anchors.map(|a| (a, ()))) - .map(|d| d.0) - } - - pub fn summaries_for_anchors_with_payload<'a, D, A, T>( - &'a self, - anchors: A, - ) -> impl 'a + Iterator - where - D: 'a + TextDimension, - A: 'a + IntoIterator, - { - let anchors = anchors.into_iter(); - let mut insertion_cursor = self.insertions.cursor::(); - let mut fragment_cursor = self.fragments.cursor::<(Option<&Locator>, usize)>(); - let mut text_cursor = self.visible_text.cursor(0); - let mut position = D::default(); - - anchors.map(move |(anchor, payload)| { - if *anchor == Anchor::MIN { - return (D::default(), payload); - } else if *anchor == Anchor::MAX { - return (D::from_text_summary(&self.visible_text.summary()), payload); - } - - let anchor_key = InsertionFragmentKey { - timestamp: anchor.timestamp, - split_offset: anchor.offset, - }; - insertion_cursor.seek(&anchor_key, anchor.bias, &()); - if let Some(insertion) = insertion_cursor.item() { - let comparison = sum_tree::KeyedItem::key(insertion).cmp(&anchor_key); - if comparison == Ordering::Greater - || (anchor.bias == Bias::Left - && comparison == Ordering::Equal - && anchor.offset > 0) - { - insertion_cursor.prev(&()); - } - } else { - insertion_cursor.prev(&()); - } - let insertion = insertion_cursor.item().expect("invalid insertion"); - assert_eq!(insertion.timestamp, anchor.timestamp, "invalid insertion"); - - fragment_cursor.seek_forward(&Some(&insertion.fragment_id), Bias::Left, &None); - let fragment = fragment_cursor.item().unwrap(); - let mut fragment_offset = fragment_cursor.start().1; - if fragment.visible { - fragment_offset += anchor.offset - insertion.split_offset; - } - - position.add_assign(&text_cursor.summary(fragment_offset)); - (position.clone(), payload) - }) - } - - fn summary_for_anchor(&self, anchor: &Anchor) -> D - where - D: TextDimension, - { - if *anchor == Anchor::MIN { - D::default() - } else if *anchor == Anchor::MAX { - D::from_text_summary(&self.visible_text.summary()) - } else { - let anchor_key = InsertionFragmentKey { - timestamp: anchor.timestamp, - split_offset: anchor.offset, - }; - let mut insertion_cursor = self.insertions.cursor::(); - insertion_cursor.seek(&anchor_key, anchor.bias, &()); - if let Some(insertion) = insertion_cursor.item() { - let comparison = sum_tree::KeyedItem::key(insertion).cmp(&anchor_key); - if comparison == Ordering::Greater - || (anchor.bias == Bias::Left - && comparison == Ordering::Equal - && anchor.offset > 0) - { - insertion_cursor.prev(&()); - } - } else { - insertion_cursor.prev(&()); - } - let insertion = insertion_cursor.item().expect("invalid insertion"); - assert_eq!(insertion.timestamp, anchor.timestamp, "invalid insertion"); - - let mut fragment_cursor = self.fragments.cursor::<(Option<&Locator>, usize)>(); - fragment_cursor.seek(&Some(&insertion.fragment_id), Bias::Left, &None); - let fragment = fragment_cursor.item().unwrap(); - let mut fragment_offset = fragment_cursor.start().1; - if fragment.visible { - fragment_offset += anchor.offset - insertion.split_offset; - } - self.text_summary_for_range(0..fragment_offset) - } - } - - fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator { - if *anchor == Anchor::MIN { - Locator::min_ref() - } else if *anchor == Anchor::MAX { - Locator::max_ref() - } else { - let anchor_key = InsertionFragmentKey { - timestamp: anchor.timestamp, - split_offset: anchor.offset, - }; - let mut insertion_cursor = self.insertions.cursor::(); - insertion_cursor.seek(&anchor_key, anchor.bias, &()); - if let Some(insertion) = insertion_cursor.item() { - let comparison = sum_tree::KeyedItem::key(insertion).cmp(&anchor_key); - if comparison == Ordering::Greater - || (anchor.bias == Bias::Left - && comparison == Ordering::Equal - && anchor.offset > 0) - { - insertion_cursor.prev(&()); - } - } else { - insertion_cursor.prev(&()); - } - let insertion = insertion_cursor.item().expect("invalid insertion"); - debug_assert_eq!(insertion.timestamp, anchor.timestamp, "invalid insertion"); - &insertion.fragment_id - } - } - - pub fn anchor_before(&self, position: T) -> Anchor { - self.anchor_at(position, Bias::Left) - } - - pub fn anchor_after(&self, position: T) -> Anchor { - self.anchor_at(position, Bias::Right) - } - - pub fn anchor_at(&self, position: T, bias: Bias) -> Anchor { - self.anchor_at_offset(position.to_offset(self), bias) - } - - fn anchor_at_offset(&self, offset: usize, bias: Bias) -> Anchor { - if bias == Bias::Left && offset == 0 { - Anchor::MIN - } else if bias == Bias::Right && offset == self.len() { - Anchor::MAX - } else { - let mut fragment_cursor = self.fragments.cursor::(); - fragment_cursor.seek(&offset, bias, &None); - let fragment = fragment_cursor.item().unwrap(); - let overshoot = offset - *fragment_cursor.start(); - Anchor { - timestamp: fragment.timestamp, - offset: fragment.insertion_offset + overshoot, - bias, - buffer_id: Some(self.remote_id), - } - } - } - - pub fn can_resolve(&self, anchor: &Anchor) -> bool { - *anchor == Anchor::MIN - || *anchor == Anchor::MAX - || (Some(self.remote_id) == anchor.buffer_id && self.version.observed(anchor.timestamp)) - } - - pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize { - self.visible_text.clip_offset(offset, bias) - } - - pub fn clip_point(&self, point: Point, bias: Bias) -> Point { - self.visible_text.clip_point(point, bias) - } - - pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 { - self.visible_text.clip_offset_utf16(offset, bias) - } - - pub fn clip_point_utf16(&self, point: Unclipped, bias: Bias) -> PointUtf16 { - self.visible_text.clip_point_utf16(point, bias) - } - - pub fn edits_since<'a, D>( - &'a self, - since: &'a clock::Global, - ) -> impl 'a + Iterator> - where - D: TextDimension + Ord, - { - self.edits_since_in_range(since, Anchor::MIN..Anchor::MAX) - } - - pub fn anchored_edits_since<'a, D>( - &'a self, - since: &'a clock::Global, - ) -> impl 'a + Iterator, Range)> - where - D: TextDimension + Ord, - { - self.anchored_edits_since_in_range(since, Anchor::MIN..Anchor::MAX) - } - - pub fn edits_since_in_range<'a, D>( - &'a self, - since: &'a clock::Global, - range: Range, - ) -> impl 'a + Iterator> - where - D: TextDimension + Ord, - { - self.anchored_edits_since_in_range(since, range) - .map(|item| item.0) - } - - pub fn anchored_edits_since_in_range<'a, D>( - &'a self, - since: &'a clock::Global, - range: Range, - ) -> impl 'a + Iterator, Range)> - where - D: TextDimension + Ord, - { - let fragments_cursor = if *since == self.version { - None - } else { - let mut cursor = self - .fragments - .filter(move |summary| !since.observed_all(&summary.max_version)); - cursor.next(&None); - Some(cursor) - }; - let mut cursor = self - .fragments - .cursor::<(Option<&Locator>, FragmentTextSummary)>(); - - let start_fragment_id = self.fragment_id_for_anchor(&range.start); - cursor.seek(&Some(start_fragment_id), Bias::Left, &None); - let mut visible_start = cursor.start().1.visible; - let mut deleted_start = cursor.start().1.deleted; - if let Some(fragment) = cursor.item() { - let overshoot = range.start.offset - fragment.insertion_offset; - if fragment.visible { - visible_start += overshoot; - } else { - deleted_start += overshoot; - } - } - let end_fragment_id = self.fragment_id_for_anchor(&range.end); - - Edits { - visible_cursor: self.visible_text.cursor(visible_start), - deleted_cursor: self.deleted_text.cursor(deleted_start), - fragments_cursor, - undos: &self.undo_map, - since, - old_end: Default::default(), - new_end: Default::default(), - range: (start_fragment_id, range.start.offset)..(end_fragment_id, range.end.offset), - buffer_id: self.remote_id, - } - } -} - -struct RopeBuilder<'a> { - old_visible_cursor: rope::Cursor<'a>, - old_deleted_cursor: rope::Cursor<'a>, - new_visible: Rope, - new_deleted: Rope, -} - -impl<'a> RopeBuilder<'a> { - fn new(old_visible_cursor: rope::Cursor<'a>, old_deleted_cursor: rope::Cursor<'a>) -> Self { - Self { - old_visible_cursor, - old_deleted_cursor, - new_visible: Rope::new(), - new_deleted: Rope::new(), - } - } - - fn append(&mut self, len: FragmentTextSummary) { - self.push(len.visible, true, true); - self.push(len.deleted, false, false); - } - - fn push_fragment(&mut self, fragment: &Fragment, was_visible: bool) { - debug_assert!(fragment.len > 0); - self.push(fragment.len, was_visible, fragment.visible) - } - - fn push(&mut self, len: usize, was_visible: bool, is_visible: bool) { - let text = if was_visible { - self.old_visible_cursor - .slice(self.old_visible_cursor.offset() + len) - } else { - self.old_deleted_cursor - .slice(self.old_deleted_cursor.offset() + len) - }; - if is_visible { - self.new_visible.append(text); - } else { - self.new_deleted.append(text); - } - } - - fn push_str(&mut self, text: &str) { - self.new_visible.push(text); - } - - fn finish(mut self) -> (Rope, Rope) { - self.new_visible.append(self.old_visible_cursor.suffix()); - self.new_deleted.append(self.old_deleted_cursor.suffix()); - (self.new_visible, self.new_deleted) - } -} - -impl<'a, D: TextDimension + Ord, F: FnMut(&FragmentSummary) -> bool> Iterator for Edits<'a, D, F> { - type Item = (Edit, Range); - - fn next(&mut self) -> Option { - let mut pending_edit: Option = None; - let cursor = self.fragments_cursor.as_mut()?; - - while let Some(fragment) = cursor.item() { - if fragment.id < *self.range.start.0 { - cursor.next(&None); - continue; - } else if fragment.id > *self.range.end.0 { - break; - } - - if cursor.start().visible > self.visible_cursor.offset() { - let summary = self.visible_cursor.summary(cursor.start().visible); - self.old_end.add_assign(&summary); - self.new_end.add_assign(&summary); - } - - if pending_edit - .as_ref() - .map_or(false, |(change, _)| change.new.end < self.new_end) - { - break; - } - - let start_anchor = Anchor { - timestamp: fragment.timestamp, - offset: fragment.insertion_offset, - bias: Bias::Right, - buffer_id: Some(self.buffer_id), - }; - let end_anchor = Anchor { - timestamp: fragment.timestamp, - offset: fragment.insertion_offset + fragment.len, - bias: Bias::Left, - buffer_id: Some(self.buffer_id), - }; - - if !fragment.was_visible(self.since, self.undos) && fragment.visible { - let mut visible_end = cursor.end(&None).visible; - if fragment.id == *self.range.end.0 { - visible_end = cmp::min( - visible_end, - cursor.start().visible + (self.range.end.1 - fragment.insertion_offset), - ); - } - - let fragment_summary = self.visible_cursor.summary(visible_end); - let mut new_end = self.new_end.clone(); - new_end.add_assign(&fragment_summary); - if let Some((edit, range)) = pending_edit.as_mut() { - edit.new.end = new_end.clone(); - range.end = end_anchor; - } else { - pending_edit = Some(( - Edit { - old: self.old_end.clone()..self.old_end.clone(), - new: self.new_end.clone()..new_end.clone(), - }, - start_anchor..end_anchor, - )); - } - - self.new_end = new_end; - } else if fragment.was_visible(self.since, self.undos) && !fragment.visible { - let mut deleted_end = cursor.end(&None).deleted; - if fragment.id == *self.range.end.0 { - deleted_end = cmp::min( - deleted_end, - cursor.start().deleted + (self.range.end.1 - fragment.insertion_offset), - ); - } - - if cursor.start().deleted > self.deleted_cursor.offset() { - self.deleted_cursor.seek_forward(cursor.start().deleted); - } - let fragment_summary = self.deleted_cursor.summary(deleted_end); - let mut old_end = self.old_end.clone(); - old_end.add_assign(&fragment_summary); - if let Some((edit, range)) = pending_edit.as_mut() { - edit.old.end = old_end.clone(); - range.end = end_anchor; - } else { - pending_edit = Some(( - Edit { - old: self.old_end.clone()..old_end.clone(), - new: self.new_end.clone()..self.new_end.clone(), - }, - start_anchor..end_anchor, - )); - } - - self.old_end = old_end; - } - - cursor.next(&None); - } - - pending_edit - } -} - -impl Fragment { - fn insertion_slice(&self) -> InsertionSlice { - InsertionSlice { - insertion_id: self.timestamp, - range: self.insertion_offset..self.insertion_offset + self.len, - } - } - - fn is_visible(&self, undos: &UndoMap) -> bool { - !undos.is_undone(self.timestamp) && self.deletions.iter().all(|d| undos.is_undone(*d)) - } - - fn was_visible(&self, version: &clock::Global, undos: &UndoMap) -> bool { - (version.observed(self.timestamp) && !undos.was_undone(self.timestamp, version)) - && self - .deletions - .iter() - .all(|d| !version.observed(*d) || undos.was_undone(*d, version)) - } -} - -impl sum_tree::Item for Fragment { - type Summary = FragmentSummary; - - fn summary(&self) -> Self::Summary { - let mut max_version = clock::Global::new(); - max_version.observe(self.timestamp); - for deletion in &self.deletions { - max_version.observe(*deletion); - } - max_version.join(&self.max_undos); - - let mut min_insertion_version = clock::Global::new(); - min_insertion_version.observe(self.timestamp); - let max_insertion_version = min_insertion_version.clone(); - if self.visible { - FragmentSummary { - max_id: self.id.clone(), - text: FragmentTextSummary { - visible: self.len, - deleted: 0, - }, - max_version, - min_insertion_version, - max_insertion_version, - } - } else { - FragmentSummary { - max_id: self.id.clone(), - text: FragmentTextSummary { - visible: 0, - deleted: self.len, - }, - max_version, - min_insertion_version, - max_insertion_version, - } - } - } -} - -impl sum_tree::Summary for FragmentSummary { - type Context = Option; - - fn add_summary(&mut self, other: &Self, _: &Self::Context) { - self.max_id.assign(&other.max_id); - self.text.visible += &other.text.visible; - self.text.deleted += &other.text.deleted; - self.max_version.join(&other.max_version); - self.min_insertion_version - .meet(&other.min_insertion_version); - self.max_insertion_version - .join(&other.max_insertion_version); - } -} - -impl Default for FragmentSummary { - fn default() -> Self { - FragmentSummary { - max_id: Locator::min(), - text: FragmentTextSummary::default(), - max_version: clock::Global::new(), - min_insertion_version: clock::Global::new(), - max_insertion_version: clock::Global::new(), - } - } -} - -impl sum_tree::Item for InsertionFragment { - type Summary = InsertionFragmentKey; - - fn summary(&self) -> Self::Summary { - InsertionFragmentKey { - timestamp: self.timestamp, - split_offset: self.split_offset, - } - } -} - -impl sum_tree::KeyedItem for InsertionFragment { - type Key = InsertionFragmentKey; - - fn key(&self) -> Self::Key { - sum_tree::Item::summary(self) - } -} - -impl InsertionFragment { - fn new(fragment: &Fragment) -> Self { - Self { - timestamp: fragment.timestamp, - split_offset: fragment.insertion_offset, - fragment_id: fragment.id.clone(), - } - } - - fn insert_new(fragment: &Fragment) -> sum_tree::Edit { - sum_tree::Edit::Insert(Self::new(fragment)) - } -} - -impl sum_tree::Summary for InsertionFragmentKey { - type Context = (); - - fn add_summary(&mut self, summary: &Self, _: &()) { - *self = *summary; - } -} - -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct FullOffset(pub usize); - -impl ops::AddAssign for FullOffset { - fn add_assign(&mut self, rhs: usize) { - self.0 += rhs; - } -} - -impl ops::Add for FullOffset { - type Output = Self; - - fn add(mut self, rhs: usize) -> Self::Output { - self += rhs; - self - } -} - -impl ops::Sub for FullOffset { - type Output = usize; - - fn sub(self, rhs: Self) -> Self::Output { - self.0 - rhs.0 - } -} - -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for usize { - fn add_summary(&mut self, summary: &FragmentSummary, _: &Option) { - *self += summary.text.visible; - } -} - -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FullOffset { - fn add_summary(&mut self, summary: &FragmentSummary, _: &Option) { - self.0 += summary.text.visible + summary.text.deleted; - } -} - -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for Option<&'a Locator> { - fn add_summary(&mut self, summary: &'a FragmentSummary, _: &Option) { - *self = Some(&summary.max_id); - } -} - -impl<'a> sum_tree::SeekTarget<'a, FragmentSummary, FragmentTextSummary> for usize { - fn cmp( - &self, - cursor_location: &FragmentTextSummary, - _: &Option, - ) -> cmp::Ordering { - Ord::cmp(self, &cursor_location.visible) - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum VersionedFullOffset { - Offset(FullOffset), - Invalid, -} - -impl VersionedFullOffset { - fn full_offset(&self) -> FullOffset { - if let Self::Offset(position) = self { - *position - } else { - panic!("invalid version") - } - } -} - -impl Default for VersionedFullOffset { - fn default() -> Self { - Self::Offset(Default::default()) - } -} - -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for VersionedFullOffset { - fn add_summary(&mut self, summary: &'a FragmentSummary, cx: &Option) { - if let Self::Offset(offset) = self { - let version = cx.as_ref().unwrap(); - if version.observed_all(&summary.max_insertion_version) { - *offset += summary.text.visible + summary.text.deleted; - } else if version.observed_any(&summary.min_insertion_version) { - *self = Self::Invalid; - } - } - } -} - -impl<'a> sum_tree::SeekTarget<'a, FragmentSummary, Self> for VersionedFullOffset { - fn cmp(&self, cursor_position: &Self, _: &Option) -> cmp::Ordering { - match (self, cursor_position) { - (Self::Offset(a), Self::Offset(b)) => Ord::cmp(a, b), - (Self::Offset(_), Self::Invalid) => cmp::Ordering::Less, - (Self::Invalid, _) => unreachable!(), - } - } -} - -impl Operation { - fn replica_id(&self) -> ReplicaId { - operation_queue::Operation::lamport_timestamp(self).replica_id - } - - pub fn timestamp(&self) -> clock::Lamport { - match self { - Operation::Edit(edit) => edit.timestamp, - Operation::Undo(undo) => undo.timestamp, - } - } - - pub fn as_edit(&self) -> Option<&EditOperation> { - match self { - Operation::Edit(edit) => Some(edit), - _ => None, - } - } - - pub fn is_edit(&self) -> bool { - matches!(self, Operation::Edit { .. }) - } -} - -impl operation_queue::Operation for Operation { - fn lamport_timestamp(&self) -> clock::Lamport { - match self { - Operation::Edit(edit) => edit.timestamp, - Operation::Undo(undo) => undo.timestamp, - } - } -} - -pub trait ToOffset { - fn to_offset(&self, snapshot: &BufferSnapshot) -> usize; -} - -impl ToOffset for Point { - fn to_offset(&self, snapshot: &BufferSnapshot) -> usize { - snapshot.point_to_offset(*self) - } -} - -impl ToOffset for usize { - fn to_offset(&self, snapshot: &BufferSnapshot) -> usize { - assert!( - *self <= snapshot.len(), - "offset {} is out of range, max allowed is {}", - self, - snapshot.len() - ); - *self - } -} - -impl ToOffset for Anchor { - fn to_offset(&self, snapshot: &BufferSnapshot) -> usize { - snapshot.summary_for_anchor(self) - } -} - -impl<'a, T: ToOffset> ToOffset for &'a T { - fn to_offset(&self, content: &BufferSnapshot) -> usize { - (*self).to_offset(content) - } -} - -impl ToOffset for PointUtf16 { - fn to_offset(&self, snapshot: &BufferSnapshot) -> usize { - snapshot.point_utf16_to_offset(*self) - } -} - -impl ToOffset for Unclipped { - fn to_offset(&self, snapshot: &BufferSnapshot) -> usize { - snapshot.unclipped_point_utf16_to_offset(*self) - } -} - -pub trait ToPoint { - fn to_point(&self, snapshot: &BufferSnapshot) -> Point; -} - -impl ToPoint for Anchor { - fn to_point(&self, snapshot: &BufferSnapshot) -> Point { - snapshot.summary_for_anchor(self) - } -} - -impl ToPoint for usize { - fn to_point(&self, snapshot: &BufferSnapshot) -> Point { - snapshot.offset_to_point(*self) - } -} - -impl ToPoint for Point { - fn to_point(&self, _: &BufferSnapshot) -> Point { - *self - } -} - -impl ToPoint for Unclipped { - fn to_point(&self, snapshot: &BufferSnapshot) -> Point { - snapshot.unclipped_point_utf16_to_point(*self) - } -} - -pub trait ToPointUtf16 { - fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> PointUtf16; -} - -impl ToPointUtf16 for Anchor { - fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> PointUtf16 { - snapshot.summary_for_anchor(self) - } -} - -impl ToPointUtf16 for usize { - fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> PointUtf16 { - snapshot.offset_to_point_utf16(*self) - } -} - -impl ToPointUtf16 for PointUtf16 { - fn to_point_utf16(&self, _: &BufferSnapshot) -> PointUtf16 { - *self - } -} - -impl ToPointUtf16 for Point { - fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> PointUtf16 { - snapshot.point_to_point_utf16(*self) - } -} - -pub trait ToOffsetUtf16 { - fn to_offset_utf16(&self, snapshot: &BufferSnapshot) -> OffsetUtf16; -} - -impl ToOffsetUtf16 for Anchor { - fn to_offset_utf16(&self, snapshot: &BufferSnapshot) -> OffsetUtf16 { - snapshot.summary_for_anchor(self) - } -} - -impl ToOffsetUtf16 for usize { - fn to_offset_utf16(&self, snapshot: &BufferSnapshot) -> OffsetUtf16 { - snapshot.offset_to_offset_utf16(*self) - } -} - -impl ToOffsetUtf16 for OffsetUtf16 { - fn to_offset_utf16(&self, _snapshot: &BufferSnapshot) -> OffsetUtf16 { - *self - } -} - -pub trait FromAnchor { - fn from_anchor(anchor: &Anchor, snapshot: &BufferSnapshot) -> Self; -} - -impl FromAnchor for Point { - fn from_anchor(anchor: &Anchor, snapshot: &BufferSnapshot) -> Self { - snapshot.summary_for_anchor(anchor) - } -} - -impl FromAnchor for PointUtf16 { - fn from_anchor(anchor: &Anchor, snapshot: &BufferSnapshot) -> Self { - snapshot.summary_for_anchor(anchor) - } -} - -impl FromAnchor for usize { - fn from_anchor(anchor: &Anchor, snapshot: &BufferSnapshot) -> Self { - snapshot.summary_for_anchor(anchor) - } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum LineEnding { - Unix, - Windows, -} - -impl Default for LineEnding { - fn default() -> Self { - #[cfg(unix)] - return Self::Unix; - - #[cfg(not(unix))] - return Self::CRLF; - } -} - -impl LineEnding { - pub fn as_str(&self) -> &'static str { - match self { - LineEnding::Unix => "\n", - LineEnding::Windows => "\r\n", - } - } - - pub fn detect(text: &str) -> Self { - let mut max_ix = cmp::min(text.len(), 1000); - while !text.is_char_boundary(max_ix) { - max_ix -= 1; - } - - if let Some(ix) = text[..max_ix].find(['\n']) { - if ix > 0 && text.as_bytes()[ix - 1] == b'\r' { - Self::Windows - } else { - Self::Unix - } - } else { - Self::default() - } - } - - pub fn normalize(text: &mut String) { - if let Cow::Owned(replaced) = LINE_SEPARATORS_REGEX.replace_all(text, "\n") { - *text = replaced; - } - } - - pub fn normalize_arc(text: Arc) -> Arc { - if let Cow::Owned(replaced) = LINE_SEPARATORS_REGEX.replace_all(&text, "\n") { - replaced.into() - } else { - text - } - } -} diff --git a/crates/text2/src/undo_map.rs b/crates/text2/src/undo_map.rs deleted file mode 100644 index f95809c02e..0000000000 --- a/crates/text2/src/undo_map.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::UndoOperation; -use std::cmp; -use sum_tree::{Bias, SumTree}; - -#[derive(Copy, Clone, Debug)] -struct UndoMapEntry { - key: UndoMapKey, - undo_count: u32, -} - -impl sum_tree::Item for UndoMapEntry { - type Summary = UndoMapKey; - - fn summary(&self) -> Self::Summary { - self.key - } -} - -impl sum_tree::KeyedItem for UndoMapEntry { - type Key = UndoMapKey; - - fn key(&self) -> Self::Key { - self.key - } -} - -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] -struct UndoMapKey { - edit_id: clock::Lamport, - undo_id: clock::Lamport, -} - -impl sum_tree::Summary for UndoMapKey { - type Context = (); - - fn add_summary(&mut self, summary: &Self, _: &Self::Context) { - *self = cmp::max(*self, *summary); - } -} - -#[derive(Clone, Default)] -pub struct UndoMap(SumTree); - -impl UndoMap { - pub fn insert(&mut self, undo: &UndoOperation) { - let edits = undo - .counts - .iter() - .map(|(edit_id, count)| { - sum_tree::Edit::Insert(UndoMapEntry { - key: UndoMapKey { - edit_id: *edit_id, - undo_id: undo.timestamp, - }, - undo_count: *count, - }) - }) - .collect::>(); - self.0.edit(edits, &()); - } - - pub fn is_undone(&self, edit_id: clock::Lamport) -> bool { - self.undo_count(edit_id) % 2 == 1 - } - - pub fn was_undone(&self, edit_id: clock::Lamport, version: &clock::Global) -> bool { - let mut cursor = self.0.cursor::(); - cursor.seek( - &UndoMapKey { - edit_id, - undo_id: Default::default(), - }, - Bias::Left, - &(), - ); - - let mut undo_count = 0; - for entry in cursor { - if entry.key.edit_id != edit_id { - break; - } - - if version.observed(entry.key.undo_id) { - undo_count = cmp::max(undo_count, entry.undo_count); - } - } - - undo_count % 2 == 1 - } - - pub fn undo_count(&self, edit_id: clock::Lamport) -> u32 { - let mut cursor = self.0.cursor::(); - cursor.seek( - &UndoMapKey { - edit_id, - undo_id: Default::default(), - }, - Bias::Left, - &(), - ); - - let mut undo_count = 0; - for entry in cursor { - if entry.key.edit_id != edit_id { - break; - } - - undo_count = cmp::max(undo_count, entry.undo_count); - } - undo_count - } -} diff --git a/crates/theme_selector/Cargo.toml b/crates/theme_selector/Cargo.toml index 161a3ce0fc..2092a7c3b6 100644 --- a/crates/theme_selector/Cargo.toml +++ b/crates/theme_selector/Cargo.toml @@ -18,7 +18,7 @@ gpui = { package = "gpui2", path = "../gpui2" } picker = { path = "../picker" } settings = { path = "../settings" } theme = { package = "theme2", path = "../theme2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } util = { path = "../util" } workspace = { path = "../workspace" } log.workspace = true diff --git a/crates/ui2/Cargo.toml b/crates/ui/Cargo.toml similarity index 92% rename from crates/ui2/Cargo.toml rename to crates/ui/Cargo.toml index e3b1803b96..479d9b5a69 100644 --- a/crates/ui2/Cargo.toml +++ b/crates/ui/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "ui2" +name = "ui" version = "0.1.0" edition = "2021" publish = false [lib] -name = "ui2" -path = "src/ui2.rs" +name = "ui" +path = "src/ui.rs" [dependencies] anyhow.workspace = true diff --git a/crates/ui2/docs/building-ui.md b/crates/ui/docs/building-ui.md similarity index 100% rename from crates/ui2/docs/building-ui.md rename to crates/ui/docs/building-ui.md diff --git a/crates/ui2/docs/hello-world.md b/crates/ui/docs/hello-world.md similarity index 100% rename from crates/ui2/docs/hello-world.md rename to crates/ui/docs/hello-world.md diff --git a/crates/ui2/docs/todo.md b/crates/ui/docs/todo.md similarity index 100% rename from crates/ui2/docs/todo.md rename to crates/ui/docs/todo.md diff --git a/crates/ui2/src/clickable.rs b/crates/ui/src/clickable.rs similarity index 100% rename from crates/ui2/src/clickable.rs rename to crates/ui/src/clickable.rs diff --git a/crates/ui2/src/components.rs b/crates/ui/src/components.rs similarity index 100% rename from crates/ui2/src/components.rs rename to crates/ui/src/components.rs diff --git a/crates/ui2/src/components/avatar.rs b/crates/ui/src/components/avatar.rs similarity index 100% rename from crates/ui2/src/components/avatar.rs rename to crates/ui/src/components/avatar.rs diff --git a/crates/ui2/src/components/button.rs b/crates/ui/src/components/button.rs similarity index 100% rename from crates/ui2/src/components/button.rs rename to crates/ui/src/components/button.rs diff --git a/crates/ui2/src/components/button/button.rs b/crates/ui/src/components/button/button.rs similarity index 100% rename from crates/ui2/src/components/button/button.rs rename to crates/ui/src/components/button/button.rs diff --git a/crates/ui2/src/components/button/button_icon.rs b/crates/ui/src/components/button/button_icon.rs similarity index 100% rename from crates/ui2/src/components/button/button_icon.rs rename to crates/ui/src/components/button/button_icon.rs diff --git a/crates/ui2/src/components/button/button_like.rs b/crates/ui/src/components/button/button_like.rs similarity index 100% rename from crates/ui2/src/components/button/button_like.rs rename to crates/ui/src/components/button/button_like.rs diff --git a/crates/ui2/src/components/button/icon_button.rs b/crates/ui/src/components/button/icon_button.rs similarity index 100% rename from crates/ui2/src/components/button/icon_button.rs rename to crates/ui/src/components/button/icon_button.rs diff --git a/crates/ui2/src/components/button/toggle_button.rs b/crates/ui/src/components/button/toggle_button.rs similarity index 100% rename from crates/ui2/src/components/button/toggle_button.rs rename to crates/ui/src/components/button/toggle_button.rs diff --git a/crates/ui2/src/components/checkbox.rs b/crates/ui/src/components/checkbox.rs similarity index 100% rename from crates/ui2/src/components/checkbox.rs rename to crates/ui/src/components/checkbox.rs diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui/src/components/context_menu.rs similarity index 100% rename from crates/ui2/src/components/context_menu.rs rename to crates/ui/src/components/context_menu.rs diff --git a/crates/ui2/src/components/disclosure.rs b/crates/ui/src/components/disclosure.rs similarity index 100% rename from crates/ui2/src/components/disclosure.rs rename to crates/ui/src/components/disclosure.rs diff --git a/crates/ui2/src/components/divider.rs b/crates/ui/src/components/divider.rs similarity index 100% rename from crates/ui2/src/components/divider.rs rename to crates/ui/src/components/divider.rs diff --git a/crates/ui2/src/components/icon.rs b/crates/ui/src/components/icon.rs similarity index 100% rename from crates/ui2/src/components/icon.rs rename to crates/ui/src/components/icon.rs diff --git a/crates/ui2/src/components/indicator.rs b/crates/ui/src/components/indicator.rs similarity index 100% rename from crates/ui2/src/components/indicator.rs rename to crates/ui/src/components/indicator.rs diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui/src/components/keybinding.rs similarity index 100% rename from crates/ui2/src/components/keybinding.rs rename to crates/ui/src/components/keybinding.rs diff --git a/crates/ui2/src/components/label.rs b/crates/ui/src/components/label.rs similarity index 100% rename from crates/ui2/src/components/label.rs rename to crates/ui/src/components/label.rs diff --git a/crates/ui2/src/components/label/highlighted_label.rs b/crates/ui/src/components/label/highlighted_label.rs similarity index 100% rename from crates/ui2/src/components/label/highlighted_label.rs rename to crates/ui/src/components/label/highlighted_label.rs diff --git a/crates/ui2/src/components/label/label.rs b/crates/ui/src/components/label/label.rs similarity index 100% rename from crates/ui2/src/components/label/label.rs rename to crates/ui/src/components/label/label.rs diff --git a/crates/ui2/src/components/label/label_like.rs b/crates/ui/src/components/label/label_like.rs similarity index 100% rename from crates/ui2/src/components/label/label_like.rs rename to crates/ui/src/components/label/label_like.rs diff --git a/crates/ui2/src/components/list.rs b/crates/ui/src/components/list.rs similarity index 100% rename from crates/ui2/src/components/list.rs rename to crates/ui/src/components/list.rs diff --git a/crates/ui2/src/components/list/list.rs b/crates/ui/src/components/list/list.rs similarity index 100% rename from crates/ui2/src/components/list/list.rs rename to crates/ui/src/components/list/list.rs diff --git a/crates/ui2/src/components/list/list_header.rs b/crates/ui/src/components/list/list_header.rs similarity index 100% rename from crates/ui2/src/components/list/list_header.rs rename to crates/ui/src/components/list/list_header.rs diff --git a/crates/ui2/src/components/list/list_item.rs b/crates/ui/src/components/list/list_item.rs similarity index 100% rename from crates/ui2/src/components/list/list_item.rs rename to crates/ui/src/components/list/list_item.rs diff --git a/crates/ui2/src/components/list/list_separator.rs b/crates/ui/src/components/list/list_separator.rs similarity index 100% rename from crates/ui2/src/components/list/list_separator.rs rename to crates/ui/src/components/list/list_separator.rs diff --git a/crates/ui2/src/components/list/list_sub_header.rs b/crates/ui/src/components/list/list_sub_header.rs similarity index 100% rename from crates/ui2/src/components/list/list_sub_header.rs rename to crates/ui/src/components/list/list_sub_header.rs diff --git a/crates/ui2/src/components/popover.rs b/crates/ui/src/components/popover.rs similarity index 100% rename from crates/ui2/src/components/popover.rs rename to crates/ui/src/components/popover.rs diff --git a/crates/ui2/src/components/popover_menu.rs b/crates/ui/src/components/popover_menu.rs similarity index 100% rename from crates/ui2/src/components/popover_menu.rs rename to crates/ui/src/components/popover_menu.rs diff --git a/crates/ui2/src/components/right_click_menu.rs b/crates/ui/src/components/right_click_menu.rs similarity index 100% rename from crates/ui2/src/components/right_click_menu.rs rename to crates/ui/src/components/right_click_menu.rs diff --git a/crates/ui2/src/components/stack.rs b/crates/ui/src/components/stack.rs similarity index 100% rename from crates/ui2/src/components/stack.rs rename to crates/ui/src/components/stack.rs diff --git a/crates/ui2/src/components/stories.rs b/crates/ui/src/components/stories.rs similarity index 100% rename from crates/ui2/src/components/stories.rs rename to crates/ui/src/components/stories.rs diff --git a/crates/ui2/src/components/stories/avatar.rs b/crates/ui/src/components/stories/avatar.rs similarity index 100% rename from crates/ui2/src/components/stories/avatar.rs rename to crates/ui/src/components/stories/avatar.rs diff --git a/crates/ui2/src/components/stories/button.rs b/crates/ui/src/components/stories/button.rs similarity index 100% rename from crates/ui2/src/components/stories/button.rs rename to crates/ui/src/components/stories/button.rs diff --git a/crates/ui2/src/components/stories/checkbox.rs b/crates/ui/src/components/stories/checkbox.rs similarity index 100% rename from crates/ui2/src/components/stories/checkbox.rs rename to crates/ui/src/components/stories/checkbox.rs diff --git a/crates/ui2/src/components/stories/context_menu.rs b/crates/ui/src/components/stories/context_menu.rs similarity index 100% rename from crates/ui2/src/components/stories/context_menu.rs rename to crates/ui/src/components/stories/context_menu.rs diff --git a/crates/ui2/src/components/stories/disclosure.rs b/crates/ui/src/components/stories/disclosure.rs similarity index 100% rename from crates/ui2/src/components/stories/disclosure.rs rename to crates/ui/src/components/stories/disclosure.rs diff --git a/crates/ui2/src/components/stories/icon.rs b/crates/ui/src/components/stories/icon.rs similarity index 100% rename from crates/ui2/src/components/stories/icon.rs rename to crates/ui/src/components/stories/icon.rs diff --git a/crates/ui2/src/components/stories/icon_button.rs b/crates/ui/src/components/stories/icon_button.rs similarity index 100% rename from crates/ui2/src/components/stories/icon_button.rs rename to crates/ui/src/components/stories/icon_button.rs diff --git a/crates/ui2/src/components/stories/keybinding.rs b/crates/ui/src/components/stories/keybinding.rs similarity index 100% rename from crates/ui2/src/components/stories/keybinding.rs rename to crates/ui/src/components/stories/keybinding.rs diff --git a/crates/ui2/src/components/stories/label.rs b/crates/ui/src/components/stories/label.rs similarity index 100% rename from crates/ui2/src/components/stories/label.rs rename to crates/ui/src/components/stories/label.rs diff --git a/crates/ui2/src/components/stories/list.rs b/crates/ui/src/components/stories/list.rs similarity index 100% rename from crates/ui2/src/components/stories/list.rs rename to crates/ui/src/components/stories/list.rs diff --git a/crates/ui2/src/components/stories/list_header.rs b/crates/ui/src/components/stories/list_header.rs similarity index 100% rename from crates/ui2/src/components/stories/list_header.rs rename to crates/ui/src/components/stories/list_header.rs diff --git a/crates/ui2/src/components/stories/list_item.rs b/crates/ui/src/components/stories/list_item.rs similarity index 100% rename from crates/ui2/src/components/stories/list_item.rs rename to crates/ui/src/components/stories/list_item.rs diff --git a/crates/ui2/src/components/stories/tab.rs b/crates/ui/src/components/stories/tab.rs similarity index 100% rename from crates/ui2/src/components/stories/tab.rs rename to crates/ui/src/components/stories/tab.rs diff --git a/crates/ui2/src/components/stories/tab_bar.rs b/crates/ui/src/components/stories/tab_bar.rs similarity index 100% rename from crates/ui2/src/components/stories/tab_bar.rs rename to crates/ui/src/components/stories/tab_bar.rs diff --git a/crates/ui2/src/components/stories/toggle_button.rs b/crates/ui/src/components/stories/toggle_button.rs similarity index 100% rename from crates/ui2/src/components/stories/toggle_button.rs rename to crates/ui/src/components/stories/toggle_button.rs diff --git a/crates/ui2/src/components/tab.rs b/crates/ui/src/components/tab.rs similarity index 100% rename from crates/ui2/src/components/tab.rs rename to crates/ui/src/components/tab.rs diff --git a/crates/ui2/src/components/tab_bar.rs b/crates/ui/src/components/tab_bar.rs similarity index 100% rename from crates/ui2/src/components/tab_bar.rs rename to crates/ui/src/components/tab_bar.rs diff --git a/crates/ui2/src/components/tooltip.rs b/crates/ui/src/components/tooltip.rs similarity index 100% rename from crates/ui2/src/components/tooltip.rs rename to crates/ui/src/components/tooltip.rs diff --git a/crates/ui2/src/disableable.rs b/crates/ui/src/disableable.rs similarity index 100% rename from crates/ui2/src/disableable.rs rename to crates/ui/src/disableable.rs diff --git a/crates/ui2/src/fixed.rs b/crates/ui/src/fixed.rs similarity index 100% rename from crates/ui2/src/fixed.rs rename to crates/ui/src/fixed.rs diff --git a/crates/ui2/src/prelude.rs b/crates/ui/src/prelude.rs similarity index 100% rename from crates/ui2/src/prelude.rs rename to crates/ui/src/prelude.rs diff --git a/crates/ui2/src/selectable.rs b/crates/ui/src/selectable.rs similarity index 100% rename from crates/ui2/src/selectable.rs rename to crates/ui/src/selectable.rs diff --git a/crates/ui2/src/styled_ext.rs b/crates/ui/src/styled_ext.rs similarity index 100% rename from crates/ui2/src/styled_ext.rs rename to crates/ui/src/styled_ext.rs diff --git a/crates/ui2/src/styles.rs b/crates/ui/src/styles.rs similarity index 100% rename from crates/ui2/src/styles.rs rename to crates/ui/src/styles.rs diff --git a/crates/ui2/src/styles/color.rs b/crates/ui/src/styles/color.rs similarity index 100% rename from crates/ui2/src/styles/color.rs rename to crates/ui/src/styles/color.rs diff --git a/crates/ui2/src/styles/docs/elevation.md b/crates/ui/src/styles/docs/elevation.md similarity index 100% rename from crates/ui2/src/styles/docs/elevation.md rename to crates/ui/src/styles/docs/elevation.md diff --git a/crates/ui2/src/styles/elevation.rs b/crates/ui/src/styles/elevation.rs similarity index 100% rename from crates/ui2/src/styles/elevation.rs rename to crates/ui/src/styles/elevation.rs diff --git a/crates/ui2/src/styles/typography.rs b/crates/ui/src/styles/typography.rs similarity index 100% rename from crates/ui2/src/styles/typography.rs rename to crates/ui/src/styles/typography.rs diff --git a/crates/ui2/src/styles/units.rs b/crates/ui/src/styles/units.rs similarity index 100% rename from crates/ui2/src/styles/units.rs rename to crates/ui/src/styles/units.rs diff --git a/crates/ui2/src/ui2.rs b/crates/ui/src/ui.rs similarity index 100% rename from crates/ui2/src/ui2.rs rename to crates/ui/src/ui.rs diff --git a/crates/ui2/src/utils.rs b/crates/ui/src/utils.rs similarity index 100% rename from crates/ui2/src/utils.rs rename to crates/ui/src/utils.rs diff --git a/crates/ui2/src/utils/format_distance.rs b/crates/ui/src/utils/format_distance.rs similarity index 100% rename from crates/ui2/src/utils/format_distance.rs rename to crates/ui/src/utils/format_distance.rs diff --git a/crates/ui2/src/visible_on_hover.rs b/crates/ui/src/visible_on_hover.rs similarity index 100% rename from crates/ui2/src/visible_on_hover.rs rename to crates/ui/src/visible_on_hover.rs diff --git a/crates/vcs_menu/Cargo.toml b/crates/vcs_menu/Cargo.toml index 55b1b9d093..5985978396 100644 --- a/crates/vcs_menu/Cargo.toml +++ b/crates/vcs_menu/Cargo.toml @@ -11,7 +11,7 @@ fs = {path = "../fs"} gpui = {package = "gpui2", path = "../gpui2"} picker = {path = "../picker"} util = {path = "../util"} -ui = {package = "ui2", path = "../ui2"} +ui = {path = "../ui"} workspace = { path = "../workspace" } anyhow.workspace = true diff --git a/crates/vim/Cargo.toml b/crates/vim/Cargo.toml index f5ce06c6e1..4674ee987d 100644 --- a/crates/vim/Cargo.toml +++ b/crates/vim/Cargo.toml @@ -33,7 +33,7 @@ search = { path = "../search" } settings = { path = "../settings" } workspace = { path = "../workspace" } theme = { package = "theme2", path = "../theme2" } -ui = { package = "ui2", path = "../ui2"} +ui = { path = "../ui"} diagnostics = { path = "../diagnostics" } zed_actions = { path = "../zed_actions" } diff --git a/crates/welcome/Cargo.toml b/crates/welcome/Cargo.toml index cda503e48a..6bc399e404 100644 --- a/crates/welcome/Cargo.toml +++ b/crates/welcome/Cargo.toml @@ -16,7 +16,7 @@ editor = { path = "../editor" } fs = { path = "../fs" } fuzzy = { path = "../fuzzy" } gpui = { package = "gpui2", path = "../gpui2" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } db = { path = "../db" } install_cli = { path = "../install_cli" } project = { path = "../project" } diff --git a/crates/workspace/Cargo.toml b/crates/workspace/Cargo.toml index e8ac3a66e2..2183bb79e7 100644 --- a/crates/workspace/Cargo.toml +++ b/crates/workspace/Cargo.toml @@ -35,7 +35,7 @@ settings = { path = "../settings" } terminal = { path = "../terminal" } theme = { path = "../theme2", package = "theme2" } util = { path = "../util" } -ui = { package = "ui2", path = "../ui2" } +ui = { path = "../ui" } async-recursion = "1.0.0" itertools = "0.10" diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 1dc857dbfc..a0aa740963 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -64,7 +64,7 @@ settings = { path = "../settings" } feature_flags = { path = "../feature_flags" } sum_tree = { path = "../sum_tree" } shellexpand = "2.1.0" -text = { package = "text2", path = "../text2" } +text = { path = "../text" } terminal_view = { path = "../terminal_view" } theme = { package = "theme2", path = "../theme2" } theme_selector = { path = "../theme_selector" } @@ -154,7 +154,7 @@ language = { path = "../language", features = ["test-support"] } project = { path = "../project", features = ["test-support"] } # rpc = { path = "../rpc", features = ["test-support"] } # settings = { path = "../settings", features = ["test-support"] } -text = { package = "text2", path = "../text2", features = ["test-support"] } +text = { path = "../text", features = ["test-support"] } # util = { path = "../util", features = ["test-support"] } # workspace = { path = "../workspace", features = ["test-support"] } unindent.workspace = true diff --git a/script/storybook b/script/storybook index 7f5d5e8893..82694f228f 100755 --- a/script/storybook +++ b/script/storybook @@ -1,7 +1,7 @@ #!/bin/bash if [ -z "$1" ]; then - cargo run -p storybook2 + cargo run -p storybook else - cargo run -p storybook2 -- "components/$1" + cargo run -p storybook -- "components/$1" fi