Extract `InlineCompletionProvider` to its own crate (#20935)

Marshall Bowers created

This PR extracts the `InlineCompletionProvider` trait and its related
types out of `editor` and into a new `inline_completion` crate.

By doing so we're able to remove a dependency on `editor` from the
`copilot` and `supermaven` crates.

We did have to move `editor::Direction` into the `inline_completion`
crate, as it is referenced by the `InlineCompletionProvider`. This
should find a better home, at some point.

Release Notes:

- N/A

Change summary

Cargo.lock                                              | 13 +++++++
Cargo.toml                                              |  2 +
crates/copilot/Cargo.toml                               |  8 ++--
crates/copilot/src/copilot_completion_provider.rs       |  2 
crates/editor/Cargo.toml                                |  1 
crates/editor/src/editor.rs                             | 10 +----
crates/inline_completion/Cargo.toml                     | 18 +++++++++++
crates/inline_completion/LICENSE-GPL                    |  1 
crates/inline_completion/src/inline_completion.rs       | 11 ++++++
crates/supermaven/Cargo.toml                            |  6 +-
crates/supermaven/src/supermaven_completion_provider.rs |  2 
11 files changed, 56 insertions(+), 18 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2876,6 +2876,7 @@ dependencies = [
  "gpui",
  "http_client",
  "indoc",
+ "inline_completion",
  "language",
  "lsp",
  "menu",
@@ -3721,6 +3722,7 @@ dependencies = [
  "gpui",
  "http_client",
  "indoc",
+ "inline_completion",
  "itertools 0.13.0",
  "language",
  "linkify",
@@ -6056,6 +6058,16 @@ dependencies = [
  "syn 2.0.87",
 ]
 
+[[package]]
+name = "inline_completion"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "language",
+ "project",
+ "text",
+]
+
 [[package]]
 name = "inline_completion_button"
 version = "0.1.0"
@@ -11781,6 +11793,7 @@ dependencies = [
  "futures 0.3.31",
  "gpui",
  "http_client",
+ "inline_completion",
  "language",
  "log",
  "postage",

Cargo.toml 🔗

@@ -49,6 +49,7 @@ members = [
     "crates/http_client",
     "crates/image_viewer",
     "crates/indexed_docs",
+    "crates/inline_completion",
     "crates/inline_completion_button",
     "crates/install_cli",
     "crates/journal",
@@ -221,6 +222,7 @@ html_to_markdown = { path = "crates/html_to_markdown" }
 http_client = { path = "crates/http_client" }
 image_viewer = { path = "crates/image_viewer" }
 indexed_docs = { path = "crates/indexed_docs" }
+inline_completion = { path = "crates/inline_completion" }
 inline_completion_button = { path = "crates/inline_completion_button" }
 install_cli = { path = "crates/install_cli" }
 journal = { path = "crates/journal" }

crates/copilot/Cargo.toml 🔗

@@ -29,14 +29,14 @@ anyhow.workspace = true
 async-compression.workspace = true
 async-tar.workspace = true
 chrono.workspace = true
-collections.workspace = true
 client.workspace = true
+collections.workspace = true
 command_palette_hooks.workspace = true
-editor.workspace = true
 fs.workspace = true
 futures.workspace = true
 gpui.workspace = true
 http_client.workspace = true
+inline_completion.workspace = true
 language.workspace = true
 lsp.workspace = true
 menu.workspace = true
@@ -44,12 +44,12 @@ node_runtime.workspace = true
 parking_lot.workspace = true
 paths.workspace = true
 project.workspace = true
+schemars = { workspace = true, optional = true }
 serde.workspace = true
 serde_json.workspace = true
-schemars = { workspace = true, optional = true }
-strum.workspace = true
 settings.workspace = true
 smol.workspace = true
+strum.workspace = true
 task.workspace = true
 ui.workspace = true
 util.workspace = true

crates/copilot/src/copilot_completion_provider.rs 🔗

@@ -1,8 +1,8 @@
 use crate::{Completion, Copilot};
 use anyhow::Result;
 use client::telemetry::Telemetry;
-use editor::{CompletionProposal, Direction, InlayProposal, InlineCompletionProvider};
 use gpui::{AppContext, EntityId, Model, ModelContext, Task};
+use inline_completion::{CompletionProposal, Direction, InlayProposal, InlineCompletionProvider};
 use language::{
     language_settings::{all_language_settings, AllLanguageSettings},
     Buffer, OffsetRangeExt, ToOffset,

crates/editor/Cargo.toml 🔗

@@ -46,6 +46,7 @@ git.workspace = true
 gpui.workspace = true
 http_client.workspace = true
 indoc.workspace = true
+inline_completion.workspace = true
 itertools.workspace = true
 language.workspace = true
 linkify.workspace = true

crates/editor/src/editor.rs 🔗

@@ -28,7 +28,6 @@ mod hover_popover;
 mod hunk_diff;
 mod indent_guides;
 mod inlay_hint_cache;
-mod inline_completion_provider;
 pub mod items;
 mod linked_editing_ranges;
 mod lsp_ext;
@@ -87,7 +86,8 @@ pub(crate) use hunk_diff::HoveredHunk;
 use hunk_diff::{diff_hunk_to_display, ExpandedHunks};
 use indent_guides::ActiveIndentGuidesState;
 use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
-pub use inline_completion_provider::*;
+pub use inline_completion::Direction;
+use inline_completion::{InlayProposal, InlineCompletionProvider, InlineCompletionProviderHandle};
 pub use items::MAX_TAB_TITLE_LEN;
 use itertools::Itertools;
 use language::{
@@ -273,12 +273,6 @@ enum DocumentHighlightRead {}
 enum DocumentHighlightWrite {}
 enum InputComposition {}
 
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub enum Direction {
-    Prev,
-    Next,
-}
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum Navigated {
     Yes,

crates/inline_completion/Cargo.toml 🔗

@@ -0,0 +1,18 @@
+[package]
+name = "inline_completion"
+version = "0.1.0"
+edition = "2021"
+publish = false
+license = "GPL-3.0-or-later"
+
+[lints]
+workspace = true
+
+[lib]
+path = "src/inline_completion.rs"
+
+[dependencies]
+gpui.workspace = true
+language.workspace = true
+project.workspace = true
+text.workspace = true

crates/editor/src/inline_completion_provider.rs → crates/inline_completion/src/inline_completion.rs 🔗

@@ -1,9 +1,18 @@
-use crate::Direction;
 use gpui::{AppContext, Model, ModelContext};
 use language::Buffer;
 use std::ops::Range;
 use text::{Anchor, Rope};
 
+// TODO: Find a better home for `Direction`.
+//
+// This should live in an ancestor crate of `editor` and `inline_completion`,
+// but at time of writing there isn't an obvious spot.
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub enum Direction {
+    Prev,
+    Next,
+}
+
 pub enum InlayProposal {
     Hint(Anchor, project::InlayHint),
     Suggestion(Anchor, Rope),

crates/supermaven/Cargo.toml 🔗

@@ -16,17 +16,17 @@ doctest = false
 anyhow.workspace = true
 client.workspace = true
 collections.workspace = true
-editor.workspace = true
-gpui.workspace = true
 futures.workspace = true
+gpui.workspace = true
+inline_completion.workspace = true
 language.workspace = true
 log.workspace = true
 postage.workspace = true
 serde.workspace = true
 serde_json.workspace = true
 settings.workspace = true
-supermaven_api.workspace = true
 smol.workspace = true
+supermaven_api.workspace = true
 text.workspace = true
 ui.workspace = true
 unicode-segmentation.workspace = true

crates/supermaven/src/supermaven_completion_provider.rs 🔗

@@ -1,9 +1,9 @@
 use crate::{Supermaven, SupermavenCompletionStateId};
 use anyhow::Result;
 use client::telemetry::Telemetry;
-use editor::{CompletionProposal, Direction, InlayProposal, InlineCompletionProvider};
 use futures::StreamExt as _;
 use gpui::{AppContext, EntityId, Model, ModelContext, Task};
+use inline_completion::{CompletionProposal, Direction, InlayProposal, InlineCompletionProvider};
 use language::{language_settings::all_language_settings, Anchor, Buffer, BufferSnapshot};
 use std::{
     ops::{AddAssign, Range},