├── .github └── FUNDING.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── code ├── example.sol └── test.sol ├── extension.toml ├── languages └── solidity │ ├── brackets.scm │ ├── config.toml │ ├── highlights.scm │ ├── indents.scm │ ├── locals.scm │ └── outline.scm ├── public └── screenshot.png └── src └── solidity.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: zarifpour 4 | buy_me_a_coffee: zarifpour 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.wasm 3 | tree-sitter-* 4 | target/ 5 | grammars/ 6 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.86" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" 10 | 11 | [[package]] 12 | name = "bitflags" 13 | version = "2.6.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 16 | 17 | [[package]] 18 | name = "equivalent" 19 | version = "1.0.1" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 22 | 23 | [[package]] 24 | name = "hashbrown" 25 | version = "0.14.5" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 28 | 29 | [[package]] 30 | name = "heck" 31 | version = "0.4.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 34 | dependencies = [ 35 | "unicode-segmentation", 36 | ] 37 | 38 | [[package]] 39 | name = "id-arena" 40 | version = "2.2.1" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" 43 | 44 | [[package]] 45 | name = "indexmap" 46 | version = "2.2.6" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 49 | dependencies = [ 50 | "equivalent", 51 | "hashbrown", 52 | "serde", 53 | ] 54 | 55 | [[package]] 56 | name = "itoa" 57 | version = "1.0.11" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 60 | 61 | [[package]] 62 | name = "leb128" 63 | version = "0.2.5" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" 66 | 67 | [[package]] 68 | name = "log" 69 | version = "0.4.22" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 72 | 73 | [[package]] 74 | name = "proc-macro2" 75 | version = "1.0.86" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 78 | dependencies = [ 79 | "unicode-ident", 80 | ] 81 | 82 | [[package]] 83 | name = "quote" 84 | version = "1.0.36" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 87 | dependencies = [ 88 | "proc-macro2", 89 | ] 90 | 91 | [[package]] 92 | name = "ryu" 93 | version = "1.0.18" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 96 | 97 | [[package]] 98 | name = "semver" 99 | version = "1.0.23" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 102 | 103 | [[package]] 104 | name = "serde" 105 | version = "1.0.203" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" 108 | dependencies = [ 109 | "serde_derive", 110 | ] 111 | 112 | [[package]] 113 | name = "serde_derive" 114 | version = "1.0.203" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" 117 | dependencies = [ 118 | "proc-macro2", 119 | "quote", 120 | "syn", 121 | ] 122 | 123 | [[package]] 124 | name = "serde_json" 125 | version = "1.0.120" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" 128 | dependencies = [ 129 | "itoa", 130 | "ryu", 131 | "serde", 132 | ] 133 | 134 | [[package]] 135 | name = "smallvec" 136 | version = "1.13.2" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 139 | 140 | [[package]] 141 | name = "spdx" 142 | version = "0.10.6" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" 145 | dependencies = [ 146 | "smallvec", 147 | ] 148 | 149 | [[package]] 150 | name = "syn" 151 | version = "2.0.68" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" 154 | dependencies = [ 155 | "proc-macro2", 156 | "quote", 157 | "unicode-ident", 158 | ] 159 | 160 | [[package]] 161 | name = "unicode-ident" 162 | version = "1.0.12" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 165 | 166 | [[package]] 167 | name = "unicode-segmentation" 168 | version = "1.11.0" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" 171 | 172 | [[package]] 173 | name = "unicode-xid" 174 | version = "0.2.4" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" 177 | 178 | [[package]] 179 | name = "wasm-encoder" 180 | version = "0.201.0" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a" 183 | dependencies = [ 184 | "leb128", 185 | ] 186 | 187 | [[package]] 188 | name = "wasm-metadata" 189 | version = "0.201.0" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "0fd83062c17b9f4985d438603cde0a5e8c5c8198201a6937f778b607924c7da2" 192 | dependencies = [ 193 | "anyhow", 194 | "indexmap", 195 | "serde", 196 | "serde_derive", 197 | "serde_json", 198 | "spdx", 199 | "wasm-encoder", 200 | "wasmparser", 201 | ] 202 | 203 | [[package]] 204 | name = "wasmparser" 205 | version = "0.201.0" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708" 208 | dependencies = [ 209 | "bitflags", 210 | "indexmap", 211 | "semver", 212 | ] 213 | 214 | [[package]] 215 | name = "wit-bindgen" 216 | version = "0.22.0" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "288f992ea30e6b5c531b52cdd5f3be81c148554b09ea416f058d16556ba92c27" 219 | dependencies = [ 220 | "bitflags", 221 | "wit-bindgen-rt", 222 | "wit-bindgen-rust-macro", 223 | ] 224 | 225 | [[package]] 226 | name = "wit-bindgen-core" 227 | version = "0.22.0" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "e85e72719ffbccf279359ad071497e47eb0675fe22106dea4ed2d8a7fcb60ba4" 230 | dependencies = [ 231 | "anyhow", 232 | "wit-parser", 233 | ] 234 | 235 | [[package]] 236 | name = "wit-bindgen-rt" 237 | version = "0.22.0" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "fcb8738270f32a2d6739973cbbb7c1b6dd8959ce515578a6e19165853272ee64" 240 | 241 | [[package]] 242 | name = "wit-bindgen-rust" 243 | version = "0.22.0" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "d8a39a15d1ae2077688213611209849cad40e9e5cccf6e61951a425850677ff3" 246 | dependencies = [ 247 | "anyhow", 248 | "heck", 249 | "indexmap", 250 | "wasm-metadata", 251 | "wit-bindgen-core", 252 | "wit-component", 253 | ] 254 | 255 | [[package]] 256 | name = "wit-bindgen-rust-macro" 257 | version = "0.22.0" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "d376d3ae5850526dfd00d937faea0d81a06fa18f7ac1e26f386d760f241a8f4b" 260 | dependencies = [ 261 | "anyhow", 262 | "proc-macro2", 263 | "quote", 264 | "syn", 265 | "wit-bindgen-core", 266 | "wit-bindgen-rust", 267 | ] 268 | 269 | [[package]] 270 | name = "wit-component" 271 | version = "0.201.0" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825" 274 | dependencies = [ 275 | "anyhow", 276 | "bitflags", 277 | "indexmap", 278 | "log", 279 | "serde", 280 | "serde_derive", 281 | "serde_json", 282 | "wasm-encoder", 283 | "wasm-metadata", 284 | "wasmparser", 285 | "wit-parser", 286 | ] 287 | 288 | [[package]] 289 | name = "wit-parser" 290 | version = "0.201.0" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "196d3ecfc4b759a8573bf86a9b3f8996b304b3732e4c7de81655f875f6efdca6" 293 | dependencies = [ 294 | "anyhow", 295 | "id-arena", 296 | "indexmap", 297 | "log", 298 | "semver", 299 | "serde", 300 | "serde_derive", 301 | "serde_json", 302 | "unicode-xid", 303 | "wasmparser", 304 | ] 305 | 306 | [[package]] 307 | name = "zed_extension_api" 308 | version = "0.0.4" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "d5c51cad4152bb5eb35b20dccdcbfb36f48d8952a2ed2d3e25b70361007d953b" 311 | dependencies = [ 312 | "wit-bindgen", 313 | ] 314 | 315 | [[package]] 316 | name = "zed_solidity" 317 | version = "0.1.3" 318 | dependencies = [ 319 | "zed_extension_api", 320 | ] 321 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zed_solidity" 3 | version = "0.1.3" 4 | edition = "2021" 5 | publish = false 6 | license = "MIT" 7 | 8 | [lib] 9 | path = "src/solidity.rs" 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | zed_extension_api = "0.0.4" 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2024 Daniel Zarifpour 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 💠 Solidity Language Support for Zed 2 | 3 | Enhance Zed with Solidity language support, including syntax highlighting and language server features such as diagnostics and more! 4 | 5 | - Tree Sitter: [tree-sitter-solidity](https://github.com/JoranHonig/tree-sitter-solidity) 6 | - Language Server: [@nomicfoundation/solidity-language-server](https://github.com/NomicFoundation/hardhat-vscode/tree/main/server) 7 | 8 | > [!Tip] 9 | > For the best experience, it is highly recommended to use [XY-Zed](https://github.com/zarifpour/xy-zed). This extension has been built on top of the XY-Zed theme, ensuring that all colors are thoughtfully chosen to provide intelligent syntax highlighting. 10 | 11 | --- 12 | 13 | ![CleanShot 2024-02-28 at 02 40 51 on Zed — example sol — zed-solidity@2x](public/screenshot.png) 14 | 15 | --- 16 | 17 | ## 🛠️ Development Setup 18 | 19 | ### 1. Clone the repository 20 | 21 | ```shell 22 | git clone https://github.com/zarifpour/zed-solidity 23 | ``` 24 | 25 | ### 2. Uninstall the existing extension 26 | 27 | If you have the existing extension installed, you need to uninstall it before installing the development version. 28 | 29 | ### 3. Load the extension 30 | 31 | - Open `zed: extensions`. 32 | - Click `Install Dev Extension`. 33 | - Select the `zed-solidity` directory. 34 | 35 | ### 4. Rebuild the extension as needed 36 | 37 | As you make changes to the extension, you may need to rebuild it. To do so: 38 | 39 | - Open `zed: extensions`. 40 | - Click the `Rebuild` button next to the extension. 41 | 42 | ## 🎸 Contributing 43 | 44 | Contributions are welcome! 45 | 46 | To contribute: 47 | 48 | 1. Fork the repo and create a new branch. 49 | 2. Make changes and test them. 50 | 3. Submit a pull request with a clear description. 51 | 52 | Check open issues for areas needing improvement. Thanks for helping improve Solidity support in Zed! 53 | 54 | 55 | contrib.rocks 56 | 57 | 58 | ## 🏆 Acknowledgments 59 | 60 | - [@JoranHonig](https://github.com/JoranHonig) for providing the [tree-sitter-solidity](https://github.com/JoranHonig/tree-sitter-solidity) repository. 61 | - [@meetmangukiya](https://github.com/meetmangukiya) and [@tomholford](https://github.com/tomholford) for inspiration with their PRs to the main Zed repo. 62 | 63 | --- 64 | 65 |
66 | 67 | Made with 🩵 by Daniel Zarifpour 68 | 69 | 70 | 71 |
72 | -------------------------------------------------------------------------------- /code/example.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract SimpleStorage { 5 | // Declare a state variable to store an integer 6 | uint256 private storedData; 7 | 8 | // Event to log the storage of a new value 9 | event DataStored(uint256 newValue); 10 | 11 | // Custom error for invalid values 12 | error InvalidValue(uint256 value); 13 | 14 | // Modifier to check a condition before executing a function 15 | modifier validateValue(uint256 x) { 16 | if (x == 0) { 17 | revert InvalidValue(x); 18 | } 19 | _; 20 | } 21 | 22 | // Function to store a new value 23 | function set(uint256 x) private validateValue(x) { 24 | // Use inline assembly to store the new value 25 | assembly { 26 | sstore(storedData.slot, x) 27 | } 28 | emit DataStored(x); 29 | } 30 | 31 | // Function to retrieve the stored value 32 | function get() public view returns (uint256) { 33 | return storedData; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.22 <0.8.0 || ^0.8.0-; // Using pragma with version comparison operators 3 | 4 | // Import statements 5 | import "./AnotherContract.sol"; 6 | import "./AnotherLibrary.sol" as Lib; 7 | import "./SomeInterface.sol"; 8 | import { Example } from "./Example.sol"; 9 | 10 | 11 | contract IdentifierExamples { 12 | // State variables 13 | string public stringLiteral = "Hello, world!"; // (identifier) @variable 14 | bytes public hexStringLiteral = hex"48656c6c6f2c20776f726c6421"; // (identifier) @variable 15 | string private unicodeStringLiteral = unicode"Hello, 🌍!"; // (identifier) @variable 16 | uint public numberLiteral = 12345; // (identifier) @variable 17 | 18 | // Struct definition 19 | struct MyStruct { 20 | uint id; // (identifier) @variable 21 | string data; // (identifier) @variable 22 | } 23 | 24 | // Enum definition 25 | enum MyEnum { 26 | Option1, // (identifier) @variable 27 | Option2, // (identifier) @variable 28 | Option3 // (identifier) @variable 29 | } 30 | 31 | // State variables for struct and enum 32 | MyStruct public myStruct; // (identifier) @variable 33 | MyEnum public myEnum; // (identifier) @variable 34 | 35 | // Constructor 36 | constructor() { 37 | myStruct = MyStruct({id: 1, data: "Struct data"}); // (identifier) @variable 38 | myEnum = MyEnum.Option1; // (identifier) @variable 39 | } 40 | 41 | // Function with local variables 42 | function exampleFunction(uint _value) public returns (uint) { // (identifier) @variable 43 | uint localValue = _value * 2; // (identifier) @variable 44 | return localValue; // (identifier) @variable 45 | } 46 | 47 | // Yul block with Yul identifiers 48 | function yulExample(uint _a, uint _b) public pure returns (uint) { // (identifier) @variable 49 | assembly { 50 | let a := _a // (yul_identifier) @variable 51 | let b := _b // (yul_identifier) @variable 52 | let result := add(a, b) // (yul_identifier) @variable 53 | mstore(0x40, result) // (yul_identifier) @variable 54 | return(0x40, 0x20) // (yul_identifier) @variable 55 | } 56 | } 57 | 58 | // Function with loop and nested function call 59 | function loopExample(uint[] memory data) public pure returns (uint) { // (identifier) @variable 60 | uint sum = 0; // (identifier) @variable 61 | for (uint i = 0; i < data.length; i++) { // (identifier) @variable 62 | sum += data[i]; // (identifier) @variable 63 | } 64 | return sum; // (identifier) @variable 65 | } 66 | 67 | // Using enum 68 | function setEnumOption(uint _option) public { // (identifier) @variable 69 | require(_option <= uint(MyEnum.Option3), "Invalid option"); // (identifier) @variable 70 | myEnum = MyEnum(_option); // (identifier) @variable 71 | } 72 | 73 | // Using struct 74 | function setStruct(uint _id, string memory _data) public { // (identifier) @variable 75 | myStruct = MyStruct({id: _id, data: _data}); // (identifier) @variable 76 | } 77 | } 78 | 79 | contract LiteralExamples { 80 | // String Literals 81 | string public stringLiteral = "Hello, world!"; 82 | 83 | // Yul String Literal 84 | function yulStringLiteral() private pure returns (string memory) { 85 | assembly { 86 | let str := "Yul string literal" 87 | mstore(0x40, str) 88 | return(0x40, 0x20) 89 | } 90 | } 91 | 92 | // Hex String Literal 93 | bytes public hexStringLiteral = hex"48656c6c6f2c20776f726c6421"; 94 | 95 | // Unicode String Literal 96 | string public unicodeStringLiteral = unicode"Hello, 🌍!"; 97 | 98 | // Number Literals 99 | uint public numberLiteral = 12345; 100 | 101 | // Yul Decimal Number 102 | function yulDecimalNumber() public pure returns (uint) { 103 | assembly { 104 | let num := 12345 105 | mstore(0x40, num) 106 | return(0x40, 0x20) 107 | } 108 | } 109 | 110 | // Yul Hex Number 111 | function yulHexNumber() public pure returns (uint) { 112 | assembly { 113 | let num := 0x3039 // 12345 in hexadecimal 114 | mstore(0x40, num) 115 | return(0x40, 0x20) 116 | } 117 | } 118 | 119 | // Yul Boolean 120 | function yulBoolean() public pure returns (bool) { 121 | assembly { 122 | let boolVal := true 123 | mstore(0x40, boolVal) 124 | return(0x40, 0x20) 125 | } 126 | } 127 | } 128 | 129 | // Library definition 130 | library MathLib { 131 | function max(uint a, uint b) internal pure returns (uint) { 132 | return a >= b ? a : b; 133 | } 134 | } 135 | 136 | // Interface definition 137 | interface IExample { 138 | function exampleFunction(uint a) external returns (uint); 139 | } 140 | 141 | // Abstract contract 142 | abstract contract AbstractContract { 143 | function abstractFunction() public view virtual returns (string memory); 144 | } 145 | 146 | // Contract inheritance 147 | contract BaseContract { 148 | uint public baseValue; 149 | 150 | function setBaseValue(uint _value) public { 151 | baseValue = _value; 152 | } 153 | } 154 | 155 | // Multi-level inheritance 156 | contract IntermediateContract is BaseContract { 157 | function intermediateFunction() public pure returns (string memory) { 158 | return "Intermediate function"; 159 | } 160 | } 161 | 162 | // Main contract 163 | contract MainContract is AbstractContract, IntermediateContract { 164 | // State variables 165 | uint public value; 166 | string private name; 167 | address immutable owner; 168 | uint256[] public numbers; 169 | mapping(address => uint256) public balances; 170 | bool private active; 171 | bytes32 constant MY_CONSTANT = "MY_CONSTANT_VALUE"; 172 | mapping(address => mapping(uint => bool)) nestedMapping; 173 | 174 | // Events 175 | event ValueChanged(uint indexed oldValue, uint indexed newValue); 176 | event Received(address, uint); 177 | event NestedMappingUpdated(address indexed account, uint indexed key, bool value); 178 | 179 | // Struct definition 180 | struct MyStruct { 181 | uint id; 182 | string data; 183 | } 184 | 185 | // Enum definition 186 | enum MyEnum { 187 | Option1, 188 | Option2, 189 | Option3 190 | } 191 | 192 | // Modifier 193 | modifier onlyOwner() { 194 | require(msg.sender == owner, "Not the contract owner"); 195 | _; 196 | } 197 | 198 | // Constructor 199 | constructor(string memory _name) { 200 | owner = msg.sender; 201 | name = _name; 202 | } 203 | 204 | // Fallback and receive functions 205 | fallback() external payable { 206 | emit Received(msg.sender, msg.value); 207 | } 208 | 209 | receive() external payable { 210 | emit Received(msg.sender, msg.value); 211 | require(msg.value); 212 | } 213 | 214 | // Public function 215 | function setValue(uint _value) public onlyOwner { 216 | emit ValueChanged(value, _value); 217 | value = _value; 218 | } 219 | 220 | // External function 221 | function externalFunction() external view returns (string memory) { 222 | return name; 223 | } 224 | 225 | // Internal function 226 | function internalFunction(uint a, uint b) internal pure returns (uint) { 227 | return MathLib.max(a, b); 228 | } 229 | 230 | // Private function 231 | function privateFunction() private view returns (address) { 232 | return owner; 233 | } 234 | 235 | // Pure function 236 | function pureFunction(uint a, uint b) public pure returns (uint) { 237 | return a + b; 238 | } 239 | 240 | // View function 241 | function viewFunction() public view returns (uint) { 242 | return value; 243 | } 244 | 245 | // Using a library for a struct 246 | using MathLib for uint; 247 | 248 | // Using assembly 249 | function assemblyFunction(uint x, uint y) public pure returns (uint result) { 250 | assembly { 251 | result := add(x, y) 252 | } 253 | } 254 | 255 | // Override function from abstract contract 256 | function abstractFunction() public view override returns (string memory) { 257 | return "Abstract function implemented"; 258 | } 259 | 260 | // Using enum 261 | MyEnum public myEnum; 262 | 263 | function setEnumOption(uint _option) public { 264 | require(_option <= uint(MyEnum.Option3), "Invalid option"); 265 | myEnum = MyEnum(_option); 266 | } 267 | 268 | // Using struct 269 | MyStruct public myStruct; 270 | 271 | function setStruct(uint _id, string memory _data) public { 272 | myStruct = MyStruct({id: _id, data: _data}); 273 | } 274 | 275 | // Using array 276 | function addNumber(uint _number) public { 277 | numbers.push(_number); 278 | } 279 | 280 | // Using mapping 281 | function updateBalance(address _address, uint256 _amount) public { 282 | balances[_address] = _amount; 283 | } 284 | 285 | // Nested mapping 286 | function updateNestedMapping(address _account, uint _key, bool _value) public { 287 | nestedMapping[_account][_key] = _value; 288 | emit NestedMappingUpdated(_account, _key, _value); 289 | } 290 | 291 | // Function with try/catch 292 | function tryCatchExample(IExample example, uint _a) public returns (uint) { 293 | try example.exampleFunction(_a) returns (uint result) { 294 | return result; 295 | } catch { 296 | return 0; 297 | } 298 | } 299 | 300 | // Custom errors 301 | error Unauthorized(address caller); 302 | error InvalidInput(string reason); 303 | 304 | function checkAuthorization() public view { 305 | if (msg.sender != owner) { 306 | revert Unauthorized(msg.sender); 307 | } 308 | } 309 | 310 | function validateInput(uint _value) public pure { 311 | if (_value == 0) { 312 | revert InvalidInput("Value cannot be zero"); 313 | } 314 | } 315 | 316 | // Function overloading 317 | function overloadedFunction(uint _value) public pure returns (uint) { 318 | return _value * 2; 319 | } 320 | 321 | function overloadedFunction(uint _value, uint _multiplier) public pure returns (uint) { 322 | return _value * _multiplier; 323 | } 324 | 325 | // Payable function 326 | function deposit() public payable { 327 | balances[msg.sender] += msg.value; 328 | } 329 | 330 | // Error handling with assert 331 | function assertExample(uint _value) public pure returns (uint) { 332 | assert(_value > 0); 333 | return _value; 334 | } 335 | 336 | // Error handling with require 337 | function requireExample(uint _value) public pure returns (uint) { 338 | require(_value > 0, InvalidInput("because")); 339 | return _value; 340 | } 341 | 342 | // Error handling with revert 343 | function revertExample(uint _value) public pure { 344 | if (_value == 0) { 345 | revert("Value cannot be zero"); 346 | } 347 | } 348 | 349 | // Using immutable 350 | function getOwner() public view returns (address) { 351 | return owner; 352 | } 353 | 354 | // Using constants 355 | function getConstant() public pure returns (bytes32) { 356 | return MY_CONSTANT; 357 | } 358 | 359 | // Constructor overloading 360 | constructor(string memory _name, uint _initialValue) { 361 | owner = msg.sender; 362 | name = _name; 363 | value = _initialValue; 364 | } 365 | 366 | // Assembly to perform bitwise operations 367 | function bitwiseAnd(uint a, uint b) public pure returns (uint) { 368 | uint result; 369 | assembly { 370 | result := and(a, b) 371 | } 372 | return result; 373 | } 374 | 375 | function bitwiseOr(uint a, uint b) public pure returns (uint) { 376 | uint result; 377 | assembly { 378 | result := or(a, b) 379 | } 380 | return result; 381 | } 382 | 383 | function bitwiseXor(uint a, uint b) public pure returns (uint) { 384 | uint result; 385 | assembly { 386 | result := xor(a, b) 387 | } 388 | return result; 389 | } 390 | 391 | function bitwiseNot(uint a) public pure returns (uint) { 392 | uint result; 393 | assembly { 394 | result := not(a) 395 | } 396 | return result; 397 | } 398 | 399 | // Use of delegatecall 400 | function delegateCallExample(address callee, bytes memory data) public returns (bytes memory) { 401 | (bool success, bytes memory result) = callee.delegatecall(data); 402 | require(success, "Delegatecall failed"); 403 | return result; 404 | } 405 | 406 | // Use of call 407 | function callExample(address callee, bytes memory data) public returns (bytes memory) { 408 | (bool success, bytes memory result) = callee.call(data); 409 | require(success, "Call failed"); 410 | return result; 411 | } 412 | 413 | // Use of staticcall 414 | function staticCallExample(address callee, bytes memory data) public view returns (bytes memory) { 415 | (bool success, bytes memory result) = callee.staticcall(data); 416 | require(success, "Staticcall failed"); 417 | return result; 418 | } 419 | 420 | // For loop 421 | function forLoopExample() public view returns (uint) { 422 | uint sum = 0; 423 | for (uint i = 0; i < numbers.length; i++) { 424 | sum += numbers[i]; 425 | } 426 | return sum; 427 | } 428 | 429 | // While loop 430 | function whileLoopExample() public view returns (uint) { 431 | uint sum = 0; 432 | uint i = 0; 433 | while (i < numbers.length) { 434 | sum += numbers[i]; 435 | i++; 436 | } 437 | return sum; 438 | } 439 | 440 | // Do-while loop 441 | function doWhileLoopExample() public view returns (uint) { 442 | uint sum = 0; 443 | uint i = 0; 444 | if (numbers.length == 0) { 445 | return sum; 446 | } 447 | do { 448 | sum += numbers[i]; 449 | i++; 450 | } while (i < numbers.length); 451 | return sum; 452 | } 453 | 454 | // Using tuples 455 | function tupleExample() public pure returns (uint, string memory, bool) { 456 | return (1, "Tuple", true); 457 | } 458 | 459 | // Function to demonstrate interaction with another contract 460 | function interactWithERC20(IERC20 token, address recipient, uint256 amount) public { 461 | require(token.transfer(recipient, amount), "Transfer failed"); 462 | } 463 | 464 | // Function to demonstrate use of storage pointers 465 | function storagePointerExample() public view returns (uint256) { 466 | uint256[] storage nums = numbers; 467 | return nums.length; 468 | } 469 | 470 | // Function to demonstrate use of memory pointers 471 | function memoryPointerExample() public view returns (uint256) { 472 | uint256[] memory nums = numbers; 473 | return nums.length; 474 | } 475 | 476 | // Inline assembly for more complex operations 477 | function assemblyComplexOperation(uint a, uint b) public pure returns (uint result) { 478 | assembly { 479 | let temp := add(a, b) 480 | result := mul(temp, 2) 481 | } 482 | } 483 | 484 | // Using .call() to send ether 485 | function sendEther(address payable recipient) public payable { 486 | (bool success, ) = recipient.call{value: msg.value}(""); 487 | require(success, "Ether transfer failed"); 488 | } 489 | 490 | // Using interface 491 | function callExampleFunction(IExample example, uint a) public returns (uint) { 492 | return example.exampleFunction(a); 493 | } 494 | 495 | // Check balance of ERC20 token using interface 496 | function checkERC20Balance(IERC20 token, address account) public view returns (uint256) { 497 | return token.balanceOf(account); 498 | } 499 | } 500 | -------------------------------------------------------------------------------- /extension.toml: -------------------------------------------------------------------------------- 1 | id = "solidity" 2 | name = "Solidity" 3 | version = "0.1.3" 4 | schema_version = 1 5 | authors = ["Daniel Zarifpour "] 6 | description = "💠 Solidity language support for Zed. ✰ and report issues ➩" 7 | repository = "https://github.com/zarifpour/zed-solidity" 8 | 9 | [language_servers.solidity] 10 | name = "Solidity Language Server" 11 | language = "Solidity" 12 | language_ids = { "Solidity" = "solidity" } 13 | 14 | [grammars.solidity] 15 | repository = "https://github.com/JoranHonig/tree-sitter-solidity" 16 | commit = "5cb506ae419c4ad620c77210fd47500d3d169dbc" 17 | -------------------------------------------------------------------------------- /languages/solidity/brackets.scm: -------------------------------------------------------------------------------- 1 | ("(" @open ")" @close) 2 | ("[" @open "]" @close) 3 | ("{" @open "}" @close) -------------------------------------------------------------------------------- /languages/solidity/config.toml: -------------------------------------------------------------------------------- 1 | name = "Solidity" 2 | grammar = "solidity" 3 | path_suffixes = ["sol"] 4 | autoclose_before = ";:.,=}])>" 5 | line_comments = ["// ", "/// "] 6 | block_comment = ["/*", "*/"] 7 | brackets = [ 8 | { start = "{", end = "}", close = true, newline = true }, 9 | { start = "[", end = "]", close = true, newline = true }, 10 | { start = "(", end = ")", close = true, newline = true }, 11 | ] 12 | -------------------------------------------------------------------------------- /languages/solidity/highlights.scm: -------------------------------------------------------------------------------- 1 | ; Literals 2 | ; -------- 3 | 4 | [ 5 | (string) 6 | (hex_string_literal) 7 | (unicode_string_literal) 8 | (yul_string_literal) 9 | ] @string 10 | 11 | (hex_string_literal 12 | "hex" @string.special.symbol 13 | ) 14 | 15 | (unicode_string_literal 16 | "unicode" @string.special.symbol 17 | ) 18 | 19 | [ 20 | (number_literal) 21 | (yul_decimal_number) 22 | (yul_hex_number) 23 | ] @number 24 | 25 | [ 26 | (true) 27 | (false) 28 | ] @constant.builtin 29 | 30 | (yul_boolean) @boolean.constant 31 | 32 | (comment) @comment 33 | 34 | ; -------- 35 | ; end Literals 36 | 37 | ; Definitions and references 38 | ; ----------- 39 | 40 | ; Variables 41 | [ 42 | (identifier) 43 | (yul_identifier) 44 | ] @variable 45 | 46 | ; Types 47 | (type_name) @type 48 | (primitive_type) @type 49 | (user_defined_type (identifier) @type) 50 | ["assembly"] @type 51 | 52 | (payable_conversion_expression "payable" @type) 53 | ; Ensures that delimiters in mapping( ... => .. ) are not colored like types 54 | (type_name "(" @punctuation.bracket "=>" @punctuation.delimiter ")" @punctuation.bracket) 55 | 56 | ; Definitions 57 | (struct_declaration 58 | name: (identifier) @type) 59 | (enum_declaration 60 | name: (identifier) @type) 61 | (contract_declaration 62 | name: (identifier) @type) 63 | (library_declaration 64 | name: (identifier) @type) 65 | (interface_declaration 66 | name: (identifier) @type) 67 | (event_definition 68 | name: (identifier) @type) 69 | 70 | (function_definition 71 | name: (identifier) @function) 72 | 73 | (modifier_definition 74 | name: (identifier) @function) 75 | (yul_evm_builtin) @function.builtin 76 | 77 | ; Use constructor coloring for special functions 78 | (constructor_definition "constructor" @constructor) 79 | (fallback_receive_definition "receive" @constructor) 80 | (fallback_receive_definition "fallback" @constructor) 81 | 82 | (struct_member name: (identifier) @property) 83 | (enum_value) @constant 84 | 85 | ; Invocations 86 | (emit_statement . (identifier) @type) 87 | (modifier_invocation (identifier) @function) 88 | 89 | (call_expression . (member_expression property: (identifier) @function.method)) 90 | (call_expression . (identifier) @function) 91 | 92 | ; Function parameters 93 | (call_struct_argument name: (identifier) @property) 94 | (event_paramater name: (identifier) @variable.parameter) 95 | (parameter name: (identifier) @variable.parameter) 96 | 97 | ; Yul functions 98 | (yul_function_call function: (yul_identifier) @function) 99 | (yul_function_definition . (yul_identifier) @function (yul_identifier) @variable.parameter) 100 | 101 | ; Structs and members 102 | (member_expression property: (identifier) @property) 103 | (struct_expression type: ((identifier) @type .)) 104 | (struct_field_assignment name: (identifier) @property) 105 | 106 | 107 | ; Tokens 108 | ; ------- 109 | 110 | ; Keywords 111 | (meta_type_expression "type" @keyword) 112 | ; Keywords 113 | [ 114 | "calldata" 115 | "catch" 116 | "constant" 117 | "contract" 118 | "do" 119 | "emit" 120 | "enum" 121 | "event" 122 | "for" 123 | "interface" 124 | "is" 125 | "library" 126 | "memory" 127 | "modifier" 128 | "pragma" 129 | "pure" 130 | "storage" 131 | "struct" 132 | "try" 133 | "using" 134 | "var" 135 | "view" 136 | "while" 137 | (immutable) 138 | (yul_variable_declaration) 139 | (virtual) 140 | (override_specifier) 141 | (yul_leave) 142 | ] @keyword 143 | 144 | [ 145 | "abstract" 146 | (visibility) 147 | ] @constructor 148 | 149 | [ 150 | "payable" 151 | "public" 152 | ] @constant 153 | 154 | [ 155 | (virtual) 156 | (override_specifier) 157 | ] @operator 158 | 159 | ; Color immutable and constant variables as constants 160 | [ 161 | (state_variable_declaration 162 | (type_name) 163 | (visibility) @keyword 164 | (immutable) @keyword 165 | (identifier) @constant) 166 | 167 | (state_variable_declaration 168 | (type_name) 169 | "constant" @keyword 170 | (identifier) @constant) 171 | ] 172 | 173 | (state_variable_declaration 174 | (type_name) 175 | (visibility ("public" @keyword))) 176 | 177 | (state_variable_declaration 178 | (type_name) 179 | (visibility ("private" @keyword))) 180 | 181 | (state_variable_declaration 182 | (type_name) 183 | (visibility ("internal" @keyword))) 184 | 185 | (state_variable_declaration 186 | (type_name) 187 | (visibility ("external" @keyword))) 188 | 189 | [ 190 | "view" 191 | "pure" 192 | ] @tag 193 | 194 | [ 195 | "break" 196 | "continue" 197 | "if" 198 | "else" 199 | "switch" 200 | "case" 201 | "default" 202 | ] @conditional 203 | 204 | [ 205 | "try" 206 | "catch" 207 | ] @exception 208 | 209 | [ 210 | "return" 211 | "returns" 212 | ] @keyword.return 213 | 214 | "function" @keyword.function 215 | 216 | "import" @include 217 | (import_directive "as" @include) 218 | (import_directive "from" @include) 219 | 220 | (event_paramater "indexed" @keyword) 221 | 222 | ; Punctuation 223 | 224 | [ 225 | "(" 226 | ")" 227 | "[" 228 | "]" 229 | "{" 230 | "}" 231 | ] @punctuation.bracket 232 | 233 | 234 | [ 235 | "." 236 | "," 237 | ] @punctuation.delimiter 238 | 239 | 240 | ; Operators 241 | 242 | [ 243 | "&&" 244 | "||" 245 | ">>" 246 | ">>>" 247 | "<<" 248 | "&" 249 | "^" 250 | "|" 251 | "+" 252 | "-" 253 | "*" 254 | "/" 255 | "%" 256 | "**" 257 | "<" 258 | "<=" 259 | "==" 260 | "!=" 261 | "!==" 262 | ">=" 263 | ">" 264 | "!" 265 | "~" 266 | "-" 267 | "+" 268 | "++" 269 | "--" 270 | "+=" 271 | "-=" 272 | "=" 273 | "*=" 274 | ":=" 275 | ] @operator 276 | 277 | [ 278 | "delete" 279 | "new" 280 | ] @keyword.operator 281 | 282 | [ 283 | "break" 284 | "continue" 285 | "if" 286 | "else" 287 | "switch" 288 | "case" 289 | "default" 290 | ] @keyword.conditional 291 | 292 | [ 293 | "for" 294 | ] 295 | @keyword.repeat 296 | 297 | [ 298 | "?" 299 | ":" 300 | ] @keyword.operator 301 | 302 | [ 303 | "revert" 304 | ] @keyword.revert 305 | 306 | [ 307 | "error" 308 | ] @keyword.error 309 | 310 | ; Pragma 311 | ; -------- 312 | 313 | [ 314 | "pragma" 315 | "solidity" 316 | ] @keyword.directive 317 | 318 | (pragma_directive) @primary 319 | 320 | [ 321 | (solidity_pragma_token 322 | "||" @string.special.symbol) 323 | 324 | (solidity_pragma_token 325 | "-" @string.special.symbol) 326 | ] 327 | 328 | (solidity_version) @string.special 329 | 330 | [ 331 | (solidity_version_comparison_operator) @string.special.symbol 332 | (solidity_version_comparison_operator 333 | ">=" @string.special.symbol) 334 | (solidity_version_comparison_operator 335 | "=" @string.special.symbol) 336 | (solidity_version_comparison_operator 337 | ">" @string.special.symbol) 338 | (solidity_version_comparison_operator 339 | "<=" @string.special.symbol) 340 | (solidity_version_comparison_operator 341 | "<" @string.special.symbol) 342 | (solidity_version_comparison_operator 343 | "^" @string.special.symbol) 344 | (solidity_version_comparison_operator 345 | "~" @string.special.symbol) 346 | ] 347 | 348 | ; -------- 349 | ; end Pragma 350 | 351 | ; Additional rules 352 | ; -------- 353 | 354 | (expression_statement (call_expression . function: (identifier) @constructor)) 355 | (try_statement "try" @keyword) 356 | (catch_clause "catch" @keyword) 357 | (call_expression function: (member_expression property: (identifier) @function)) 358 | (error_declaration name: (identifier) @constant) 359 | (event_definition name: (identifier) @tag) 360 | (revert_statement error: (identifier) @constant) 361 | (revert_statement "revert" @constructor) 362 | (emit_statement name: (identifier) @tag) 363 | (emit_statement "emit" @boolean) 364 | (user_defined_type (identifier)) @variable 365 | (call_expression function: (identifier) @function) 366 | 367 | ; -------- 368 | ; end Additional rules 369 | -------------------------------------------------------------------------------- /languages/solidity/indents.scm: -------------------------------------------------------------------------------- 1 | [ 2 | (block_statement) 3 | (if_statement) 4 | (emit_statement) 5 | (revert_statement) 6 | (try_statement) 7 | (catch_clause) 8 | (for_statement) 9 | (while_statement) 10 | (do_while_statement) 11 | (call_expression) 12 | (error_declaration) 13 | (enum_declaration) 14 | ] @indent.begin 15 | 16 | (_ "[" "]" @end) @indent 17 | (_ "{" "}" @end) @indent 18 | (_ "(" ")" @end) @indent -------------------------------------------------------------------------------- /languages/solidity/locals.scm: -------------------------------------------------------------------------------- 1 | (function_definition) @local.scope 2 | (block_statement) @local.scope 3 | 4 | (function_definition (parameter name: (identifier) @local.definition)) 5 | 6 | ; still have to support tuple assignments 7 | (assignment_expression left: (identifier) @local.definition) 8 | 9 | (identifier) @local.reference -------------------------------------------------------------------------------- /languages/solidity/outline.scm: -------------------------------------------------------------------------------- 1 | (contract_declaration (identifier) @name) @item 2 | (library_declaration (identifier) @name) @item 3 | (interface_declaration (identifier) @name) @item 4 | 5 | (event_definition (identifier) @name) @item 6 | (constructor_definition "constructor" @name) @item 7 | (function_definition (identifier) @name) @item 8 | (modifier_definition (identifier) @name) @item 9 | (fallback_receive_definition "fallback" @name) @item 10 | (fallback_receive_definition "receive" @name) @item 11 | 12 | (error_declaration (identifier) @name) @item 13 | (struct_declaration (identifier) @name) @item 14 | (enum_declaration (identifier) @name) @item -------------------------------------------------------------------------------- /public/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zarifpour/zed-solidity/0ab0f33215ee8a553041cbbf6f08ef691b99a5d2/public/screenshot.png -------------------------------------------------------------------------------- /src/solidity.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs}; 2 | use zed_extension_api::{self as zed, Result}; 3 | 4 | const SERVER_PATH: &str = "node_modules/@nomicfoundation/solidity-language-server/out/index.js"; 5 | const PACKAGE_NAME: &str = "@nomicfoundation/solidity-language-server"; 6 | 7 | struct SolidityExtension { 8 | did_find_server: bool, 9 | } 10 | 11 | impl SolidityExtension { 12 | fn server_exists(&self) -> bool { 13 | fs::metadata(SERVER_PATH).map_or(false, |stat| stat.is_file()) 14 | } 15 | 16 | fn server_script_path(&mut self, config: zed::LanguageServerConfig) -> Result { 17 | let server_exists = self.server_exists(); 18 | if self.did_find_server && server_exists { 19 | return Ok(SERVER_PATH.to_string()); 20 | } 21 | 22 | zed::set_language_server_installation_status( 23 | &config.name, 24 | &zed::LanguageServerInstallationStatus::CheckingForUpdate, 25 | ); 26 | let version = zed::npm_package_latest_version(PACKAGE_NAME)?; 27 | 28 | if !server_exists 29 | || zed::npm_package_installed_version(PACKAGE_NAME)?.as_ref() != Some(&version) 30 | { 31 | zed::set_language_server_installation_status( 32 | &config.name, 33 | &zed::LanguageServerInstallationStatus::Downloading, 34 | ); 35 | let result = zed::npm_install_package(PACKAGE_NAME, &version); 36 | match result { 37 | Ok(()) => { 38 | if !self.server_exists() { 39 | Err(format!( 40 | "installed package '{PACKAGE_NAME}' did not contain expected path '{SERVER_PATH}'", 41 | ))?; 42 | } 43 | } 44 | Err(error) => { 45 | if !self.server_exists() { 46 | Err(error)?; 47 | } 48 | } 49 | } 50 | } 51 | 52 | self.did_find_server = true; 53 | Ok(SERVER_PATH.to_string()) 54 | } 55 | } 56 | 57 | impl zed::Extension for SolidityExtension { 58 | fn new() -> Self { 59 | Self { 60 | did_find_server: false, 61 | } 62 | } 63 | 64 | fn language_server_command( 65 | &mut self, 66 | config: zed::LanguageServerConfig, 67 | _worktree: &zed::Worktree, 68 | ) -> Result { 69 | let server_path = self.server_script_path(config)?; 70 | Ok(zed::Command { 71 | command: zed::node_binary_path()?, 72 | args: vec![ 73 | env::current_dir() 74 | .unwrap() 75 | .join(&server_path) 76 | .to_string_lossy() 77 | .to_string(), 78 | "--stdio".to_string(), 79 | ], 80 | env: Default::default(), 81 | }) 82 | } 83 | } 84 | 85 | zed::register_extension!(SolidityExtension); 86 | --------------------------------------------------------------------------------