├── .gitignore ├── languages ├── php │ ├── indents.scm │ ├── overrides.scm │ ├── brackets.scm │ ├── injections.scm │ ├── debugger.scm │ ├── embedding.scm │ ├── textobjects.scm │ ├── outline.scm │ ├── config.toml │ ├── tags.scm │ ├── tasks.json │ ├── runnables.scm │ └── highlights.scm └── phpdoc │ ├── highlights.scm │ └── config.toml ├── src ├── language_servers.rs ├── language_servers │ ├── phpactor.rs │ ├── phptools.rs │ └── intelephense.rs ├── php.rs └── xdebug.rs ├── Cargo.toml ├── .github └── workflows │ ├── release_version.yml │ └── bump_version.yml ├── extension.toml ├── debug_adapter_schemas └── Xdebug.json ├── LICENSE-APACHE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | grammars/ 3 | *.wasm 4 | -------------------------------------------------------------------------------- /languages/php/indents.scm: -------------------------------------------------------------------------------- 1 | (_ "{" "}" @end) @indent 2 | -------------------------------------------------------------------------------- /languages/php/overrides.scm: -------------------------------------------------------------------------------- 1 | (comment) @comment.inclusive 2 | 3 | [ 4 | (string) 5 | (encapsed_string) 6 | ] @string 7 | -------------------------------------------------------------------------------- /languages/php/brackets.scm: -------------------------------------------------------------------------------- 1 | ("{" @open "}" @close) 2 | ("(" @open ")" @close) 3 | ("[" @open "]" @close) 4 | ("\"" @open "\"" @close) 5 | -------------------------------------------------------------------------------- /src/language_servers.rs: -------------------------------------------------------------------------------- 1 | mod intelephense; 2 | mod phpactor; 3 | mod phptools; 4 | 5 | pub use intelephense::*; 6 | pub use phpactor::*; 7 | pub use phptools::*; 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zed_php" 3 | version = "0.4.5" 4 | edition = "2021" 5 | publish = false 6 | license = "Apache-2.0" 7 | 8 | [lib] 9 | path = "src/php.rs" 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | zed_extension_api = "0.7.0" 14 | -------------------------------------------------------------------------------- /languages/phpdoc/highlights.scm: -------------------------------------------------------------------------------- 1 | (tag_name) @keyword 2 | 3 | (tag (variable_name) @variable) 4 | (variable_name "$" @operator) 5 | 6 | (tag 7 | (tag_name) @keyword 8 | (#eq? @keyword "@method") 9 | (name) @function.method) 10 | 11 | (primitive_type) @type.builtin 12 | (named_type (name) @type) @type 13 | (named_type (qualified_name) @type) @type 14 | -------------------------------------------------------------------------------- /languages/phpdoc/config.toml: -------------------------------------------------------------------------------- 1 | name = "PHPDoc" 2 | grammar = "phpdoc" 3 | autoclose_before = "]})>" 4 | brackets = [ 5 | { start = "{", end = "}", close = true, newline = false }, 6 | { start = "[", end = "]", close = true, newline = false }, 7 | { start = "(", end = ")", close = true, newline = false }, 8 | { start = "<", end = ">", close = true, newline = false }, 9 | ] 10 | hidden = true 11 | -------------------------------------------------------------------------------- /languages/php/injections.scm: -------------------------------------------------------------------------------- 1 | ((text) @injection.content 2 | (#set! injection.language "html") 3 | (#set! injection.combined)) 4 | 5 | ((comment) @injection.content 6 | (#match? @injection.content "^/\\*\\*[^*]") 7 | (#set! injection.language "phpdoc")) 8 | 9 | ((comment) @injection.content 10 | (#set! injection.language "comment")) 11 | 12 | ((heredoc_body) (heredoc_end) @injection.language) @injection.content 13 | 14 | ((nowdoc_body) (heredoc_end) @injection.language) @injection.content 15 | -------------------------------------------------------------------------------- /.github/workflows/release_version.yml: -------------------------------------------------------------------------------- 1 | # Generated from xtask::workflows::extensions::release_version within the Zed repository. 2 | # Rebuild with `cargo xtask workflows`. 3 | name: extensions::release_version 4 | on: 5 | push: 6 | tags: 7 | - v** 8 | jobs: 9 | call_release_version: 10 | uses: zed-industries/zed/.github/workflows/extension_release.yml@main 11 | secrets: 12 | app-id: ${{ secrets.ZED_ZIPPY_APP_ID }} 13 | app-secret: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }} 14 | -------------------------------------------------------------------------------- /languages/php/debugger.scm: -------------------------------------------------------------------------------- 1 | ; e.g. `$age = 25` matches `$age` 2 | (expression_statement 3 | (assignment_expression 4 | left: (variable_name) @debug-variable 5 | ) 6 | ) 7 | 8 | ; e.g. `++$age` matches `$age` 9 | (expression_statement 10 | (update_expression 11 | argument: (variable_name) @debug-variable 12 | ) 13 | ) 14 | 15 | ; e.g. `if ($age > 18)` matches `$age` 16 | (binary_expression 17 | left: (variable_name) @debug-variable 18 | ) 19 | 20 | ; e.g. `if (18 < $age)` matches `$age` 21 | (binary_expression 22 | right: (variable_name) @debug-variable 23 | ) 24 | 25 | ; e.g. `__construct(int $age)` matches `$age` 26 | (simple_parameter 27 | name: (variable_name) @debug-variable 28 | ) 29 | -------------------------------------------------------------------------------- /languages/php/embedding.scm: -------------------------------------------------------------------------------- 1 | ( 2 | (comment)* @context 3 | . 4 | [ 5 | (function_definition 6 | "function" @name 7 | name: (_) @name 8 | body: (_ 9 | "{" @keep 10 | "}" @keep) @collapse 11 | ) 12 | 13 | (trait_declaration 14 | "trait" @name 15 | name: (_) @name) 16 | 17 | (method_declaration 18 | "function" @name 19 | name: (_) @name 20 | body: (_ 21 | "{" @keep 22 | "}" @keep) @collapse 23 | ) 24 | 25 | (interface_declaration 26 | "interface" @name 27 | name: (_) @name 28 | ) 29 | 30 | (enum_declaration 31 | "enum" @name 32 | name: (_) @name 33 | ) 34 | 35 | ] @item 36 | ) 37 | -------------------------------------------------------------------------------- /extension.toml: -------------------------------------------------------------------------------- 1 | id = "php" 2 | name = "PHP" 3 | description = "PHP support." 4 | version = "0.4.5" 5 | schema_version = 1 6 | authors = ["Piotr Osiewicz "] 7 | repository = "https://github.com/zed-extensions/php" 8 | 9 | [language_servers.phptools] 10 | name = "PhpTools" 11 | language = "PHP" 12 | language_ids = { PHP = "php" } 13 | 14 | [language_servers.intelephense] 15 | name = "Intelephense" 16 | language = "PHP" 17 | language_ids = { PHP = "php" } 18 | 19 | [language_servers.phpactor] 20 | name = "Phpactor" 21 | language = "PHP" 22 | 23 | [debug_adapters.Xdebug] 24 | 25 | [grammars.php] 26 | repository = "https://github.com/tree-sitter/tree-sitter-php" 27 | commit = "8ab93274065cbaf529ea15c24360cfa3348ec9e4" 28 | path = "php" 29 | 30 | [grammars.phpdoc] 31 | repository = "https://github.com/claytonrcarter/tree-sitter-phpdoc" 32 | commit = "03bb10330704b0b371b044e937d5cc7cd40b4999" 33 | -------------------------------------------------------------------------------- /languages/php/textobjects.scm: -------------------------------------------------------------------------------- 1 | (function_definition 2 | body: (_ 3 | "{" 4 | (_)* @function.inside 5 | "}" )) @function.around 6 | 7 | (method_declaration 8 | body: (_ 9 | "{" 10 | (_)* @function.inside 11 | "}" )) @function.around 12 | 13 | (method_declaration) @function.around 14 | 15 | (class_declaration 16 | body: (_ 17 | "{" 18 | (_)* @class.inside 19 | "}")) @class.around 20 | 21 | (interface_declaration 22 | body: (_ 23 | "{" 24 | (_)* @class.inside 25 | "}")) @class.around 26 | 27 | (trait_declaration 28 | body: (_ 29 | "{" 30 | (_)* @class.inside 31 | "}")) @class.around 32 | 33 | (enum_declaration 34 | body: (_ 35 | "{" 36 | (_)* @class.inside 37 | "}")) @class.around 38 | 39 | (namespace_definition 40 | body: (_ 41 | "{" 42 | (_)* @class.inside 43 | "}")) @class.around 44 | 45 | (comment)+ @comment.around 46 | -------------------------------------------------------------------------------- /languages/php/outline.scm: -------------------------------------------------------------------------------- 1 | (class_declaration 2 | "class" @context 3 | name: (name) @name 4 | ) @item 5 | 6 | (function_definition 7 | "function" @context 8 | name: (_) @name 9 | ) @item 10 | 11 | (method_declaration 12 | "function" @context 13 | name: (_) @name 14 | ) @item 15 | 16 | (interface_declaration 17 | "interface" @context 18 | name: (_) @name 19 | ) @item 20 | 21 | (enum_declaration 22 | "enum" @context 23 | name: (_) @name 24 | ) @item 25 | 26 | (trait_declaration 27 | "trait" @context 28 | name: (_) @name 29 | ) @item 30 | 31 | ; Add support for Pest runnable 32 | (function_call_expression 33 | function: (_) @context 34 | (#any-of? @context "it" "test" "describe") 35 | arguments: (arguments 36 | . 37 | (argument 38 | [ 39 | (encapsed_string (string_value) @name) 40 | (string (string_value) @name) 41 | ] 42 | ) 43 | ) 44 | ) @item 45 | 46 | (comment) @annotation 47 | -------------------------------------------------------------------------------- /languages/php/config.toml: -------------------------------------------------------------------------------- 1 | name = "PHP" 2 | grammar = "php" 3 | path_suffixes = ["php"] 4 | first_line_pattern = '^#!.*php' 5 | line_comments = ["// ", "# "] 6 | block_comment = { start = "/*", end = "*/", prefix = "* ", tab_size = 1 } 7 | documentation_comment = { start = "/**", end = "*/", prefix = "* ", tab_size = 1 } 8 | autoclose_before = ";:.,=}])>" 9 | brackets = [ 10 | { start = "{", end = "}", close = true, newline = true }, 11 | { start = "[", end = "]", close = true, newline = true }, 12 | { start = "(", end = ")", close = true, newline = true }, 13 | { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] }, 14 | { start = "'", end = "'", close = true, newline = false, not_in = ["string"] }, 15 | { start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] }, 16 | ] 17 | collapsed_placeholder = "/* ... */" 18 | scope_opt_in_language_servers = ["tailwindcss-language-server"] 19 | prettier_parser_name = "php" 20 | prettier_plugins = ["@prettier/plugin-php"] 21 | completion_query_characters = ["$"] 22 | word_characters = ["$"] 23 | -------------------------------------------------------------------------------- /languages/php/tags.scm: -------------------------------------------------------------------------------- 1 | (namespace_definition 2 | name: (namespace_name) @name) @module 3 | 4 | (interface_declaration 5 | name: (name) @name) @definition.interface 6 | 7 | (trait_declaration 8 | name: (name) @name) @definition.interface 9 | 10 | (class_declaration 11 | name: (name) @name) @definition.class 12 | 13 | (class_interface_clause [(name) (qualified_name)] @name) @impl 14 | 15 | (property_declaration 16 | (property_element (variable_name (name) @name))) @definition.field 17 | 18 | (function_definition 19 | name: (name) @name) @definition.function 20 | 21 | (method_declaration 22 | name: (name) @name) @definition.function 23 | 24 | (object_creation_expression 25 | [ 26 | (qualified_name (name) @name) 27 | (variable_name (name) @name) 28 | ]) @reference.class 29 | 30 | (function_call_expression 31 | function: [ 32 | (qualified_name (name) @name) 33 | (variable_name (name)) @name 34 | ]) @reference.call 35 | 36 | (scoped_call_expression 37 | name: (name) @name) @reference.call 38 | 39 | (member_call_expression 40 | name: (name) @name) @reference.call 41 | -------------------------------------------------------------------------------- /languages/php/tasks.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "label": "phpunit test $ZED_SYMBOL", 4 | "command": "./vendor/bin/phpunit", 5 | "args": ["--filter", "\"$ZED_SYMBOL\"", "$ZED_FILE"], 6 | "tags": ["phpunit-test"] 7 | }, 8 | { 9 | "label": "phpunit test $ZED_FILENAME", 10 | "command": "./vendor/bin/phpunit", 11 | "args": ["$ZED_FILE"], 12 | "tags": ["phpunit-test"] 13 | }, 14 | { 15 | "label": "phpunit run all tests", 16 | "command": "./vendor/bin/phpunit", 17 | "args": [], 18 | "tags": ["phpunit-test"] 19 | }, 20 | { 21 | "label": "pest test $ZED_SYMBOL", 22 | "command": "./vendor/bin/pest", 23 | "args": ["--filter", "\"$ZED_SYMBOL\"", "$ZED_FILE"], 24 | "tags": ["pest-test"] 25 | }, 26 | { 27 | "label": "pest test $ZED_FILENAME", 28 | "command": "./vendor/bin/pest", 29 | "args": ["$ZED_FILE"], 30 | "tags": ["pest-test"] 31 | }, 32 | { 33 | "label": "pest run all tests", 34 | "command": "./vendor/bin/pest", 35 | "args": [], 36 | "tags": ["pest-test"] 37 | }, 38 | { 39 | "label": "execute selection $ZED_SELECTED_TEXT", 40 | "command": "php", 41 | "args": ["-r", "$ZED_SELECTED_TEXT"] 42 | } 43 | ] 44 | -------------------------------------------------------------------------------- /.github/workflows/bump_version.yml: -------------------------------------------------------------------------------- 1 | # Generated from xtask::workflows::extensions::bump_version within the Zed repository. 2 | # Rebuild with `cargo xtask workflows`. 3 | name: extensions::bump_version 4 | on: 5 | pull_request: 6 | types: 7 | - labeled 8 | push: 9 | branches: 10 | - main 11 | paths-ignore: 12 | - .github/** 13 | workflow_dispatch: {} 14 | jobs: 15 | determine_bump_type: 16 | runs-on: namespace-profile-16x32-ubuntu-2204 17 | steps: 18 | - id: get-bump-type 19 | name: extensions::bump_version::get_bump_type 20 | run: | 21 | if [ "$HAS_MAJOR_LABEL" = "true" ]; then 22 | bump_type="major" 23 | elif [ "$HAS_MINOR_LABEL" = "true" ]; then 24 | bump_type="minor" 25 | else 26 | bump_type="patch" 27 | fi 28 | echo "bump_type=$bump_type" >> $GITHUB_OUTPUT 29 | shell: bash -euxo pipefail {0} 30 | env: 31 | HAS_MAJOR_LABEL: |- 32 | ${{ (github.event.action == 'labeled' && github.event.label.name == 'major') || 33 | (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'major')) }} 34 | HAS_MINOR_LABEL: |- 35 | ${{ (github.event.action == 'labeled' && github.event.label.name == 'minor') || 36 | (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'minor')) }} 37 | outputs: 38 | bump_type: ${{ steps.get-bump-type.outputs.bump_type }} 39 | call_bump_version: 40 | needs: 41 | - determine_bump_type 42 | if: github.event.action != 'labeled' || needs.determine_bump_type.outputs.bump_type != 'patch' 43 | uses: zed-industries/zed/.github/workflows/extension_bump.yml@main 44 | secrets: 45 | app-id: ${{ secrets.ZED_ZIPPY_APP_ID }} 46 | app-secret: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }} 47 | with: 48 | bump-type: ${{ needs.determine_bump_type.outputs.bump_type }} 49 | force-bump: true 50 | concurrency: 51 | group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}labels 52 | cancel-in-progress: true 53 | -------------------------------------------------------------------------------- /src/language_servers/phpactor.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | use zed_extension_api::{self as zed, LanguageServerId, Result}; 4 | 5 | pub struct Phpactor { 6 | cached_binary_path: Option, 7 | } 8 | 9 | impl Phpactor { 10 | pub const LANGUAGE_SERVER_ID: &'static str = "phpactor"; 11 | 12 | pub fn new() -> Self { 13 | Self { 14 | cached_binary_path: None, 15 | } 16 | } 17 | 18 | pub fn language_server_binary_path( 19 | &mut self, 20 | language_server_id: &LanguageServerId, 21 | worktree: &zed::Worktree, 22 | ) -> Result { 23 | if let Some(path) = worktree.which("phpactor") { 24 | return Ok(path); 25 | } 26 | 27 | if let Some(path) = &self.cached_binary_path { 28 | if fs::metadata(path).is_ok_and(|stat| stat.is_file()) { 29 | return Ok(path.clone()); 30 | } 31 | } 32 | 33 | zed::set_language_server_installation_status( 34 | language_server_id, 35 | &zed::LanguageServerInstallationStatus::CheckingForUpdate, 36 | ); 37 | let release = zed::latest_github_release( 38 | "phpactor/phpactor", 39 | zed::GithubReleaseOptions { 40 | require_assets: true, 41 | pre_release: false, 42 | }, 43 | )?; 44 | 45 | let asset_name = "phpactor.phar"; 46 | let asset = release 47 | .assets 48 | .iter() 49 | .find(|asset| asset.name == asset_name) 50 | .ok_or_else(|| format!("no asset found matching {:?}", asset_name))?; 51 | 52 | let version_dir = format!("phpactor-{}", release.version); 53 | fs::create_dir_all(&version_dir).map_err(|e| format!("failed to create directory: {e}"))?; 54 | 55 | let binary_path = format!("{version_dir}/phpactor.phar"); 56 | 57 | if !fs::metadata(&binary_path).is_ok_and(|stat| stat.is_file()) { 58 | zed::set_language_server_installation_status( 59 | language_server_id, 60 | &zed::LanguageServerInstallationStatus::Downloading, 61 | ); 62 | 63 | zed::download_file( 64 | &asset.download_url, 65 | &binary_path, 66 | zed::DownloadedFileType::Uncompressed, 67 | ) 68 | .map_err(|e| format!("failed to download file: {e}"))?; 69 | 70 | zed::make_file_executable(&binary_path)?; 71 | 72 | let entries = 73 | fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?; 74 | for entry in entries { 75 | let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?; 76 | if entry.file_name().to_str() != Some(&version_dir) { 77 | fs::remove_dir_all(entry.path()).ok(); 78 | } 79 | } 80 | } 81 | 82 | self.cached_binary_path = Some(binary_path.clone()); 83 | Ok(binary_path) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /languages/php/runnables.scm: -------------------------------------------------------------------------------- 1 | ; Class that follow the naming convention of PHPUnit test classes 2 | ; and that doesn't have the abstract modifier 3 | ; and have a method that follow the naming convention of PHPUnit test methods 4 | ; and the method is public 5 | ( 6 | (class_declaration 7 | modifier: (_)? @_modifier 8 | (#not-eq? @_modifier "abstract") 9 | name: (_) @_name 10 | (#match? @_name ".*Test$") 11 | body: (declaration_list 12 | (method_declaration 13 | (visibility_modifier)? @_visibility 14 | (#eq? @_visibility "public") 15 | name: (_) @run 16 | (#match? @run "^test.*") 17 | ) 18 | ) 19 | ) @_phpunit-test 20 | (#set! tag phpunit-test) 21 | ) 22 | 23 | ; Class that follow the naming convention of PHPUnit test classes 24 | ; and that doesn't have the abstract modifier 25 | ; and have a method that has the @test annotation 26 | ; and the method is public 27 | ( 28 | (class_declaration 29 | modifier: (_)? @_modifier 30 | (#not-eq? @_modifier "abstract") 31 | name: (_) @_name 32 | (#match? @_name ".*Test$") 33 | body: (declaration_list 34 | ((comment) @_comment 35 | (#match? @_comment ".*@test\\b.*") 36 | . 37 | (method_declaration 38 | (visibility_modifier)? @_visibility 39 | (#eq? @_visibility "public") 40 | name: (_) @run 41 | (#not-match? @run "^test.*") 42 | )) 43 | ) 44 | ) @_phpunit-test 45 | (#set! tag phpunit-test) 46 | ) 47 | 48 | ; Class that follow the naming convention of PHPUnit test classes 49 | ; and that doesn't have the abstract modifier 50 | ; and have a method that has the #[Test] attribute 51 | ; and the method is public 52 | ( 53 | (class_declaration 54 | modifier: (_)? @_modifier 55 | (#not-eq? @_modifier "abstract") 56 | name: (_) @_name 57 | (#match? @_name ".*Test$") 58 | body: (declaration_list 59 | (method_declaration 60 | (attribute_list 61 | (attribute_group 62 | (attribute (name) @_attribute) 63 | ) 64 | ) 65 | (#eq? @_attribute "Test") 66 | (visibility_modifier)? @_visibility 67 | (#eq? @_visibility "public") 68 | name: (_) @run 69 | (#not-match? @run "^test.*") 70 | ) 71 | ) 72 | ) @_phpunit-test 73 | (#set! tag phpunit-test) 74 | ) 75 | 76 | ; Class that follow the naming convention of PHPUnit test classes 77 | ; and that doesn't have the abstract modifier 78 | ( 79 | (class_declaration 80 | modifier: (_)? @_modifier 81 | (#not-eq? @_modifier "abstract") 82 | name: (_) @run 83 | (#match? @run ".*Test$") 84 | ) @_phpunit-test 85 | (#set! tag phpunit-test) 86 | ) 87 | 88 | ; Add support for Pest runnable 89 | ; Function expression that has `it`, `test` or `describe` as the function name 90 | ( 91 | (function_call_expression 92 | function: (_) @_name 93 | (#any-of? @_name "it" "test" "describe") 94 | arguments: (arguments 95 | . 96 | (argument 97 | [ 98 | (encapsed_string (string_value) @run) 99 | (string (string_value) @run) 100 | ] 101 | ) 102 | ) 103 | ) @_pest-test 104 | (#set! tag pest-test) 105 | ) 106 | -------------------------------------------------------------------------------- /languages/php/highlights.scm: -------------------------------------------------------------------------------- 1 | (php_tag) @tag 2 | "?>" @tag 3 | 4 | ; Types 5 | 6 | (primitive_type) @type.builtin 7 | (cast_type) @type.builtin 8 | (named_type (name) @type) @type 9 | (named_type (qualified_name) @type) @type 10 | 11 | ; Functions 12 | 13 | (array_creation_expression "array" @function.builtin) 14 | (list_literal "list" @function.builtin) 15 | 16 | (method_declaration 17 | name: (name) @function.method) 18 | 19 | (function_call_expression 20 | function: [(qualified_name (name)) (name)] @function) 21 | 22 | (scoped_call_expression 23 | name: (name) @function) 24 | 25 | (member_call_expression 26 | name: (name) @function.method) 27 | 28 | (function_definition 29 | name: (name) @function) 30 | 31 | ; Member 32 | 33 | (property_element 34 | (variable_name) @property) 35 | 36 | (member_access_expression 37 | name: (variable_name (name)) @property) 38 | (member_access_expression 39 | name: (name) @property) 40 | (nullsafe_member_access_expression 41 | name: (variable_name (name)) @property) 42 | (nullsafe_member_access_expression 43 | name: (name) @property) 44 | 45 | ; Special classes 46 | 47 | (relative_scope) @constructor 48 | 49 | ((object_creation_expression (name) @constructor) 50 | (#any-of? @constructor "self" "parent")) 51 | 52 | ((binary_expression 53 | operator: "instanceof" 54 | right: (name) @constructor) 55 | (#any-of? @constructor "self" "parent")) 56 | 57 | ; Variables 58 | 59 | ((name) @constant 60 | (#match? @constant "^_?[A-Z][A-Z\\d_]+$")) 61 | ((name) @constant.builtin 62 | (#match? @constant.builtin "^__[A-Z][A-Z\d_]+__$")) 63 | 64 | ((name) @constructor 65 | (#match? @constructor "^[A-Z]")) 66 | 67 | ((name) @variable.builtin 68 | (#eq? @variable.builtin "this")) 69 | 70 | (variable_name) @variable 71 | 72 | ; Basic tokens 73 | [ 74 | (string) 75 | (string_value) 76 | (encapsed_string) 77 | (heredoc) 78 | (heredoc_body) 79 | (nowdoc_body) 80 | ] @string 81 | (boolean) @constant.builtin 82 | (null) @constant.builtin 83 | (integer) @number 84 | (float) @number 85 | (comment) @comment 86 | 87 | ; Operators 88 | 89 | [ 90 | "=" 91 | "+=" 92 | "-=" 93 | "*=" 94 | "/=" 95 | "%=" 96 | "**=" 97 | ".=" 98 | "??=" 99 | "&=" 100 | "|=" 101 | "^=" 102 | "<<=" 103 | ">>=" 104 | 105 | "+" 106 | "-" 107 | "*" 108 | "/" 109 | "%" 110 | "**" 111 | "." 112 | 113 | "==" 114 | "!=" 115 | "===" 116 | "!==" 117 | "<" 118 | ">" 119 | "<=" 120 | ">=" 121 | "<=>" 122 | 123 | "&&" 124 | "||" 125 | "!" 126 | 127 | "??" 128 | "?" 129 | ":" 130 | 131 | "&" 132 | "|" 133 | "^" 134 | "~" 135 | "<<" 136 | ">>" 137 | 138 | "++" 139 | "--" 140 | 141 | "@" 142 | 143 | "$" 144 | ] @operator 145 | 146 | ; punctuation 147 | 148 | [ 149 | "(" 150 | ")" 151 | "[" 152 | "]" 153 | "{" 154 | "}" 155 | ] @punctuation.bracket 156 | 157 | ; "$" @punctuation.special 158 | 159 | ; Keywords 160 | 161 | "abstract" @keyword 162 | "and" @keyword 163 | "as" @keyword 164 | "break" @keyword 165 | "callable" @keyword 166 | "case" @keyword 167 | "catch" @keyword 168 | "class" @keyword 169 | "clone" @keyword 170 | "const" @keyword 171 | "continue" @keyword 172 | "declare" @keyword 173 | "default" @keyword 174 | "do" @keyword 175 | "echo" @keyword 176 | "else" @keyword 177 | "elseif" @keyword 178 | "enum" @keyword 179 | "enddeclare" @keyword 180 | "endfor" @keyword 181 | "endforeach" @keyword 182 | "endif" @keyword 183 | "endswitch" @keyword 184 | "endwhile" @keyword 185 | "extends" @keyword 186 | "final" @keyword 187 | "readonly" @keyword 188 | "finally" @keyword 189 | "for" @keyword 190 | "foreach" @keyword 191 | "fn" @keyword 192 | "from" @keyword 193 | "function" @keyword 194 | "global" @keyword 195 | "goto" @keyword 196 | "if" @keyword 197 | "implements" @keyword 198 | "include_once" @keyword 199 | "include" @keyword 200 | "instanceof" @keyword 201 | "insteadof" @keyword 202 | "interface" @keyword 203 | "match" @keyword 204 | "namespace" @keyword 205 | "new" @keyword 206 | "or" @keyword 207 | "print" @keyword 208 | "private" @keyword 209 | "protected" @keyword 210 | "public" @keyword 211 | "readonly" @keyword 212 | "require_once" @keyword 213 | "require" @keyword 214 | "return" @keyword 215 | "static" @keyword 216 | "switch" @keyword 217 | "throw" @keyword 218 | "trait" @keyword 219 | "try" @keyword 220 | "use" @keyword 221 | "while" @keyword 222 | "xor" @keyword 223 | "yield" @keyword 224 | -------------------------------------------------------------------------------- /src/language_servers/phptools.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use zed::{Architecture, Os}; 3 | use zed_extension_api::settings::LspSettings; 4 | use zed_extension_api::{self as zed, serde_json, LanguageServerId, Result}; 5 | 6 | const PACKAGE_NAME: &str = "devsense-php-ls"; 7 | 8 | pub struct PhpTools { 9 | did_find_server: bool, 10 | } 11 | 12 | impl PhpTools { 13 | pub const LANGUAGE_SERVER_ID: &'static str = "phptools"; 14 | 15 | pub fn new() -> Self { 16 | Self { 17 | did_find_server: false, 18 | } 19 | } 20 | 21 | pub fn language_server_command( 22 | &mut self, 23 | language_server_id: &LanguageServerId, 24 | worktree: &zed::Worktree, 25 | ) -> Result { 26 | if let Some(path) = worktree.which("phptools") { 27 | return Ok(zed::Command { 28 | command: path, 29 | args: vec!["--stdio".to_string()], 30 | env: Default::default(), 31 | }); 32 | } 33 | 34 | let server_path = self.server_script_path(language_server_id)?; 35 | Ok(zed::Command { 36 | command: server_path, 37 | args: vec![ 38 | "--composerNodes".into(), 39 | "false".into(), // disable /vendor/ caching 40 | ], 41 | env: Default::default(), 42 | }) 43 | } 44 | 45 | fn server_file_path(&self) -> std::string::String { 46 | let (os, arch) = zed::current_platform(); 47 | 48 | let os_str = match os { 49 | Os::Mac => "darwin", 50 | Os::Linux => "linux", 51 | Os::Windows => "win32", 52 | }; 53 | 54 | let arch_str = match arch { 55 | Architecture::Aarch64 => "arm64", 56 | Architecture::X86 | Architecture::X8664 => "x64", 57 | }; 58 | 59 | let ext_str = match os { 60 | Os::Windows => ".exe", 61 | _ => "", 62 | }; 63 | // 64 | format!( 65 | "node_modules/devsense-php-ls-{0}-{1}/dist/devsense.php.ls{2}", 66 | os_str, arch_str, ext_str 67 | ) 68 | } 69 | 70 | fn server_exists(&self) -> bool { 71 | fs::metadata(self.server_file_path()).is_ok_and(|stat| stat.is_file()) 72 | } 73 | 74 | fn server_script_path(&mut self, language_server_id: &LanguageServerId) -> Result { 75 | let server_exists = self.server_exists(); 76 | let server_path = self.server_file_path(); 77 | if self.did_find_server && server_exists { 78 | return Ok(server_path); 79 | } 80 | 81 | zed::set_language_server_installation_status( 82 | language_server_id, 83 | &zed::LanguageServerInstallationStatus::CheckingForUpdate, 84 | ); 85 | let version = zed::npm_package_latest_version(PACKAGE_NAME)?; 86 | 87 | if !server_exists 88 | || zed::npm_package_installed_version(PACKAGE_NAME)?.as_ref() != Some(&version) 89 | { 90 | zed::set_language_server_installation_status( 91 | language_server_id, 92 | &zed::LanguageServerInstallationStatus::Downloading, 93 | ); 94 | let result = zed::npm_install_package(PACKAGE_NAME, &version); 95 | match result { 96 | Ok(()) => { 97 | if !self.server_exists() { 98 | Err(format!( 99 | "installed package '{PACKAGE_NAME}' did not contain expected path '{server_path}'", 100 | ))?; 101 | } 102 | } 103 | Err(error) => { 104 | if !self.server_exists() { 105 | Err(error)?; 106 | } 107 | } 108 | } 109 | } 110 | 111 | self.did_find_server = true; 112 | Ok(server_path) 113 | } 114 | 115 | pub fn language_server_workspace_configuration( 116 | &mut self, 117 | worktree: &zed::Worktree, 118 | ) -> Result> { 119 | let settings = LspSettings::for_worktree("phptools", worktree) 120 | .ok() 121 | .and_then(|lsp_settings| lsp_settings.settings.clone()) 122 | .unwrap_or_default(); 123 | 124 | Ok(Some(serde_json::json!({ 125 | "phptools": settings 126 | }))) 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/php.rs: -------------------------------------------------------------------------------- 1 | mod language_servers; 2 | mod xdebug; 3 | 4 | use std::fs; 5 | use zed::CodeLabel; 6 | use zed_extension_api::{ 7 | self as zed, serde_json, DebugConfig, DebugScenario, LanguageServerId, Result, 8 | StartDebuggingRequestArgumentsRequest, 9 | }; 10 | 11 | use crate::{ 12 | language_servers::{Intelephense, PhpTools, Phpactor}, 13 | xdebug::XDebug, 14 | }; 15 | 16 | struct PhpExtension { 17 | phptools: Option, 18 | intelephense: Option, 19 | phpactor: Option, 20 | xdebug: XDebug, 21 | } 22 | 23 | impl zed::Extension for PhpExtension { 24 | fn new() -> Self { 25 | Self { 26 | phptools: None, 27 | intelephense: None, 28 | phpactor: None, 29 | xdebug: XDebug::new(), 30 | } 31 | } 32 | 33 | fn language_server_command( 34 | &mut self, 35 | language_server_id: &LanguageServerId, 36 | worktree: &zed::Worktree, 37 | ) -> Result { 38 | match language_server_id.as_ref() { 39 | PhpTools::LANGUAGE_SERVER_ID => { 40 | let phptools = self.phptools.get_or_insert_with(PhpTools::new); 41 | phptools.language_server_command(language_server_id, worktree) 42 | } 43 | Intelephense::LANGUAGE_SERVER_ID => { 44 | let intelephense = self.intelephense.get_or_insert_with(Intelephense::new); 45 | intelephense.language_server_command(language_server_id, worktree) 46 | } 47 | Phpactor::LANGUAGE_SERVER_ID => { 48 | let phpactor = self.phpactor.get_or_insert_with(Phpactor::new); 49 | 50 | let (platform, _) = zed::current_platform(); 51 | 52 | let phpactor_path = 53 | phpactor.language_server_binary_path(language_server_id, worktree)?; 54 | 55 | if platform == zed::Os::Windows { 56 | // fix:.phar files are not executable https://github.com/zed-extensions/php/issues/23 57 | let php_path = worktree 58 | .which("php") 59 | .ok_or("Could not find PHP in path! PHP needs to be installed for running phpactor on Windows")?; 60 | 61 | let abs_phpactor_path = std::env::current_dir() 62 | .map_err(|_| "Could not get current directory")? 63 | .join(&phpactor_path); 64 | 65 | if !fs::exists(&abs_phpactor_path).is_ok_and(|exists| exists) { 66 | return Err(format!( 67 | "Could not resolve phpactor path {:?}!", 68 | phpactor_path 69 | )); 70 | }; 71 | 72 | Ok(zed::Command { 73 | command: php_path, 74 | args: vec![ 75 | abs_phpactor_path.to_string_lossy().into(), 76 | "language-server".into(), 77 | ], 78 | env: Default::default(), 79 | }) 80 | } else { 81 | Ok(zed::Command { 82 | command: phpactor_path, 83 | args: vec!["language-server".into()], 84 | env: Default::default(), 85 | }) 86 | } 87 | } 88 | language_server_id => Err(format!("unknown language server: {language_server_id}")), 89 | } 90 | } 91 | 92 | fn language_server_workspace_configuration( 93 | &mut self, 94 | language_server_id: &LanguageServerId, 95 | worktree: &zed::Worktree, 96 | ) -> Result> { 97 | if language_server_id.as_ref() == PhpTools::LANGUAGE_SERVER_ID { 98 | if let Some(phptools) = self.phptools.as_mut() { 99 | return phptools.language_server_workspace_configuration(worktree); 100 | } 101 | } 102 | if language_server_id.as_ref() == Intelephense::LANGUAGE_SERVER_ID { 103 | if let Some(intelephense) = self.intelephense.as_mut() { 104 | return intelephense.language_server_workspace_configuration(worktree); 105 | } 106 | } 107 | 108 | Ok(None) 109 | } 110 | 111 | fn label_for_completion( 112 | &self, 113 | language_server_id: &zed::LanguageServerId, 114 | completion: zed::lsp::Completion, 115 | ) -> Option { 116 | match language_server_id.as_ref() { 117 | Intelephense::LANGUAGE_SERVER_ID => { 118 | self.intelephense.as_ref()?.label_for_completion(completion) 119 | } 120 | _ => None, 121 | } 122 | } 123 | fn dap_request_kind( 124 | &mut self, 125 | adapter_name: String, 126 | config: serde_json::Value, 127 | ) -> Result { 128 | if adapter_name != XDebug::NAME { 129 | return Err(format!( 130 | "PHP extension does not support unknown adapter in `dap_request_kind`: {adapter_name} (supported: [{}])", 131 | XDebug::NAME 132 | )); 133 | } 134 | self.xdebug.dap_request_kind(&config) 135 | } 136 | fn dap_config_to_scenario(&mut self, config: DebugConfig) -> Result { 137 | if config.adapter != XDebug::NAME { 138 | return Err(format!( 139 | "PHP extension does not support unknown adapter in `dap_config_to_scenario`: {} (supported: [{}])", 140 | config.adapter, XDebug::NAME 141 | )); 142 | } 143 | self.xdebug.dap_config_to_scenario(config) 144 | } 145 | fn get_dap_binary( 146 | &mut self, 147 | adapter_name: String, 148 | config: zed_extension_api::DebugTaskDefinition, 149 | user_provided_debug_adapter_path: Option, 150 | worktree: &zed_extension_api::Worktree, 151 | ) -> Result { 152 | if config.adapter != XDebug::NAME { 153 | return Err(format!( 154 | "PHP extension does not support unknown adapter in `get_dap_binary`: {} (supported: [{}])", 155 | adapter_name, XDebug::NAME 156 | )); 157 | } 158 | self.xdebug 159 | .get_binary(config, user_provided_debug_adapter_path, worktree) 160 | } 161 | } 162 | 163 | zed::register_extension!(PhpExtension); 164 | -------------------------------------------------------------------------------- /debug_adapter_schemas/Xdebug.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "request": { 4 | "type": "string", 5 | "enum": ["launch"], 6 | "description": "The request type for the PHP debug adapter, always \"launch\"", 7 | "default": "launch" 8 | }, 9 | "hostname": { 10 | "type": "string", 11 | "description": "The address to bind to when listening for Xdebug (default: all IPv6 connections if available, else all IPv4 connections) or Unix Domain socket (prefix with unix://) or Windows Pipe (\\\\?\\pipe\\name) - cannot be combined with port" 12 | }, 13 | "port": { 14 | "type": "integer", 15 | "description": "The port on which to listen for Xdebug (default: 9003). If port is set to 0 a random port is chosen by the system and a placeholder ${port} is replaced with the chosen port in env and runtimeArgs.", 16 | "default": 9003 17 | }, 18 | "program": { 19 | "type": "string", 20 | "description": "The PHP script to debug (typically a path to a file)", 21 | "default": "${file}" 22 | }, 23 | "cwd": { 24 | "type": "string", 25 | "description": "Working directory for the debugged program" 26 | }, 27 | "args": { 28 | "type": "array", 29 | "items": { 30 | "type": "string" 31 | }, 32 | "description": "Command line arguments to pass to the program" 33 | }, 34 | "env": { 35 | "type": "object", 36 | "description": "Environment variables to pass to the program", 37 | "additionalProperties": { 38 | "type": "string" 39 | } 40 | }, 41 | "stopOnEntry": { 42 | "type": "boolean", 43 | "description": "Whether to break at the beginning of the script", 44 | "default": false 45 | }, 46 | "pathMappings": { 47 | "type": "object", 48 | "description": "A mapping of server paths to local paths." 49 | }, 50 | "log": { 51 | "type": "boolean", 52 | "description": "Whether to log all communication between editor and the adapter to the debug console", 53 | "default": false 54 | }, 55 | "ignore": { 56 | "type": "array", 57 | "description": "An array of glob patterns that errors should be ignored from (for example **/vendor/**/*.php)", 58 | "items": { 59 | "type": "string" 60 | } 61 | }, 62 | "ignoreExceptions": { 63 | "type": "array", 64 | "description": "An array of exception class names that should be ignored (for example BaseException, \\NS1\\Exception, \\*\\Exception or \\**\\Exception*)", 65 | "items": { 66 | "type": "string" 67 | } 68 | }, 69 | "skipFiles": { 70 | "type": "array", 71 | "description": "An array of glob patterns to skip when debugging. Star patterns and negations are allowed.", 72 | "items": { 73 | "type": "string" 74 | } 75 | }, 76 | "skipEntryPaths": { 77 | "type": "array", 78 | "description": "An array of glob patterns to immediately detach from and ignore for debugging if the entry script matches", 79 | "items": { 80 | "type": "string" 81 | } 82 | }, 83 | "maxConnections": { 84 | "type": "integer", 85 | "description": "Accept only this number of parallel debugging sessions. Additional connections will be dropped.", 86 | "default": 1 87 | }, 88 | "proxy": { 89 | "type": "object", 90 | "description": "DBGp Proxy settings", 91 | "properties": { 92 | "enable": { 93 | "type": "boolean", 94 | "description": "To enable proxy registration", 95 | "default": false 96 | }, 97 | "host": { 98 | "type": "string", 99 | "description": "The address of the proxy. Supports host name, IP address, or Unix domain socket.", 100 | "default": "127.0.0.1" 101 | }, 102 | "port": { 103 | "type": "integer", 104 | "description": "The port where the adapter will register with the proxy", 105 | "default": 9001 106 | }, 107 | "key": { 108 | "type": "string", 109 | "description": "A unique key that allows the proxy to match requests to your editor", 110 | "default": "vsc" 111 | }, 112 | "timeout": { 113 | "type": "integer", 114 | "description": "The number of milliseconds to wait before giving up on the connection to proxy", 115 | "default": 3000 116 | }, 117 | "allowMultipleSessions": { 118 | "type": "boolean", 119 | "description": "If the proxy should forward multiple sessions/connections at the same time or not", 120 | "default": true 121 | } 122 | } 123 | }, 124 | "xdebugSettings": { 125 | "type": "object", 126 | "description": "Allows you to override Xdebug's remote debugging settings to fine tune Xdebug to your needs", 127 | "properties": { 128 | "max_children": { 129 | "type": "integer", 130 | "description": "Max number of array or object children to initially retrieve" 131 | }, 132 | "max_data": { 133 | "type": "integer", 134 | "description": "Max amount of variable data to initially retrieve" 135 | }, 136 | "max_depth": { 137 | "type": "integer", 138 | "description": "Maximum depth that the debugger engine may return when sending arrays, hashes or object structures to the IDE" 139 | }, 140 | "show_hidden": { 141 | "type": "integer", 142 | "description": "Whether to show detailed internal information on properties (e.g. private members of classes). Zero means hidden members are not shown.", 143 | "enum": [0, 1] 144 | }, 145 | "breakpoint_include_return_value": { 146 | "type": "boolean", 147 | "description": "Determines whether to enable an additional \"return from function\" debugging step, allowing inspection of the return value when a function call returns" 148 | } 149 | } 150 | }, 151 | "xdebugCloudToken": { 152 | "type": "string", 153 | "description": "Instead of listening locally, open a connection and register with Xdebug Cloud and accept debugging sessions on that connection" 154 | }, 155 | "stream": { 156 | "type": "object", 157 | "description": "Allows to influence DBGp streams. Xdebug only supports stdout", 158 | "properties": { 159 | "stdout": { 160 | "type": "integer", 161 | "description": "Redirect stdout stream: 0 (disable), 1 (copy), 2 (redirect)", 162 | "enum": [0, 1, 2], 163 | "default": 0 164 | } 165 | } 166 | } 167 | }, 168 | "required": ["request", "program"] 169 | } 170 | -------------------------------------------------------------------------------- /src/xdebug.rs: -------------------------------------------------------------------------------- 1 | use std::{env, path::Path, str::FromStr, sync::OnceLock}; 2 | 3 | use zed_extension_api::{ 4 | download_file, latest_github_release, node_binary_path, resolve_tcp_template, 5 | serde_json::{self, json, Value}, 6 | DebugAdapterBinary, DebugConfig, DebugRequest, DebugScenario, DownloadedFileType, 7 | GithubReleaseAsset, GithubReleaseOptions, StartDebuggingRequestArguments, 8 | StartDebuggingRequestArgumentsRequest, TcpArguments, TcpArgumentsTemplate, 9 | }; 10 | 11 | pub(super) struct XDebug { 12 | current_version: OnceLock, 13 | } 14 | 15 | impl XDebug { 16 | pub(super) const NAME: &'static str = "Xdebug"; 17 | const ADAPTER_PATH: &'static str = "extension/out/phpDebug.js"; 18 | pub(super) fn new() -> Self { 19 | Self { 20 | current_version: Default::default(), 21 | } 22 | } 23 | pub(super) fn dap_request_kind( 24 | &self, 25 | config: &serde_json::Value, 26 | ) -> Result { 27 | config 28 | .get("request") 29 | .and_then(|v| { 30 | v.as_str().and_then(|s| { 31 | s.eq("launch") 32 | .then_some(StartDebuggingRequestArgumentsRequest::Launch) 33 | }) 34 | }) 35 | .ok_or_else(|| "Invalid config".into()) 36 | } 37 | 38 | pub(crate) fn dap_config_to_scenario( 39 | &self, 40 | config: DebugConfig, 41 | ) -> Result { 42 | let obj = match &config.request { 43 | DebugRequest::Attach(_) => { 44 | return Err("Php adapter doesn't support attaching".into()); 45 | } 46 | DebugRequest::Launch(launch_config) => json!({ 47 | "program": launch_config.program, 48 | "cwd": launch_config.cwd, 49 | "args": launch_config.args, 50 | "env": serde_json::Value::Object( 51 | launch_config.envs 52 | .iter() 53 | .map(|(k, v)| (k.clone(), v.to_owned().into())) 54 | .collect::>(), 55 | ), 56 | "stopOnEntry": config.stop_on_entry.unwrap_or_default(), 57 | }), 58 | }; 59 | 60 | Ok(DebugScenario { 61 | adapter: config.adapter, 62 | label: config.label, 63 | build: None, 64 | config: obj.to_string(), 65 | tcp_connection: None, 66 | }) 67 | } 68 | fn fetch_latest_adapter_version() -> Result<(GithubReleaseAsset, String), String> { 69 | let release = latest_github_release( 70 | "xdebug/vscode-php-debug", 71 | GithubReleaseOptions { 72 | require_assets: true, 73 | pre_release: false, 74 | }, 75 | )?; 76 | 77 | let asset_name = format!("php-debug-{}.vsix", release.version.trim_start_matches("v")); 78 | 79 | let asset = release 80 | .assets 81 | .into_iter() 82 | .find(|asset| asset.name == asset_name) 83 | .ok_or_else(|| format!("no asset found matching {asset_name:?}"))?; 84 | 85 | Ok((asset, release.version)) 86 | } 87 | 88 | fn get_installed_binary( 89 | &mut self, 90 | task_definition: zed_extension_api::DebugTaskDefinition, 91 | user_provided_debug_adapter_path: Option, 92 | worktree: &zed_extension_api::Worktree, 93 | ) -> Result { 94 | let adapter_path = if let Some(user_installed_path) = user_provided_debug_adapter_path { 95 | user_installed_path 96 | } else { 97 | let version = self 98 | .current_version 99 | .get() 100 | .cloned() 101 | .ok_or_else(|| "no installed version of Xdebug found".to_string())?; 102 | env::current_dir() 103 | .unwrap() 104 | .join(Self::NAME) 105 | .join(format!("{}_{version}", Self::NAME)) 106 | .to_string_lossy() 107 | .into_owned() 108 | }; 109 | 110 | let tcp_connection = task_definition 111 | .tcp_connection 112 | .unwrap_or(TcpArgumentsTemplate { 113 | host: None, 114 | port: None, 115 | timeout: None, 116 | }); 117 | let TcpArguments { 118 | host, 119 | port, 120 | timeout, 121 | } = resolve_tcp_template(tcp_connection)?; 122 | 123 | let mut configuration = Value::from_str(&task_definition.config) 124 | .map_err(|e| format!("Invalid JSON configuration: {e}"))?; 125 | if let Some(obj) = configuration.as_object_mut() { 126 | obj.entry("cwd") 127 | .or_insert_with(|| worktree.root_path().into()); 128 | } 129 | 130 | Ok(DebugAdapterBinary { 131 | command: Some(node_binary_path()?), 132 | arguments: vec![ 133 | Path::new(&adapter_path) 134 | .join(Self::ADAPTER_PATH) 135 | .to_string_lossy() 136 | .into_owned(), 137 | format!("--server={}", port), 138 | ], 139 | connection: Some(TcpArguments { 140 | port, 141 | host, 142 | timeout, 143 | }), 144 | cwd: Some(worktree.root_path()), 145 | envs: vec![], 146 | request_args: StartDebuggingRequestArguments { 147 | request: self.dap_request_kind(&configuration)?, 148 | configuration: configuration.to_string(), 149 | }, 150 | }) 151 | } 152 | pub(crate) fn get_binary( 153 | &mut self, 154 | config: zed_extension_api::DebugTaskDefinition, 155 | user_provided_debug_adapter_path: Option, 156 | worktree: &zed_extension_api::Worktree, 157 | ) -> Result { 158 | if self.current_version.get_mut().is_none() { 159 | if let Ok((asset, version)) = Self::fetch_latest_adapter_version() { 160 | let output_path = format!("{0}/{0}_{1}", Self::NAME, version); 161 | if !Path::new(&output_path).exists() { 162 | std::fs::remove_dir_all(Self::NAME).ok(); 163 | std::fs::create_dir_all(Self::NAME) 164 | .map_err(|e| format!("Failed to create directory: {}", e))?; 165 | download_file(&asset.download_url, &output_path, DownloadedFileType::Zip)?; 166 | } 167 | self.current_version.set(version).ok(); 168 | } else { 169 | // Just find the highest version we currently have. 170 | let prefix = format!("{}_", Self::NAME); 171 | let mut version = std::fs::read_dir(Self::NAME) 172 | .ok() 173 | .into_iter() 174 | .flatten() 175 | .filter_map(|e| { 176 | e.ok().and_then(|entry| { 177 | entry 178 | .file_name() 179 | .to_string_lossy() 180 | .strip_prefix(&prefix) 181 | .map(ToOwned::to_owned) 182 | }) 183 | }) 184 | .max(); 185 | 186 | if let Some(version) = version.take() { 187 | self.current_version.set(version).ok(); 188 | } 189 | } 190 | } 191 | self.get_installed_binary(config, user_provided_debug_adapter_path, worktree) 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/language_servers/intelephense.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs}; 2 | 3 | use zed::{CodeLabel, CodeLabelSpan}; 4 | use zed_extension_api::settings::LspSettings; 5 | use zed_extension_api::{self as zed, serde_json, LanguageServerId, Result}; 6 | 7 | const SERVER_PATH: &str = "node_modules/intelephense/lib/intelephense.js"; 8 | const PACKAGE_NAME: &str = "intelephense"; 9 | 10 | pub struct Intelephense { 11 | did_find_server: bool, 12 | } 13 | 14 | impl Intelephense { 15 | pub const LANGUAGE_SERVER_ID: &'static str = "intelephense"; 16 | 17 | pub fn new() -> Self { 18 | Self { 19 | did_find_server: false, 20 | } 21 | } 22 | 23 | pub fn language_server_command( 24 | &mut self, 25 | language_server_id: &LanguageServerId, 26 | worktree: &zed::Worktree, 27 | ) -> Result { 28 | if let Some(path) = worktree.which("intelephense") { 29 | return Ok(zed::Command { 30 | command: path, 31 | args: vec!["--stdio".to_string()], 32 | env: Default::default(), 33 | }); 34 | } 35 | 36 | let server_path = self.server_script_path(language_server_id)?; 37 | Ok(zed::Command { 38 | command: zed::node_binary_path()?, 39 | args: vec![ 40 | env::current_dir() 41 | .unwrap() 42 | .join(&server_path) 43 | .to_string_lossy() 44 | .to_string(), 45 | "--stdio".to_string(), 46 | ], 47 | env: Default::default(), 48 | }) 49 | } 50 | 51 | fn server_exists(&self) -> bool { 52 | fs::metadata(SERVER_PATH).is_ok_and(|stat| stat.is_file()) 53 | } 54 | 55 | fn server_script_path(&mut self, language_server_id: &LanguageServerId) -> Result { 56 | let server_exists = self.server_exists(); 57 | if self.did_find_server && server_exists { 58 | return Ok(SERVER_PATH.to_string()); 59 | } 60 | 61 | zed::set_language_server_installation_status( 62 | language_server_id, 63 | &zed::LanguageServerInstallationStatus::CheckingForUpdate, 64 | ); 65 | let version = zed::npm_package_latest_version(PACKAGE_NAME)?; 66 | 67 | if !server_exists 68 | || zed::npm_package_installed_version(PACKAGE_NAME)?.as_ref() != Some(&version) 69 | { 70 | zed::set_language_server_installation_status( 71 | language_server_id, 72 | &zed::LanguageServerInstallationStatus::Downloading, 73 | ); 74 | let result = zed::npm_install_package(PACKAGE_NAME, &version); 75 | match result { 76 | Ok(()) => { 77 | if !self.server_exists() { 78 | Err(format!( 79 | "installed package '{PACKAGE_NAME}' did not contain expected path '{SERVER_PATH}'", 80 | ))?; 81 | } 82 | } 83 | Err(error) => { 84 | if !self.server_exists() { 85 | Err(error)?; 86 | } 87 | } 88 | } 89 | } 90 | 91 | self.did_find_server = true; 92 | Ok(SERVER_PATH.to_string()) 93 | } 94 | 95 | pub fn language_server_workspace_configuration( 96 | &mut self, 97 | worktree: &zed::Worktree, 98 | ) -> Result> { 99 | let settings = LspSettings::for_worktree("intelephense", worktree) 100 | .ok() 101 | .and_then(|lsp_settings| lsp_settings.settings.clone()) 102 | .unwrap_or_default(); 103 | 104 | Ok(Some(serde_json::json!({ 105 | "intelephense": settings 106 | }))) 107 | } 108 | 109 | pub fn label_for_completion(&self, completion: zed::lsp::Completion) -> Option { 110 | let label = &completion.label; 111 | 112 | match completion.kind? { 113 | zed::lsp::CompletionKind::Method => { 114 | // __construct method doesn't have a detail 115 | if let Some(ref detail) = completion.detail { 116 | if detail.is_empty() { 117 | return Some(CodeLabel { 118 | spans: vec![ 119 | CodeLabelSpan::literal(label, Some("function.method".to_string())), 120 | CodeLabelSpan::literal("()", None), 121 | ], 122 | filter_range: (0..label.len()).into(), 123 | code: completion.label, 124 | }); 125 | } 126 | } 127 | 128 | let mut parts = completion.detail.as_ref()?.split(":"); 129 | // E.g., `foo(string $var)` 130 | let name_and_params = parts.next()?; 131 | let return_type = parts.next()?.trim(); 132 | 133 | let (_, params) = name_and_params.split_once("(")?; 134 | let params = params.trim_end_matches(")"); 135 | 136 | Some(CodeLabel { 137 | spans: vec![ 138 | CodeLabelSpan::literal(label, Some("function.method".to_string())), 139 | CodeLabelSpan::literal("(", None), 140 | CodeLabelSpan::literal(params, Some("comment".to_string())), 141 | CodeLabelSpan::literal("): ", None), 142 | CodeLabelSpan::literal(return_type, Some("type".to_string())), 143 | ], 144 | filter_range: (0..label.len()).into(), 145 | code: completion.label, 146 | }) 147 | } 148 | zed::lsp::CompletionKind::Constant | zed::lsp::CompletionKind::EnumMember => { 149 | if let Some(ref detail) = completion.detail { 150 | if !detail.is_empty() { 151 | return Some(CodeLabel { 152 | spans: vec![ 153 | CodeLabelSpan::literal(label, Some("constant".to_string())), 154 | CodeLabelSpan::literal(" ", None), 155 | CodeLabelSpan::literal(detail, Some("comment".to_string())), 156 | ], 157 | filter_range: (0..label.len()).into(), 158 | code: completion.label, 159 | }); 160 | } 161 | } 162 | 163 | Some(CodeLabel { 164 | spans: vec![CodeLabelSpan::literal(label, Some("constant".to_string()))], 165 | filter_range: (0..label.len()).into(), 166 | code: completion.label, 167 | }) 168 | } 169 | zed::lsp::CompletionKind::Property => { 170 | let return_type = completion.detail?; 171 | Some(CodeLabel { 172 | spans: vec![ 173 | CodeLabelSpan::literal(label, Some("attribute".to_string())), 174 | CodeLabelSpan::literal(": ", None), 175 | CodeLabelSpan::literal(return_type, Some("type".to_string())), 176 | ], 177 | filter_range: (0..label.len()).into(), 178 | code: completion.label, 179 | }) 180 | } 181 | zed::lsp::CompletionKind::Variable => { 182 | // See https://www.php.net/manual/en/reserved.variables.php 183 | const SYSTEM_VAR_NAMES: &[&str] = 184 | &["argc", "argv", "php_errormsg", "http_response_header"]; 185 | 186 | let var_name = completion.label.trim_start_matches("$"); 187 | let is_uppercase = var_name 188 | .chars() 189 | .filter(|c| c.is_alphabetic()) 190 | .all(|c| c.is_uppercase()); 191 | let is_system_constant = var_name.starts_with("_"); 192 | let is_reserved = SYSTEM_VAR_NAMES.contains(&var_name); 193 | 194 | let highlight = if is_uppercase || is_system_constant || is_reserved { 195 | Some("comment".to_string()) 196 | } else { 197 | None 198 | }; 199 | 200 | Some(CodeLabel { 201 | spans: vec![CodeLabelSpan::literal(label, highlight)], 202 | filter_range: (0..label.len()).into(), 203 | code: completion.label, 204 | }) 205 | } 206 | _ => None, 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2022 - 2025 Zed Industries, Inc. 2 | 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | 18 | 19 | 20 | 21 | Apache License 22 | Version 2.0, January 2004 23 | http://www.apache.org/licenses/ 24 | 25 | 26 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 27 | 28 | 29 | 1. Definitions. 30 | 31 | 32 | "License" shall mean the terms and conditions for use, reproduction, 33 | and distribution as defined by Sections 1 through 9 of this document. 34 | 35 | 36 | "Licensor" shall mean the copyright owner or entity authorized by 37 | the copyright owner that is granting the License. 38 | 39 | 40 | "Legal Entity" shall mean the union of the acting entity and all 41 | other entities that control, are controlled by, or are under common 42 | control with that entity. For the purposes of this definition, 43 | "control" means (i) the power, direct or indirect, to cause the 44 | direction or management of such entity, whether by contract or 45 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 46 | outstanding shares, or (iii) beneficial ownership of such entity. 47 | 48 | 49 | "You" (or "Your") shall mean an individual or Legal Entity 50 | exercising permissions granted by this License. 51 | 52 | 53 | "Source" form shall mean the preferred form for making modifications, 54 | including but not limited to software source code, documentation 55 | source, and configuration files. 56 | 57 | 58 | "Object" form shall mean any form resulting from mechanical 59 | transformation or translation of a Source form, including but 60 | not limited to compiled object code, generated documentation, 61 | and conversions to other media types. 62 | 63 | 64 | "Work" shall mean the work of authorship, whether in Source or 65 | Object form, made available under the License, as indicated by a 66 | copyright notice that is included in or attached to the work 67 | (an example is provided in the Appendix below). 68 | 69 | 70 | "Derivative Works" shall mean any work, whether in Source or Object 71 | form, that is based on (or derived from) the Work and for which the 72 | editorial revisions, annotations, elaborations, or other modifications 73 | represent, as a whole, an original work of authorship. For the purposes 74 | of this License, Derivative Works shall not include works that remain 75 | separable from, or merely link (or bind by name) to the interfaces of, 76 | the Work and Derivative Works thereof. 77 | 78 | 79 | "Contribution" shall mean any work of authorship, including 80 | the original version of the Work and any modifications or additions 81 | to that Work or Derivative Works thereof, that is intentionally 82 | submitted to Licensor for inclusion in the Work by the copyright owner 83 | or by an individual or Legal Entity authorized to submit on behalf of 84 | the copyright owner. For the purposes of this definition, "submitted" 85 | means any form of electronic, verbal, or written communication sent 86 | to the Licensor or its representatives, including but not limited to 87 | communication on electronic mailing lists, source code control systems, 88 | and issue tracking systems that are managed by, or on behalf of, the 89 | Licensor for the purpose of discussing and improving the Work, but 90 | excluding communication that is conspicuously marked or otherwise 91 | designated in writing by the copyright owner as "Not a Contribution." 92 | 93 | 94 | "Contributor" shall mean Licensor and any individual or Legal Entity 95 | on behalf of whom a Contribution has been received by Licensor and 96 | subsequently incorporated within the Work. 97 | 98 | 99 | 2. Grant of Copyright License. Subject to the terms and conditions of 100 | this License, each Contributor hereby grants to You a perpetual, 101 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 102 | copyright license to reproduce, prepare Derivative Works of, 103 | publicly display, publicly perform, sublicense, and distribute the 104 | Work and such Derivative Works in Source or Object form. 105 | 106 | 107 | 3. Grant of Patent License. Subject to the terms and conditions of 108 | this License, each Contributor hereby grants to You a perpetual, 109 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 110 | (except as stated in this section) patent license to make, have made, 111 | use, offer to sell, sell, import, and otherwise transfer the Work, 112 | where such license applies only to those patent claims licensable 113 | by such Contributor that are necessarily infringed by their 114 | Contribution(s) alone or by combination of their Contribution(s) 115 | with the Work to which such Contribution(s) was submitted. If You 116 | institute patent litigation against any entity (including a 117 | cross-claim or counterclaim in a lawsuit) alleging that the Work 118 | or a Contribution incorporated within the Work constitutes direct 119 | or contributory patent infringement, then any patent licenses 120 | granted to You under this License for that Work shall terminate 121 | as of the date such litigation is filed. 122 | 123 | 124 | 4. Redistribution. You may reproduce and distribute copies of the 125 | Work or Derivative Works thereof in any medium, with or without 126 | modifications, and in Source or Object form, provided that You 127 | meet the following conditions: 128 | 129 | 130 | (a) You must give any other recipients of the Work or 131 | Derivative Works a copy of this License; and 132 | 133 | 134 | (b) You must cause any modified files to carry prominent notices 135 | stating that You changed the files; and 136 | 137 | 138 | (c) You must retain, in the Source form of any Derivative Works 139 | that You distribute, all copyright, patent, trademark, and 140 | attribution notices from the Source form of the Work, 141 | excluding those notices that do not pertain to any part of 142 | the Derivative Works; and 143 | 144 | 145 | (d) If the Work includes a "NOTICE" text file as part of its 146 | distribution, then any Derivative Works that You distribute must 147 | include a readable copy of the attribution notices contained 148 | within such NOTICE file, excluding those notices that do not 149 | pertain to any part of the Derivative Works, in at least one 150 | of the following places: within a NOTICE text file distributed 151 | as part of the Derivative Works; within the Source form or 152 | documentation, if provided along with the Derivative Works; or, 153 | within a display generated by the Derivative Works, if and 154 | wherever such third-party notices normally appear. The contents 155 | of the NOTICE file are for informational purposes only and 156 | do not modify the License. You may add Your own attribution 157 | notices within Derivative Works that You distribute, alongside 158 | or as an addendum to the NOTICE text from the Work, provided 159 | that such additional attribution notices cannot be construed 160 | as modifying the License. 161 | 162 | 163 | You may add Your own copyright statement to Your modifications and 164 | may provide additional or different license terms and conditions 165 | for use, reproduction, or distribution of Your modifications, or 166 | for any such Derivative Works as a whole, provided Your use, 167 | reproduction, and distribution of the Work otherwise complies with 168 | the conditions stated in this License. 169 | 170 | 171 | 5. Submission of Contributions. Unless You explicitly state otherwise, 172 | any Contribution intentionally submitted for inclusion in the Work 173 | by You to the Licensor shall be under the terms and conditions of 174 | this License, without any additional terms or conditions. 175 | Notwithstanding the above, nothing herein shall supersede or modify 176 | the terms of any separate license agreement you may have executed 177 | with Licensor regarding such Contributions. 178 | 179 | 180 | 6. Trademarks. This License does not grant permission to use the trade 181 | names, trademarks, service marks, or product names of the Licensor, 182 | except as required for reasonable and customary use in describing the 183 | origin of the Work and reproducing the content of the NOTICE file. 184 | 185 | 186 | 7. Disclaimer of Warranty. Unless required by applicable law or 187 | agreed to in writing, Licensor provides the Work (and each 188 | Contributor provides its Contributions) on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 190 | implied, including, without limitation, any warranties or conditions 191 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 192 | PARTICULAR PURPOSE. You are solely responsible for determining the 193 | appropriateness of using or redistributing the Work and assume any 194 | risks associated with Your exercise of permissions under this License. 195 | 196 | 197 | 8. Limitation of Liability. In no event and under no legal theory, 198 | whether in tort (including negligence), contract, or otherwise, 199 | unless required by applicable law (such as deliberate and grossly 200 | negligent acts) or agreed to in writing, shall any Contributor be 201 | liable to You for damages, including any direct, indirect, special, 202 | incidental, or consequential damages of any character arising as a 203 | result of this License or out of the use or inability to use the 204 | Work (including but not limited to damages for loss of goodwill, 205 | work stoppage, computer failure or malfunction, or any and all 206 | other commercial damages or losses), even if such Contributor 207 | has been advised of the possibility of such damages. 208 | 209 | 210 | 9. Accepting Warranty or Additional Liability. While redistributing 211 | the Work or Derivative Works thereof, You may choose to offer, 212 | and charge a fee for, acceptance of support, warranty, indemnity, 213 | or other liability obligations and/or rights consistent with this 214 | License. However, in accepting such obligations, You may act only 215 | on Your own behalf and on Your sole responsibility, not on behalf 216 | of any other Contributor, and only if You agree to indemnify, 217 | defend, and hold each Contributor harmless for any liability 218 | incurred by, or claims asserted against, such Contributor by reason 219 | of your accepting any such warranty or additional liability. 220 | 221 | 222 | END OF TERMS AND CONDITIONS 223 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "adler2" 7 | version = "2.0.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 10 | 11 | [[package]] 12 | name = "anyhow" 13 | version = "1.0.100" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" 16 | 17 | [[package]] 18 | name = "auditable-serde" 19 | version = "0.8.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "5c7bf8143dfc3c0258df908843e169b5cc5fcf76c7718bd66135ef4a9cd558c5" 22 | dependencies = [ 23 | "semver", 24 | "serde", 25 | "serde_json", 26 | "topological-sort", 27 | ] 28 | 29 | [[package]] 30 | name = "bitflags" 31 | version = "2.9.4" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" 34 | 35 | [[package]] 36 | name = "cfg-if" 37 | version = "1.0.3" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" 40 | 41 | [[package]] 42 | name = "crc32fast" 43 | version = "1.5.0" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" 46 | dependencies = [ 47 | "cfg-if", 48 | ] 49 | 50 | [[package]] 51 | name = "displaydoc" 52 | version = "0.2.5" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 55 | dependencies = [ 56 | "proc-macro2", 57 | "quote", 58 | "syn", 59 | ] 60 | 61 | [[package]] 62 | name = "equivalent" 63 | version = "1.0.2" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 66 | 67 | [[package]] 68 | name = "flate2" 69 | version = "1.1.2" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" 72 | dependencies = [ 73 | "crc32fast", 74 | "miniz_oxide", 75 | ] 76 | 77 | [[package]] 78 | name = "foldhash" 79 | version = "0.1.5" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" 82 | 83 | [[package]] 84 | name = "form_urlencoded" 85 | version = "1.2.2" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 88 | dependencies = [ 89 | "percent-encoding", 90 | ] 91 | 92 | [[package]] 93 | name = "futures" 94 | version = "0.3.31" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 97 | dependencies = [ 98 | "futures-channel", 99 | "futures-core", 100 | "futures-executor", 101 | "futures-io", 102 | "futures-sink", 103 | "futures-task", 104 | "futures-util", 105 | ] 106 | 107 | [[package]] 108 | name = "futures-channel" 109 | version = "0.3.31" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 112 | dependencies = [ 113 | "futures-core", 114 | "futures-sink", 115 | ] 116 | 117 | [[package]] 118 | name = "futures-core" 119 | version = "0.3.31" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 122 | 123 | [[package]] 124 | name = "futures-executor" 125 | version = "0.3.31" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 128 | dependencies = [ 129 | "futures-core", 130 | "futures-task", 131 | "futures-util", 132 | ] 133 | 134 | [[package]] 135 | name = "futures-io" 136 | version = "0.3.31" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 139 | 140 | [[package]] 141 | name = "futures-macro" 142 | version = "0.3.31" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 145 | dependencies = [ 146 | "proc-macro2", 147 | "quote", 148 | "syn", 149 | ] 150 | 151 | [[package]] 152 | name = "futures-sink" 153 | version = "0.3.31" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 156 | 157 | [[package]] 158 | name = "futures-task" 159 | version = "0.3.31" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 162 | 163 | [[package]] 164 | name = "futures-util" 165 | version = "0.3.31" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 168 | dependencies = [ 169 | "futures-channel", 170 | "futures-core", 171 | "futures-io", 172 | "futures-macro", 173 | "futures-sink", 174 | "futures-task", 175 | "memchr", 176 | "pin-project-lite", 177 | "pin-utils", 178 | "slab", 179 | ] 180 | 181 | [[package]] 182 | name = "hashbrown" 183 | version = "0.15.5" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 186 | dependencies = [ 187 | "foldhash", 188 | ] 189 | 190 | [[package]] 191 | name = "hashbrown" 192 | version = "0.16.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" 195 | 196 | [[package]] 197 | name = "heck" 198 | version = "0.5.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 201 | 202 | [[package]] 203 | name = "icu_collections" 204 | version = "2.0.0" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" 207 | dependencies = [ 208 | "displaydoc", 209 | "potential_utf", 210 | "yoke", 211 | "zerofrom", 212 | "zerovec", 213 | ] 214 | 215 | [[package]] 216 | name = "icu_locale_core" 217 | version = "2.0.0" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" 220 | dependencies = [ 221 | "displaydoc", 222 | "litemap", 223 | "tinystr", 224 | "writeable", 225 | "zerovec", 226 | ] 227 | 228 | [[package]] 229 | name = "icu_normalizer" 230 | version = "2.0.0" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" 233 | dependencies = [ 234 | "displaydoc", 235 | "icu_collections", 236 | "icu_normalizer_data", 237 | "icu_properties", 238 | "icu_provider", 239 | "smallvec", 240 | "zerovec", 241 | ] 242 | 243 | [[package]] 244 | name = "icu_normalizer_data" 245 | version = "2.0.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" 248 | 249 | [[package]] 250 | name = "icu_properties" 251 | version = "2.0.1" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" 254 | dependencies = [ 255 | "displaydoc", 256 | "icu_collections", 257 | "icu_locale_core", 258 | "icu_properties_data", 259 | "icu_provider", 260 | "potential_utf", 261 | "zerotrie", 262 | "zerovec", 263 | ] 264 | 265 | [[package]] 266 | name = "icu_properties_data" 267 | version = "2.0.1" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" 270 | 271 | [[package]] 272 | name = "icu_provider" 273 | version = "2.0.0" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" 276 | dependencies = [ 277 | "displaydoc", 278 | "icu_locale_core", 279 | "stable_deref_trait", 280 | "tinystr", 281 | "writeable", 282 | "yoke", 283 | "zerofrom", 284 | "zerotrie", 285 | "zerovec", 286 | ] 287 | 288 | [[package]] 289 | name = "id-arena" 290 | version = "2.2.1" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" 293 | 294 | [[package]] 295 | name = "idna" 296 | version = "1.1.0" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 299 | dependencies = [ 300 | "idna_adapter", 301 | "smallvec", 302 | "utf8_iter", 303 | ] 304 | 305 | [[package]] 306 | name = "idna_adapter" 307 | version = "1.2.1" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 310 | dependencies = [ 311 | "icu_normalizer", 312 | "icu_properties", 313 | ] 314 | 315 | [[package]] 316 | name = "indexmap" 317 | version = "2.11.4" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" 320 | dependencies = [ 321 | "equivalent", 322 | "hashbrown 0.16.0", 323 | "serde", 324 | "serde_core", 325 | ] 326 | 327 | [[package]] 328 | name = "itoa" 329 | version = "1.0.15" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 332 | 333 | [[package]] 334 | name = "leb128fmt" 335 | version = "0.1.0" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" 338 | 339 | [[package]] 340 | name = "litemap" 341 | version = "0.8.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" 344 | 345 | [[package]] 346 | name = "log" 347 | version = "0.4.28" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 350 | 351 | [[package]] 352 | name = "memchr" 353 | version = "2.7.6" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" 356 | 357 | [[package]] 358 | name = "miniz_oxide" 359 | version = "0.8.9" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 362 | dependencies = [ 363 | "adler2", 364 | ] 365 | 366 | [[package]] 367 | name = "once_cell" 368 | version = "1.21.3" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 371 | 372 | [[package]] 373 | name = "percent-encoding" 374 | version = "2.3.2" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 377 | 378 | [[package]] 379 | name = "pin-project-lite" 380 | version = "0.2.16" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 383 | 384 | [[package]] 385 | name = "pin-utils" 386 | version = "0.1.0" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 389 | 390 | [[package]] 391 | name = "potential_utf" 392 | version = "0.1.3" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" 395 | dependencies = [ 396 | "zerovec", 397 | ] 398 | 399 | [[package]] 400 | name = "prettyplease" 401 | version = "0.2.37" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" 404 | dependencies = [ 405 | "proc-macro2", 406 | "syn", 407 | ] 408 | 409 | [[package]] 410 | name = "proc-macro2" 411 | version = "1.0.101" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" 414 | dependencies = [ 415 | "unicode-ident", 416 | ] 417 | 418 | [[package]] 419 | name = "quote" 420 | version = "1.0.41" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" 423 | dependencies = [ 424 | "proc-macro2", 425 | ] 426 | 427 | [[package]] 428 | name = "ryu" 429 | version = "1.0.20" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 432 | 433 | [[package]] 434 | name = "semver" 435 | version = "1.0.27" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" 438 | dependencies = [ 439 | "serde", 440 | "serde_core", 441 | ] 442 | 443 | [[package]] 444 | name = "serde" 445 | version = "1.0.228" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 448 | dependencies = [ 449 | "serde_core", 450 | "serde_derive", 451 | ] 452 | 453 | [[package]] 454 | name = "serde_core" 455 | version = "1.0.228" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 458 | dependencies = [ 459 | "serde_derive", 460 | ] 461 | 462 | [[package]] 463 | name = "serde_derive" 464 | version = "1.0.228" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 467 | dependencies = [ 468 | "proc-macro2", 469 | "quote", 470 | "syn", 471 | ] 472 | 473 | [[package]] 474 | name = "serde_json" 475 | version = "1.0.145" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" 478 | dependencies = [ 479 | "itoa", 480 | "memchr", 481 | "ryu", 482 | "serde", 483 | "serde_core", 484 | ] 485 | 486 | [[package]] 487 | name = "slab" 488 | version = "0.4.11" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 491 | 492 | [[package]] 493 | name = "smallvec" 494 | version = "1.15.1" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 497 | 498 | [[package]] 499 | name = "spdx" 500 | version = "0.10.9" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "c3e17e880bafaeb362a7b751ec46bdc5b61445a188f80e0606e68167cd540fa3" 503 | dependencies = [ 504 | "smallvec", 505 | ] 506 | 507 | [[package]] 508 | name = "stable_deref_trait" 509 | version = "1.2.0" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 512 | 513 | [[package]] 514 | name = "syn" 515 | version = "2.0.106" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" 518 | dependencies = [ 519 | "proc-macro2", 520 | "quote", 521 | "unicode-ident", 522 | ] 523 | 524 | [[package]] 525 | name = "synstructure" 526 | version = "0.13.2" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 529 | dependencies = [ 530 | "proc-macro2", 531 | "quote", 532 | "syn", 533 | ] 534 | 535 | [[package]] 536 | name = "tinystr" 537 | version = "0.8.1" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" 540 | dependencies = [ 541 | "displaydoc", 542 | "zerovec", 543 | ] 544 | 545 | [[package]] 546 | name = "topological-sort" 547 | version = "0.2.2" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" 550 | 551 | [[package]] 552 | name = "unicode-ident" 553 | version = "1.0.19" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" 556 | 557 | [[package]] 558 | name = "unicode-xid" 559 | version = "0.2.6" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 562 | 563 | [[package]] 564 | name = "url" 565 | version = "2.5.7" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" 568 | dependencies = [ 569 | "form_urlencoded", 570 | "idna", 571 | "percent-encoding", 572 | "serde", 573 | ] 574 | 575 | [[package]] 576 | name = "utf8_iter" 577 | version = "1.0.4" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 580 | 581 | [[package]] 582 | name = "wasm-encoder" 583 | version = "0.227.1" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "80bb72f02e7fbf07183443b27b0f3d4144abf8c114189f2e088ed95b696a7822" 586 | dependencies = [ 587 | "leb128fmt", 588 | "wasmparser", 589 | ] 590 | 591 | [[package]] 592 | name = "wasm-metadata" 593 | version = "0.227.1" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "ce1ef0faabbbba6674e97a56bee857ccddf942785a336c8b47b42373c922a91d" 596 | dependencies = [ 597 | "anyhow", 598 | "auditable-serde", 599 | "flate2", 600 | "indexmap", 601 | "serde", 602 | "serde_derive", 603 | "serde_json", 604 | "spdx", 605 | "url", 606 | "wasm-encoder", 607 | "wasmparser", 608 | ] 609 | 610 | [[package]] 611 | name = "wasmparser" 612 | version = "0.227.1" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "0f51cad774fb3c9461ab9bccc9c62dfb7388397b5deda31bf40e8108ccd678b2" 615 | dependencies = [ 616 | "bitflags", 617 | "hashbrown 0.15.5", 618 | "indexmap", 619 | "semver", 620 | ] 621 | 622 | [[package]] 623 | name = "wit-bindgen" 624 | version = "0.41.0" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "10fb6648689b3929d56bbc7eb1acf70c9a42a29eb5358c67c10f54dbd5d695de" 627 | dependencies = [ 628 | "wit-bindgen-rt", 629 | "wit-bindgen-rust-macro", 630 | ] 631 | 632 | [[package]] 633 | name = "wit-bindgen-core" 634 | version = "0.41.0" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "92fa781d4f2ff6d3f27f3cc9b74a73327b31ca0dc4a3ef25a0ce2983e0e5af9b" 637 | dependencies = [ 638 | "anyhow", 639 | "heck", 640 | "wit-parser", 641 | ] 642 | 643 | [[package]] 644 | name = "wit-bindgen-rt" 645 | version = "0.41.0" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "c4db52a11d4dfb0a59f194c064055794ee6564eb1ced88c25da2cf76e50c5621" 648 | dependencies = [ 649 | "bitflags", 650 | "futures", 651 | "once_cell", 652 | ] 653 | 654 | [[package]] 655 | name = "wit-bindgen-rust" 656 | version = "0.41.0" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "9d0809dc5ba19e2e98661bf32fc0addc5a3ca5bf3a6a7083aa6ba484085ff3ce" 659 | dependencies = [ 660 | "anyhow", 661 | "heck", 662 | "indexmap", 663 | "prettyplease", 664 | "syn", 665 | "wasm-metadata", 666 | "wit-bindgen-core", 667 | "wit-component", 668 | ] 669 | 670 | [[package]] 671 | name = "wit-bindgen-rust-macro" 672 | version = "0.41.0" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "ad19eec017904e04c60719592a803ee5da76cb51c81e3f6fbf9457f59db49799" 675 | dependencies = [ 676 | "anyhow", 677 | "prettyplease", 678 | "proc-macro2", 679 | "quote", 680 | "syn", 681 | "wit-bindgen-core", 682 | "wit-bindgen-rust", 683 | ] 684 | 685 | [[package]] 686 | name = "wit-component" 687 | version = "0.227.1" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "635c3adc595422cbf2341a17fb73a319669cc8d33deed3a48368a841df86b676" 690 | dependencies = [ 691 | "anyhow", 692 | "bitflags", 693 | "indexmap", 694 | "log", 695 | "serde", 696 | "serde_derive", 697 | "serde_json", 698 | "wasm-encoder", 699 | "wasm-metadata", 700 | "wasmparser", 701 | "wit-parser", 702 | ] 703 | 704 | [[package]] 705 | name = "wit-parser" 706 | version = "0.227.1" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "ddf445ed5157046e4baf56f9138c124a0824d4d1657e7204d71886ad8ce2fc11" 709 | dependencies = [ 710 | "anyhow", 711 | "id-arena", 712 | "indexmap", 713 | "log", 714 | "semver", 715 | "serde", 716 | "serde_derive", 717 | "serde_json", 718 | "unicode-xid", 719 | "wasmparser", 720 | ] 721 | 722 | [[package]] 723 | name = "writeable" 724 | version = "0.6.1" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" 727 | 728 | [[package]] 729 | name = "yoke" 730 | version = "0.8.0" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" 733 | dependencies = [ 734 | "serde", 735 | "stable_deref_trait", 736 | "yoke-derive", 737 | "zerofrom", 738 | ] 739 | 740 | [[package]] 741 | name = "yoke-derive" 742 | version = "0.8.0" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" 745 | dependencies = [ 746 | "proc-macro2", 747 | "quote", 748 | "syn", 749 | "synstructure", 750 | ] 751 | 752 | [[package]] 753 | name = "zed_extension_api" 754 | version = "0.7.0" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "0729d50b4ca0a7e28e590bbe32e3ca0194d97ef654961451a424c661a366fca0" 757 | dependencies = [ 758 | "serde", 759 | "serde_json", 760 | "wit-bindgen", 761 | ] 762 | 763 | [[package]] 764 | name = "zed_php" 765 | version = "0.4.5" 766 | dependencies = [ 767 | "zed_extension_api", 768 | ] 769 | 770 | [[package]] 771 | name = "zerofrom" 772 | version = "0.1.6" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 775 | dependencies = [ 776 | "zerofrom-derive", 777 | ] 778 | 779 | [[package]] 780 | name = "zerofrom-derive" 781 | version = "0.1.6" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 784 | dependencies = [ 785 | "proc-macro2", 786 | "quote", 787 | "syn", 788 | "synstructure", 789 | ] 790 | 791 | [[package]] 792 | name = "zerotrie" 793 | version = "0.2.2" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" 796 | dependencies = [ 797 | "displaydoc", 798 | "yoke", 799 | "zerofrom", 800 | ] 801 | 802 | [[package]] 803 | name = "zerovec" 804 | version = "0.11.4" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" 807 | dependencies = [ 808 | "yoke", 809 | "zerofrom", 810 | "zerovec-derive", 811 | ] 812 | 813 | [[package]] 814 | name = "zerovec-derive" 815 | version = "0.11.1" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" 818 | dependencies = [ 819 | "proc-macro2", 820 | "quote", 821 | "syn", 822 | ] 823 | --------------------------------------------------------------------------------