fix(plugins): read the marketplace index on first open (#1378)

On a fresh install, Settings › Plugins › Available showed no marketplace plugins until the user refreshed by hand: opening the page asked for the listing without a refresh, which only returned the cached index, and a first run has none. The listing now reads the index when none has been read yet; later opens keep using the index already read, and an explicit refresh reads it again.
This commit is contained in:
l0ng-ai
2026-11-05 10:04:42 +08:00
committed by GitHub
parent 1248c3231e
commit 89ffde304b
4 changed files with 35 additions and 3 deletions
+10
View File
@@ -165,6 +165,16 @@ impl PluginHost {
self.save_state();
}
/// The marketplace's plugins: read again when `refresh`, else the last index
/// read. Reads it when none has been read yet (first run, nothing cached).
pub fn market_listing(&self, refresh: bool) -> IdeResult<Vec<MarketPlugin>> {
if refresh || (self.market.read().is_none() && self.market_url().is_some()) {
self.refresh_market()
} else {
Ok(self.market_plugins())
}
}
/// Reads the index again, keeps it, and applies its revocations. Announces
/// updates of installed plugins it hasn't announced yet.
pub fn refresh_market(&self) -> IdeResult<Vec<MarketPlugin>> {
+22
View File
@@ -196,6 +196,28 @@ fn write_index(
path.to_string_lossy().into_owned()
}
/// First run: nothing cached yet, so listing the marketplace reads its index
/// instead of showing an empty one; later listings use the index read.
#[test]
fn the_first_marketplace_listing_reads_the_index() {
let f = fixture();
assert!(f.host.market_listing(false).unwrap().is_empty(), "no marketplace configured");
let market = f.work.join("market");
std::fs::create_dir_all(&market).unwrap();
let key = PublisherKey::from_seed([3; 32]);
let (_, entry) = signed_hello(&market, "1.0.0", &key, &f.host);
let url = write_index(&market, &key, vec![entry], vec![], false);
f.host.set_market_url(Some(url.clone()));
let listed = f.host.market_listing(false).unwrap();
assert_eq!(listed.iter().map(|p| p.entry.id.as_str()).collect::<Vec<_>>(), ["acme.hello"]);
std::fs::remove_file(&url).unwrap();
assert_eq!(f.host.market_listing(false).unwrap().len(), 1, "the index read is kept");
assert!(f.host.market_listing(true).is_err(), "refresh reads the index again");
}
#[test]
fn signed_marketplace_plugins_install_and_revocations_disable_them() {
let f = fixture();
+2 -2
View File
@@ -473,7 +473,7 @@ pub async fn plugin_web_read_file(path: PathBuf) -> IdeResult<String> {
Ok(base64::engine::general_purpose::STANDARD.encode(bytes))
}
/// The marketplace's plugins: read again when `refresh`, else the last index read.
/// The marketplace's plugins: read again when `refresh` or when none was read yet, else the last index read.
#[tauri::command]
#[specta::specta]
pub async fn plugin_market(
@@ -481,7 +481,7 @@ pub async fn plugin_market(
refresh: bool,
) -> IdeResult<Vec<ide_host::plugins::MarketPlugin>> {
let host = state.plugins.clone();
blocking(move || if refresh { host.refresh_market() } else { Ok(host.market_plugins()) }).await
blocking(move || host.market_listing(refresh)).await
}
#[tauri::command]
+1 -1
View File
@@ -999,7 +999,7 @@ export const commands = {
pluginWebReadFile: (path: string) => typedError<string, IdeError>(__TAURI_INVOKE("plugin_web_read_file", { path })),
/** Gutter markers of plugin `line-markers` providers for an open document. */
pluginLineMarkers: (doc: DocId) => typedError<LineMarkerInfo[], IdeError>(__TAURI_INVOKE("plugin_line_markers", { doc })),
/** The marketplace's plugins: read again when `refresh`, else the last index read. */
/** The marketplace's plugins: read again when `refresh` or when none was read yet, else the last index read. */
pluginMarket: (refresh: boolean) => typedError<MarketPlugin[], IdeError>(__TAURI_INVOKE("plugin_market", { refresh })),
pluginMarketUrl: () => __TAURI_INVOKE<string | null>("plugin_market_url"),
/** Sets the marketplace index URL (an `https://…/index.json` or a local path; `None` for the default). */