@@ -10,7 +10,7 @@ use axum::{
Extension, Json, Router,
};
use collections::HashMap;
-use rpc::{ExtensionApiManifest, GetExtensionsResponse};
+use rpc::{ExtensionApiManifest, ExtensionMetadata, GetExtensionsResponse};
use semantic_version::SemanticVersion;
use serde::Deserialize;
use std::{sync::Arc, time::Duration};
@@ -43,7 +43,7 @@ async fn get_extensions(
Extension(app): Extension<Arc<AppState>>,
Query(params): Query<GetExtensionsParams>,
) -> Result<Json<GetExtensionsResponse>> {
- let extensions = app
+ let mut extensions = app
.db
.get_extensions(params.filter.as_deref(), params.max_schema_version, 500)
.await?;
@@ -53,6 +53,23 @@ async fn get_extensions(
tracing::info!(query, count, "extension_search")
}
+ if let Some(filter) = params.filter.as_deref() {
+ let mut exact_match: Option<ExtensionMetadata> = None;
+ extensions.retain(|extension| {
+ exact_match = Some(extension.clone());
+ extension.id.as_ref() != &filter.to_lowercase()
+ });
+ if exact_match == None {
+ exact_match = app
+ .db
+ .get_extensions_by_ids(&[&filter.to_lowercase()], None)
+ .await?
+ .first()
+ .cloned();
+ }
+ extensions.splice(0..0, exact_match);
+ };
+
Ok(Json(GetExtensionsResponse { data: extensions }))
}
@@ -136,11 +136,14 @@ impl ExtensionFilter {
enum Feature {
Git,
Vim,
+ LanguageBash,
LanguageC,
LanguageCpp,
LanguageGo,
LanguagePython,
+ LanguageReact,
LanguageRust,
+ LanguageTypescript,
}
fn keywords_by_feature() -> &'static BTreeMap<Feature, Vec<&'static str>> {
@@ -149,11 +152,17 @@ fn keywords_by_feature() -> &'static BTreeMap<Feature, Vec<&'static str>> {
BTreeMap::from_iter([
(Feature::Git, vec!["git"]),
(Feature::Vim, vec!["vim"]),
+ (Feature::LanguageBash, vec!["sh", "bash"]),
(Feature::LanguageC, vec!["c", "clang"]),
(Feature::LanguageCpp, vec!["c++", "cpp", "clang"]),
(Feature::LanguageGo, vec!["go", "golang"]),
(Feature::LanguagePython, vec!["python", "py"]),
+ (Feature::LanguageReact, vec!["react"]),
(Feature::LanguageRust, vec!["rust", "rs"]),
+ (
+ Feature::LanguageTypescript,
+ vec!["type", "typescript", "ts"],
+ ),
])
})
}
@@ -973,6 +982,10 @@ impl ExtensionsPage {
);
}),
)),
+ Feature::LanguageBash => {
+ FeatureUpsell::new(telemetry, "Shell support is built-in to Zed!")
+ .docs_url("https://zed.dev/docs/languages/bash")
+ }
Feature::LanguageC => {
FeatureUpsell::new(telemetry, "C support is built-in to Zed!")
.docs_url("https://zed.dev/docs/languages/c")
@@ -989,10 +1002,18 @@ impl ExtensionsPage {
FeatureUpsell::new(telemetry, "Python support is built-in to Zed!")
.docs_url("https://zed.dev/docs/languages/python")
}
+ Feature::LanguageReact => {
+ FeatureUpsell::new(telemetry, "React support is built-in to Zed!")
+ .docs_url("https://zed.dev/docs/languages/typescript")
+ }
Feature::LanguageRust => {
FeatureUpsell::new(telemetry, "Rust support is built-in to Zed!")
.docs_url("https://zed.dev/docs/languages/rust")
}
+ Feature::LanguageTypescript => {
+ FeatureUpsell::new(telemetry, "Typescript support is built-in to Zed!")
+ .docs_url("https://zed.dev/docs/languages/typescript")
+ }
};
upsell.when(ix < upsells_count, |upsell| upsell.border_b_1())
@@ -2,7 +2,7 @@ use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
-#[derive(Serialize, Deserialize, Debug, PartialEq)]
+#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct ExtensionApiManifest {
pub name: String,
pub version: Arc<str>,
@@ -13,7 +13,7 @@ pub struct ExtensionApiManifest {
pub wasm_api_version: Option<String>,
}
-#[derive(Serialize, Deserialize, Debug, PartialEq)]
+#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct ExtensionMetadata {
pub id: Arc<str>,
#[serde(flatten)]