extension: Make `provides` a method on `ExtensionManifest` (#49234)

Marshall Bowers created

This PR takes the `extension_provides` method from the `extension_cli`
and makes it a method on `ExtensionManifest`.

Release Notes:

- N/A

Change summary

Cargo.lock                                 |  1 
crates/extension/Cargo.toml                |  1 
crates/extension/src/extension_manifest.rs | 56 +++++++++++++++++++++---
crates/extension_cli/src/main.rs           | 47 -------------------
4 files changed, 53 insertions(+), 52 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -5937,6 +5937,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "async-trait",
+ "cloud_api_types",
  "collections",
  "dap",
  "fs",

crates/extension/Cargo.toml 🔗

@@ -14,6 +14,7 @@ path = "src/extension.rs"
 [dependencies]
 anyhow.workspace = true
 async-trait.workspace = true
+cloud_api_types.workspace = true
 collections.workspace = true
 dap.workspace = true
 fs.workspace = true

crates/extension/src/extension_manifest.rs 🔗

@@ -1,16 +1,16 @@
+use std::ffi::OsStr;
+use std::fmt;
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
+
 use anyhow::{Context as _, Result, anyhow, bail};
-use collections::{BTreeMap, HashMap};
+use cloud_api_types::ExtensionProvides;
+use collections::{BTreeMap, BTreeSet, HashMap};
 use fs::Fs;
 use language::LanguageName;
 use lsp::LanguageServerName;
 use semver::Version;
 use serde::{Deserialize, Serialize};
-use std::{
-    ffi::OsStr,
-    fmt,
-    path::{Path, PathBuf},
-    sync::Arc,
-};
 
 use crate::ExtensionCapability;
 
@@ -122,6 +122,48 @@ pub struct ExtensionManifest {
 }
 
 impl ExtensionManifest {
+    /// Returns the set of features provided by the extension.
+    pub fn provides(&self) -> BTreeSet<ExtensionProvides> {
+        let mut provides = BTreeSet::default();
+        if !self.themes.is_empty() {
+            provides.insert(ExtensionProvides::Themes);
+        }
+
+        if !self.icon_themes.is_empty() {
+            provides.insert(ExtensionProvides::IconThemes);
+        }
+
+        if !self.languages.is_empty() {
+            provides.insert(ExtensionProvides::Languages);
+        }
+
+        if !self.grammars.is_empty() {
+            provides.insert(ExtensionProvides::Grammars);
+        }
+
+        if !self.language_servers.is_empty() {
+            provides.insert(ExtensionProvides::LanguageServers);
+        }
+
+        if !self.context_servers.is_empty() {
+            provides.insert(ExtensionProvides::ContextServers);
+        }
+
+        if !self.agent_servers.is_empty() {
+            provides.insert(ExtensionProvides::AgentServers);
+        }
+
+        if self.snippets.is_some() {
+            provides.insert(ExtensionProvides::Snippets);
+        }
+
+        if !self.debug_adapters.is_empty() {
+            provides.insert(ExtensionProvides::DebugAdapters);
+        }
+
+        provides
+    }
+
     pub fn allow_exec(
         &self,
         desired_command: &str,

crates/extension_cli/src/main.rs 🔗

@@ -1,4 +1,4 @@
-use std::collections::{BTreeSet, HashMap};
+use std::collections::HashMap;
 use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
@@ -7,7 +7,6 @@ use std::sync::Arc;
 use ::fs::{CopyOptions, Fs, RealFs, copy_recursive};
 use anyhow::{Context as _, Result, anyhow, bail};
 use clap::Parser;
-use cloud_api_types::ExtensionProvides;
 use extension::extension_builder::{CompileExtensionOptions, ExtensionBuilder};
 use extension::{ExtensionManifest, ExtensionSnippets};
 use language::LanguageConfig;
@@ -78,7 +77,7 @@ async fn main() -> Result<()> {
         .await
         .context("failed to compile extension")?;
 
-    let extension_provides = extension_provides(&manifest);
+    let extension_provides = manifest.provides();
 
     if extension_provides.is_empty() {
         bail!("extension does not provide any features");
@@ -126,48 +125,6 @@ async fn main() -> Result<()> {
     Ok(())
 }
 
-/// Returns the set of features provided by the extension.
-fn extension_provides(manifest: &ExtensionManifest) -> BTreeSet<ExtensionProvides> {
-    let mut provides = BTreeSet::default();
-    if !manifest.themes.is_empty() {
-        provides.insert(ExtensionProvides::Themes);
-    }
-
-    if !manifest.icon_themes.is_empty() {
-        provides.insert(ExtensionProvides::IconThemes);
-    }
-
-    if !manifest.languages.is_empty() {
-        provides.insert(ExtensionProvides::Languages);
-    }
-
-    if !manifest.grammars.is_empty() {
-        provides.insert(ExtensionProvides::Grammars);
-    }
-
-    if !manifest.language_servers.is_empty() {
-        provides.insert(ExtensionProvides::LanguageServers);
-    }
-
-    if !manifest.context_servers.is_empty() {
-        provides.insert(ExtensionProvides::ContextServers);
-    }
-
-    if !manifest.agent_servers.is_empty() {
-        provides.insert(ExtensionProvides::AgentServers);
-    }
-
-    if manifest.snippets.is_some() {
-        provides.insert(ExtensionProvides::Snippets);
-    }
-
-    if !manifest.debug_adapters.is_empty() {
-        provides.insert(ExtensionProvides::DebugAdapters);
-    }
-
-    provides
-}
-
 async fn copy_extension_resources(
     manifest: &ExtensionManifest,
     extension_path: &Path,