- Install the VS Code extension directly from the VS Code marketplace following this guide
- Clone the VS Code extension repo and open the test-fixtures directory in VS Code.
- Follow the VS Code extension's "Development, Debugging and Automated Testing Guide" to set up a test environment.
- Use the "Run Extension (without Rust Analyzer)" launch configuration to test the extension in an isolated environment (see further instructions in the "Development, Debugging and Automated Testing Guide").
NOTE: If you're using the Debug Environment option and have already cloned the VS Code extension repository in the past, be sure to pull the latest changes to make sure you get the latest release of the language server.
The instructions below are written for the erc20 contract in the "test-fixtures" directory/workspace of the VS Code extension's repository (unless stated otherwise), so open that in VS Code first.
You can view a list of all available commands in one of the following ways:
- Typing
>ink!
into the "Command Palette" (notice the preceding>
beforeink!
in this case). - Clicking in the "Command Palette", then selecting
Show and Run Commands >
, and then typingink!
(after the now prefilled>
). - Typing
Cmd/Ctrl + Shift + P
to navigate directly into theShow and Run Commands >
section of the "Command Palette", and then typeink!
. - Hovering over the
ink! analyzer
"Status Bar" item.
Action:
Remove the ink! storage item i.e.
/// A simple ERC-20 contract.
#[ink(storage)]
// ...
pub struct Erc20 {
/// Total token supply.
total_supply: Balance,
// ...
}
Expected Result:
- You should see diagnostic "squiggles" (zigzag underlines) on the ink! contract
mod
item (i.e. covering the linemod erc20 {
). - Hovering over the "squiggles" should show a diagnostic message like
Missing ink! storage
. - Hovering over the "squiggles" should reveal a "quickfix" to
Add ink! storage "struct".
- Alternatively, positioning the cursor on the "squiggles" and clicking the "light bulb" that's triggered by this action will also reveal the above quickfix.
Additional testing examples:
- Remove other required ink! entities (e.g. remove all ink! messages).
- Add a conflicting argument to one of the ink! attributes (e.g. change
#[ink(constructor)]
to#[ink(constructor, topic)]
or change#[ink::contract]
to#[ink::contract(payable)]
). - Add an unknown argument to one of the ink! attributes
(e.g. change
#[ink(constructor)]
to#[ink(constructor, xyz)]
). - Apply an ink! attribute to the wrong Rust item kind
(e.g. add an
#[ink::test]
attribute above the lineimpl Erc20 {
). - Add unexpected or remove required Rust item invariants e.g. remove the
Self
return type (i.e. remove-> Self
) from one of the ink! constructor functions or add a self reference receiver (i.e. add&self
as the first parameter) to one of the ink! constructor functions. - Add clashing selectors to ink! constructors or ink! messages (e.g. change all
#[ink(message)]
attributes to#[ink(message, selector = 1)]
, or add an ink! constructor or ink! message with the samefn
name as an existing callable e.g. add another ink! message namedtotal_supply
). - Move an ink! entity to the wrong scope (e.g. move an ink! message into the root of the contract
mod
- e.g. move thetotal_supply
ink! message to the line right after the ink! storagestruct
). - Set a wrong value for an ink!
env
argument value (e.g. replace#[ink::contract(env = crate::CustomEnvironment)]
with#[ink::contract(env = self::CustomEnvironment)]
in the psp22-extension contract in the test-fixtures directory). - Remove the
ink::env::Environment
implementation for a custom chain environment type (e.g. remove theink::env::Environment
implementation for theCustomEnvironment
type i.e. by removing theimpl
block starting with the lineimpl Environment for CustomEnvironment {
in the psp22-extension contract in the test-fixtures directory). - Remove one of the methods in a trait definition implementation block (e.g. remove the
total_supply(&self) -> Balance
method from theimpl
block starting with lineimpl BaseErc20 for Erc20 {
in the trait-erc20 contract in the test-fixtures directory). - Add a custom method that's not defined in the trait definition to its implementation block (e.g. add a method named
another
to theimpl
block starting with lineimpl BaseErc20 for Erc20 {
in the trait-erc20 contract in the test-fixtures directory). - Modify the signature of a trait definition implementation block method to not match the signature of the similarly
named method in the trait definition (e.g. replace the immutable self receiver in
total_supply(&self) -> Balance
with a mutable self receiver i.e.total_supply(&mut self) -> Balance
, or replace thebool
return type with aOption<bool>
return type for theimpl
block starting with lineimpl BaseErc20 for Erc20 {
in the trait-erc20 contract in the test-fixtures directory). - Modify the ink! attribute arguments of a trait definition implementation block method to not match those of the
similarly named method in the trait definition (e.g. add the ink!
payable
attribute argument to thetotal_supply(&self) -> Balance
method i.e. replace#[ink(message)]
with#[ink(message, payable)]
for theimpl
block starting with lineimpl BaseErc20 for Erc20 {
in the trait-erc20 contract in the test-fixtures directory). - Remove the
ink::env::chain_extension::FromStatusCode
implementation for a chain extension'sErrorCode
type (e.g. remove theink::env::chain_extension::FromStatusCode
implementation for thePsp22Error
type i.e. by removing theimpl
block starting with the lineimpl ink::env::chain_extension::FromStatusCode for Psp22Error {
in the psp22-extension contract in the test-fixtures directory). - Use
Self::ErrorCode
in a chain extension (e.g. change thetoken_name
extension declaration fromfn token_name(asset_id: u32) -> Result<Vec<u8>>;
tofn token_name(asset_id: u32) -> core::result::Result<Vec<u8>, Self::ErrorCode>;
in the psp22-extension contract in the test-fixtures directory). - Remove at least one SCALE codec trait (i.e.
scale::Encode
,scale::Decode
orscale_info::TypeInfo
) implementation (including via#[ink::scale_derive(...)]
or#[derive(...)]
attributes) from a chain extension'sErrorCode
type or a custom input or output type for one of its methods (e.g. remove the#[ink::scale_derive(Encode, Decode, TypeInfo)]
attribute for thePsp22Error
type i.e. by removing the attributes above the linepub enum Psp22Error {
in the psp22-extension contract in the test-fixtures directory).
All the above edits should result in diagnostics "squiggles" that reveal one or more quickfixes for the issues.
NOTE: The list of diagnostics and quickfixes above is not exhaustive.
- For attribute macro completions, make one of the ink! macro-based attributes "incomplete"
(e.g. change
#[ink::contract]
to#[ink]
or#[ink::c]
) and either start typing to complete the macro name or hitCmd/Ctrl + Space
to trigger a completion proposal manually. - For "primary" attribute argument completions (e.g.
storage
,event
,constructor
,message
e.t.c), make one of the ink! argument-based attributes "incomplete" (e.g. change#[ink(storage)]
to#[ink()]
) and either typing the(
character, or starting to type inside the parentheses, or hittingCmd/Ctrl + Space
should trigger completion proposals. - For "complementary" attribute argument completions
(e.g.
payable
,default
,selector
for#[ink(message)]
, oranonymous
for#[ink(event)]
e.t.c), add a comma after an existing attribute argument (e.g. change#[ink(message)]
to#[ink(message,)]
) and either typing the comma (,
) character, or hittingCmd/Ctrl + Space
should trigger completion proposals. - For "complementary" argument completions for ink! attribute macros (e.g.
env
andkeep_attr
for#[ink::contract]
), add parentheses after the attribute macro (e.g. change#[ink::contract]
to#[ink::contract()]
), and either typing the(
character, or starting to type inside the parentheses, or hittingCmd/Ctrl + Space
should trigger completion proposals.
Hovering over an ink! attribute macro (e.g. #[ink::contract]
) or argument (e.g. #[ink(storage)]
or the env = ...
part in #[ink::contract(env = crate::Environment)]
) will reveal related usage documentation for the
ink! attribute macro or specific ink! attribute argument in a popup.
Positioning the cursor either on an ink! attribute (e.g. on an #[ink::contract]
) or on the "declaration"
(e.g. anywhere on the line mod erc20 {
but not inside the body) of a Rust item that is either already annotated
with ink! attributes or can be annotated with ink! attributes (e.g. mod
, struct
, fn
, impl
e.t.c) will trigger
a "light bulb" with relevant code actions.
Testing examples:
- Positioning the cursor on an ink! attribute (e.g. on
#[ink::contract]
) will trigger a "light bulb" with code actions for adding complementary arguments (if any) to the ink! attribute (i.e.env
andkeep_attr
for#[ink(contract)]
orpayable
,default
andselector
for#[ink(message)]
). - Positioning the cursor on the "declaration" of a Rust item without any other ink! attributes but whose item kind
can be annotated with ink! attributes (e.g.
mod
,struct
,fn
,impl
e.t.c) will trigger a "light bulb" with code actions for adding relevant ink! attributes depending on the context (e.g.Add ink! message attribute
for anfn
item). - Positioning the cursor on the ink! contract
mod
item "declaration" (i.e. on the linemod erc20 {
) will trigger a "light bulb" with code actions for adding anink! event "struct"
,ink! message "fn"
orink! constructor "fn"
to the ink! contract. - After inserting an ink! event (e.g. use code action described above), positioning the cursor on the
ink! event
struct
item "declaration" (i.e. on the linepub struct MyEvent {
) will trigger a "light bulb" with code actions for adding anink! topic "field"
. - Positioning the cursor on the item "declaration" of a "test"
mod
(i.e. amod
annotated with#[cfg(test)]
or similar e.g. on the linemod tests {
) will trigger a "light bulb" with code actions for adding anink! test "fn"
to themod
item. - Positioning the cursor on the item "declaration" of a "test"
mod
with an additionale2e-tests
feature condition (i.e. amod
annotated with#[cfg(all(test, feature = "e2e-tests"))]
or similar e.g. on the linemod e2e_tests {
) will trigger a "light bulb" with code actions for adding anink! e2e test "fn"
to themod
item. - Positioning the cursor on the "declaration" of a Rust item with multiple ink! attributes
(e.g.
#[ink(event)]\n#[ink(anonymous)]
e.t.c) will trigger a "light bulb" with code actions for "flattening" the ink! attributes. - For VS Code version 1.86 or newer, you can enable code actions on empty lines by changing the
Editor › Lightbulb: Enabled
setting toon
(See this guide for details - the equivalent entry forsettings.json
is"editor.lightbulb.enabled" = "on"
), with this setting enabled, positioning the cursor on an empty line will trigger a "light bulb" with code actions for inserting relevant ink! entities for the context (e.g. placing the cursor on the new line between#![cfg_attr(not(feature = "std"), no_std, no_main)]
and#[ink::contract]
trigger a "light bulb" with code actions for adding an ink! trait definition, ink! chain extension, ink! storage item or a custom ink! environment at the cursor position). NOTE: Alternatively, to trigger code actions on empty lines without changing the above setting (or on versions of VS Code older than 1.86), you can right-click at the empty line position, and then selectRefactor
from the subsequent context menu to reveal the equivalent code actions.
ink! attribute arguments that are expected to have values
(e.g. selector
, env
, keep_attr
, namespace
, extension
, handle_status
, derive
e.t.c)
will have inlay hints (additional inline information) about the type of the expected value added right after
the name
part of the name=value
pair (e.g. : u32 | _
for selector
, : impl Environment
for env
,
and : bool
for handle_status
).
When adding ink! attribute arguments (e.g. "primary" like storage
, event
, constructor
, message
e.t.c or
"complementary"/"additional" like env
, keep_attr
, payable
, selector
, anonymous
e.t.c),
a popup with additional information about the "signature" for the ink! attribute and a description about
the current argument can be triggered either automatically after typing the opening parenthesis
((
) character or a comma (,
) separator character, or manually by hitting Cmd/Ctrl + Shift + Space
.