785 lines · 28.1 KB · Rust
RawDownload
use crate::{    Event, ExtensionIndex, ExtensionIndexEntry, ExtensionIndexLanguageEntry,    ExtensionIndexThemeEntry, ExtensionManifest, ExtensionSettings, ExtensionStore,    GrammarManifestEntry, SchemaVersion, RELOAD_DEBOUNCE_DURATION,};use async_compression::futures::bufread::GzipEncoder;use collections::BTreeMap;use extension::ExtensionHostProxy;use fs::{FakeFs, Fs, RealFs};use futures::{io::BufReader, AsyncReadExt, StreamExt};use gpui::{AppContext as _, SemanticVersion, TestAppContext};use http_client::{FakeHttpClient, Response};use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus};use lsp::LanguageServerName;use node_runtime::NodeRuntime;use parking_lot::Mutex;use project::{Project, DEFAULT_COMPLETION_CONTEXT};use release_channel::AppVersion;use reqwest_client::ReqwestClient;use serde_json::json;use settings::{Settings as _, SettingsStore};use std::{    ffi::OsString,    path::{Path, PathBuf},    sync::Arc,};use theme::ThemeRegistry;use util::test::TempTree; #[cfg(test)]#[ctor::ctor]fn init_logger() {    if std::env::var("RUST_LOG").is_ok() {        env_logger::init();    }} #[gpui::test]async fn test_extension_store(cx: &mut TestAppContext) {    init_test(cx);     let fs = FakeFs::new(cx.executor());    let http_client = FakeHttpClient::with_200_response();     fs.insert_tree(        "/the-extension-dir",        json!({            "installed": {                "zed-monokai": {                    "extension.json": r#"{                        "id": "zed-monokai",                        "name": "Zed Monokai",                        "version": "2.0.0",                        "themes": {                            "Monokai Dark": "themes/monokai.json",                            "Monokai Light": "themes/monokai.json",                            "Monokai Pro Dark": "themes/monokai-pro.json",                            "Monokai Pro Light": "themes/monokai-pro.json"                        }                    }"#,                    "themes": {                        "monokai.json": r#"{                            "name": "Monokai",                            "author": "Someone",                            "themes": [                                {                                    "name": "Monokai Dark",                                    "appearance": "dark",                                    "style": {}                                },                                {                                    "name": "Monokai Light",                                    "appearance": "light",                                    "style": {}                                }                            ]                        }"#,                        "monokai-pro.json": r#"{                            "name": "Monokai Pro",                            "author": "Someone",                            "themes": [                                {                                    "name": "Monokai Pro Dark",                                    "appearance": "dark",                                    "style": {}                                },                                {                                    "name": "Monokai Pro Light",                                    "appearance": "light",                                    "style": {}                                }                            ]                        }"#,                    }                },                "zed-ruby": {                    "extension.json": r#"{                        "id": "zed-ruby",                        "name": "Zed Ruby",                        "version": "1.0.0",                        "grammars": {                            "ruby": "grammars/ruby.wasm",                            "embedded_template": "grammars/embedded_template.wasm"                        },                        "languages": {                            "ruby": "languages/ruby",                            "erb": "languages/erb"                        }                    }"#,                    "grammars": {                        "ruby.wasm": "",                        "embedded_template.wasm": "",                    },                    "languages": {                        "ruby": {                            "config.toml": r#"                                name = "Ruby"                                grammar = "ruby"                                path_suffixes = ["rb"]                            "#,                            "highlights.scm": "",                        },                        "erb": {                            "config.toml": r#"                                name = "ERB"                                grammar = "embedded_template"                                path_suffixes = ["erb"]                            "#,                            "highlights.scm": "",                        }                    },                }            }        }),    )    .await;     let mut expected_index = ExtensionIndex {        extensions: [            (                "zed-ruby".into(),                ExtensionIndexEntry {                    manifest: Arc::new(ExtensionManifest {                        id: "zed-ruby".into(),                        name: "Zed Ruby".into(),                        version: "1.0.0".into(),                        schema_version: SchemaVersion::ZERO,                        description: None,                        authors: Vec::new(),                        repository: None,                        themes: Default::default(),                        icon_themes: Vec::new(),                        lib: Default::default(),                        languages: vec!["languages/erb".into(), "languages/ruby".into()],                        grammars: [                            ("embedded_template".into(), GrammarManifestEntry::default()),                            ("ruby".into(), GrammarManifestEntry::default()),                        ]                        .into_iter()                        .collect(),                        language_servers: BTreeMap::default(),                        context_servers: BTreeMap::default(),                        slash_commands: BTreeMap::default(),                        indexed_docs_providers: BTreeMap::default(),                        snippets: None,                    }),                    dev: false,                },            ),            (                "zed-monokai".into(),                ExtensionIndexEntry {                    manifest: Arc::new(ExtensionManifest {                        id: "zed-monokai".into(),                        name: "Zed Monokai".into(),                        version: "2.0.0".into(),                        schema_version: SchemaVersion::ZERO,                        description: None,                        authors: vec![],                        repository: None,                        themes: vec![                            "themes/monokai-pro.json".into(),                            "themes/monokai.json".into(),                        ],                        icon_themes: Vec::new(),                        lib: Default::default(),                        languages: Default::default(),                        grammars: BTreeMap::default(),                        language_servers: BTreeMap::default(),                        context_servers: BTreeMap::default(),                        slash_commands: BTreeMap::default(),                        indexed_docs_providers: BTreeMap::default(),                        snippets: None,                    }),                    dev: false,                },            ),        ]        .into_iter()        .collect(),        languages: [            (                "ERB".into(),                ExtensionIndexLanguageEntry {                    extension: "zed-ruby".into(),                    path: "languages/erb".into(),                    grammar: Some("embedded_template".into()),                    hidden: false,                    matcher: LanguageMatcher {                        path_suffixes: vec!["erb".into()],                        first_line_pattern: None,                    },                },            ),            (                "Ruby".into(),                ExtensionIndexLanguageEntry {                    extension: "zed-ruby".into(),                    path: "languages/ruby".into(),                    grammar: Some("ruby".into()),                    hidden: false,                    matcher: LanguageMatcher {                        path_suffixes: vec!["rb".into()],                        first_line_pattern: None,                    },                },            ),        ]        .into_iter()        .collect(),        themes: [            (                "Monokai Dark".into(),                ExtensionIndexThemeEntry {                    extension: "zed-monokai".into(),                    path: "themes/monokai.json".into(),                },            ),            (                "Monokai Light".into(),                ExtensionIndexThemeEntry {                    extension: "zed-monokai".into(),                    path: "themes/monokai.json".into(),                },            ),            (                "Monokai Pro Dark".into(),                ExtensionIndexThemeEntry {                    extension: "zed-monokai".into(),                    path: "themes/monokai-pro.json".into(),                },            ),            (                "Monokai Pro Light".into(),                ExtensionIndexThemeEntry {                    extension: "zed-monokai".into(),                    path: "themes/monokai-pro.json".into(),                },            ),        ]        .into_iter()        .collect(),        icon_themes: BTreeMap::default(),    };     let proxy = Arc::new(ExtensionHostProxy::new());    let theme_registry = Arc::new(ThemeRegistry::new(Box::new(())));    theme_extension::init(proxy.clone(), theme_registry.clone(), cx.executor());    let language_registry = Arc::new(LanguageRegistry::test(cx.executor()));    language_extension::init(proxy.clone(), language_registry.clone());    let node_runtime = NodeRuntime::unavailable();     let store = cx.new(|cx| {        ExtensionStore::new(            PathBuf::from("/the-extension-dir"),            None,            proxy.clone(),            fs.clone(),            http_client.clone(),            http_client.clone(),            None,            node_runtime.clone(),            cx,        )    });     cx.executor().advance_clock(RELOAD_DEBOUNCE_DURATION);    store.read_with(cx, |store, _| {        let index = &store.extension_index;        assert_eq!(index.extensions, expected_index.extensions);        assert_eq!(index.languages, expected_index.languages);        assert_eq!(index.themes, expected_index.themes);         assert_eq!(            language_registry.language_names(),            ["ERB", "Plain Text", "Ruby"]        );        assert_eq!(            theme_registry.list_names(),            [                "Monokai Dark",                "Monokai Light",                "Monokai Pro Dark",                "Monokai Pro Light",                "One Dark",            ]        );    });     fs.insert_tree(        "/the-extension-dir/installed/zed-gruvbox",        json!({            "extension.json": r#"{                "id": "zed-gruvbox",                "name": "Zed Gruvbox",                "version": "1.0.0",                "themes": {                    "Gruvbox": "themes/gruvbox.json"                }            }"#,            "themes": {                "gruvbox.json": r#"{                    "name": "Gruvbox",                    "author": "Someone Else",                    "themes": [                        {                            "name": "Gruvbox",                            "appearance": "dark",                            "style": {}                        }                    ]                }"#,            }        }),    )    .await;     expected_index.extensions.insert(        "zed-gruvbox".into(),        ExtensionIndexEntry {            manifest: Arc::new(ExtensionManifest {                id: "zed-gruvbox".into(),                name: "Zed Gruvbox".into(),                version: "1.0.0".into(),                schema_version: SchemaVersion::ZERO,                description: None,                authors: vec![],                repository: None,                themes: vec!["themes/gruvbox.json".into()],                icon_themes: Vec::new(),                lib: Default::default(),                languages: Default::default(),                grammars: BTreeMap::default(),                language_servers: BTreeMap::default(),                context_servers: BTreeMap::default(),                slash_commands: BTreeMap::default(),                indexed_docs_providers: BTreeMap::default(),                snippets: None,            }),            dev: false,        },    );    expected_index.themes.insert(        "Gruvbox".into(),        ExtensionIndexThemeEntry {            extension: "zed-gruvbox".into(),            path: "themes/gruvbox.json".into(),        },    );     #[allow(clippy::let_underscore_future)]    let _ = store.update(cx, |store, cx| store.reload(None, cx));     cx.executor().advance_clock(RELOAD_DEBOUNCE_DURATION);    store.read_with(cx, |store, _| {        let index = &store.extension_index;        assert_eq!(index.extensions, expected_index.extensions);        assert_eq!(index.languages, expected_index.languages);        assert_eq!(index.themes, expected_index.themes);         assert_eq!(            theme_registry.list_names(),            [                "Gruvbox",                "Monokai Dark",                "Monokai Light",                "Monokai Pro Dark",                "Monokai Pro Light",                "One Dark",            ]        );    });     let prev_fs_metadata_call_count = fs.metadata_call_count();    let prev_fs_read_dir_call_count = fs.read_dir_call_count();     // Create new extension store, as if Zed were restarting.    drop(store);    let store = cx.new(|cx| {        ExtensionStore::new(            PathBuf::from("/the-extension-dir"),            None,            proxy,            fs.clone(),            http_client.clone(),            http_client.clone(),            None,            node_runtime.clone(),            cx,        )    });     cx.executor().run_until_parked();    store.read_with(cx, |store, _| {        assert_eq!(store.extension_index, expected_index);        assert_eq!(            language_registry.language_names(),            ["ERB", "Plain Text", "Ruby"]        );        assert_eq!(            language_registry.grammar_names(),            ["embedded_template".into(), "ruby".into()]        );        assert_eq!(            theme_registry.list_names(),            [                "Gruvbox",                "Monokai Dark",                "Monokai Light",                "Monokai Pro Dark",                "Monokai Pro Light",                "One Dark",            ]        );         // The on-disk manifest limits the number of FS calls that need to be made        // on startup.        assert_eq!(fs.read_dir_call_count(), prev_fs_read_dir_call_count);        assert_eq!(fs.metadata_call_count(), prev_fs_metadata_call_count + 2);    });     store.update(cx, |store, cx| {        store.uninstall_extension("zed-ruby".into(), cx)    });     cx.executor().advance_clock(RELOAD_DEBOUNCE_DURATION);    expected_index.extensions.remove("zed-ruby");    expected_index.languages.remove("Ruby");    expected_index.languages.remove("ERB");     store.read_with(cx, |store, _| {        assert_eq!(store.extension_index, expected_index);        assert_eq!(language_registry.language_names(), ["Plain Text"]);        assert_eq!(language_registry.grammar_names(), []);    });} // todo(windows)// Disable this test on Windows for now. Because this test hangs at// `let fake_server = fake_servers.next().await.unwrap();`.// Reenable this test when we figure out why.#[gpui::test]#[cfg_attr(target_os = "windows", ignore)]async fn test_extension_store_with_test_extension(cx: &mut TestAppContext) {    init_test(cx);    cx.executor().allow_parking();     let root_dir = Path::new(env!("CARGO_MANIFEST_DIR"))        .parent()        .unwrap()        .parent()        .unwrap();    let cache_dir = root_dir.join("target");    let test_extension_id = "test-extension";    let test_extension_dir = root_dir.join("extensions").join(test_extension_id);     let fs = Arc::new(RealFs::default());    let extensions_dir = TempTree::new(json!({        "installed": {},        "work": {}    }));    let project_dir = TempTree::new(json!({        "test.gleam": ""    }));     let extensions_dir = extensions_dir.path().canonicalize().unwrap();    let project_dir = project_dir.path().canonicalize().unwrap();     let project = Project::test(fs.clone(), [project_dir.as_path()], cx).await;     let proxy = Arc::new(ExtensionHostProxy::new());    let theme_registry = Arc::new(ThemeRegistry::new(Box::new(())));    theme_extension::init(proxy.clone(), theme_registry.clone(), cx.executor());    let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());    language_extension::init(proxy.clone(), language_registry.clone());    let node_runtime = NodeRuntime::unavailable();     let mut status_updates = language_registry.language_server_binary_statuses();     struct FakeLanguageServerVersion {

Lines 1–500 of 785.