├── .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 | 
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 |
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 |
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 |
--------------------------------------------------------------------------------