Compare commits

..

87 Commits

Author SHA1 Message Date
folex
589238f7a5
fix(deps): update vscode to 1.94.0 (#125)
fix(deps): vscode 1.94.0 compatibility
2024-10-07 12:28:48 +07:00
renovate[bot]
6314288e73
chore(deps): update dependency @fluencelabs/aqua-lib to v0.12.1 (#124)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-05 12:17:26 +03:00
Anatolios Laskaris
dbb1f95de0
chore: Update renovate (#123) 2024-09-04 17:31:25 +03:00
renovate[bot]
3c1d2c30e0
chore(deps): update dependency vscode to v1.92.1 (#112)
* chore(deps): update dependency vscode to v1.92.1

* chore(ci): setup ssh session on failure

* fix(ci): ignore fcli setup error

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: folex <0xdxdy@gmail.com>
2024-08-12 15:17:23 +03:00
renovate[bot]
876ae6eb8c
chore(deps): update dependency @vscode/test-electron to v2.4.1 (#117)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-12 12:27:52 +03:00
renovate[bot]
e597a27197
chore(deps): update dependency vscode-languageserver-textdocument to v1.0.12 (#111)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-12 12:27:24 +03:00
renovate[bot]
497a5e17a2
fix(deps): update dependency @fluencelabs/aqua-language-server-api to v0.14.11 (#115)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-12 12:26:59 +03:00
renovate[bot]
02b01e474a
fix(deps): update dependency @fluencelabs/aqua-language-server-api to v0.14.10 (#110)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-07 17:47:12 +07:00
renovate[bot]
c83cdc9e46
fix(deps): update dependency @fluencelabs/aqua-language-server-api to v0.14.9 (#109)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-06 13:56:59 +03:00
renovate[bot]
6b628c0df2
chore(deps): update all github-actions (#103)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-06 13:43:22 +03:00
renovate[bot]
ab0ddf6623
fix(deps): pin dependencies (#101)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-06 13:42:58 +03:00
renovate[bot]
d4f883a211
fix(deps): update dependency @fluencelabs/aqua-lib to ^0.10.1 (#102)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-29 10:10:48 +03:00
Dima
a31e1c78b5
find file paths in use and import tokens (#105) 2024-05-29 10:10:16 +03:00
renovate[bot]
6edf408617
chore(deps): update typescript-eslint monorepo to v7 (#68)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 08:22:45 +03:00
renovate[bot]
feed343c8a
chore(deps): update dependency global-dirs to v4 (#94)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 08:22:19 +03:00
renovate[bot]
968794ff11
chore(deps): update dependency eslint to ^8.56.0 (#96)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 08:21:58 +03:00
renovate[bot]
e15a1dbbfb
fix(deps): update dependency vscode-languageclient to v9 (#69)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 08:20:55 +03:00
renovate[bot]
2505865f67
fix(deps): update dependency vscode-languageserver to v9 (#70)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 08:20:36 +03:00
renovate[bot]
62e063b919
chore(deps): update dependency @vscode/test-cli to ^0.0.9 (#83)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 08:10:29 +03:00
renovate[bot]
7dd3d60d8e
chore(deps): update dependency @vscode/test-electron to v2.3.10 (#82)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 08:09:58 +03:00
Dima
b7c9d02042
update renovate config to make unstable updates for fluencelabs packages (#98) 2024-05-15 08:08:51 +03:00
renovate[bot]
9fac848273
chore(deps): update dependency @types/vscode to v1.89.0 (#65)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 08:08:28 +03:00
Dima
d5d0f80bf6
update aqua to 0.14.7 (#97) 2024-05-15 08:05:55 +03:00
Dima
c4411eb54c
update aqua to 0.14.6 (#95) 2024-04-24 19:14:21 +03:00
DieMyst
4b0c776a69 filter non-related errors, update aqua 2024-04-15 14:50:53 +07:00
Dima
6e05ea7b25
add highlighted todo (#92) 2024-03-05 20:45:28 +03:00
renovate[bot]
a54e0ed202
fix(deps): update dependency @fluencelabs/aqua-lib to ^0.10.0 (#86)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-01 13:27:59 +03:00
Dima
8c3f478421
update aqua to 0.14.4 (#90) 2024-03-01 13:27:39 +03:00
renovate[bot]
038065fa1f
fix(deps): update dependency @fluencelabs/aqua-language-server-api to v0.14.3 (#88)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-29 15:11:35 +03:00
Dima
56d4d41e6c
feat(aqua-vscode): Prettify types view [LNG-331] (#85) 2024-02-21 09:13:14 +03:00
Dima
0055ff0859
use path in locations to search definitions (#84) 2024-02-09 16:05:55 +07:00
renovate[bot]
798bc6b08f
fix(deps): update dependency @fluencelabs/aqua-language-server-api to v0.14.0 (#77)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-01 10:29:31 +03:00
InversionSpaces
89fcde5d26
feat(tests): Add unit tests [LNG-323] (#81)
* Add imports tests

* Add unit tests on document info

* Add workflow

* PR fixes

* Update server/src/test/info.test.ts

Co-authored-by: shamsartem <shamsartem@gmail.com>

* PR fixes

* Update target, PR fixes

* Update .vscodeignore

---------

Co-authored-by: shamsartem <shamsartem@gmail.com>
2024-01-18 10:25:09 +01:00
InversionSpaces
0ff680eb4a
fix(ci): Update publish workflow (#80)
* Update workflow, bump vscode

* Remove BRANCH_NAME

* Change name
2024-01-16 11:14:42 +01:00
InversionSpaces
1c5d01cd97
feat(tests): Add integration tests [LNG-318] (#76) 2024-01-16 09:36:45 +03:00
InversionSpaces
309905b680
Add null to return type (#79) 2024-01-12 13:30:06 +01:00
InversionSpaces
8abf687b01
fix(aqua-vscode): Refactor token info gathering, fix error in onHover (#78)
* Refactor onHover and onDefinition

* Fix path encoding

* Use url

* Update server/src/server.ts

Co-authored-by: Akim <59872966+akim-bow@users.noreply.github.com>

---------

Co-authored-by: Akim <59872966+akim-bow@users.noreply.github.com>
2024-01-12 13:24:44 +01:00
InversionSpaces
6a6c08a569
Decode uri (#75) 2023-12-26 15:27:43 +01:00
Dima
ba3192f988
delete legacy import, pass new improts to compiler (#74) 2023-12-25 19:09:53 +03:00
InversionSpaces
3fad69ba77
Rewrite imports handling (#73) 2023-12-20 12:57:14 +01:00
Dima
60bd5335b5
suppress error from updateimports (#67) 2023-12-13 10:49:37 +03:00
InversionSpaces
e11ec1bd5b
feat(server): support workspaces [LNG-256] (#63)
* Rewrite settings manager

* Add cwd

* Update server/src/settings.ts

Co-authored-by: Akim <59872966+akim-bow@users.noreply.github.com>

* Update server/src/settings.ts

Co-authored-by: Akim <59872966+akim-bow@users.noreply.github.com>

* Rename var

* Move delay to config

---------

Co-authored-by: Akim <59872966+akim-bow@users.noreply.github.com>
2023-12-08 11:32:00 +01:00
Dima
41fd59fe31
feat(server): Support show types on hover [LNG-285] (#64) 2023-12-08 11:45:52 +03:00
Dima
fdb17c9266
update aqua (#52) 2023-11-28 13:22:20 +03:00
InversionSpaces
cbff64a0a2
feat(vscode): Retrieve imports from fluence CLI [LNG-252] (#49)
* Fix settings definition

* Fix onDidChangeConfiguration event

* Implement settings manager

* Remove undefined

* Refactor
2023-10-10 12:47:24 +02:00
InversionSpaces
780246c71e
feat(vs-code): Add warnings [fixes LNG-248] (#48)
* Bump api version

* Refactor, add warnings

* Bump version
2023-09-28 12:19:31 +02:00
InversionSpaces
ce32be5c65
Give comments higher priority (#47) 2023-09-14 18:48:19 +03:00
InversionSpaces
3194dfb651
feat(vs-code): Update aqua syntax defs [fixes LNG-227] (#46) 2023-09-01 15:38:29 +03:00
Dima
f1ed3059f2
Fix null settings (#45) 2023-08-24 14:19:43 +03:00
Dima
906e40b273
fix empty settings (#44) 2023-08-24 13:07:52 +03:00
Dima
0f56c283a8
update lsp to 0.11.11 (#43) 2023-08-24 12:26:22 +03:00
renovate[bot]
d5d3a117b0
fix(deps): update dependency @fluencelabs/aqua-language-server-api to v0.11.9 (#34)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-16 04:26:14 +03:00
Dima
6b73358330
feat: add useOnlyImportsFromSettings flag (#41) 2023-08-16 04:25:14 +03:00
Dima
4d26bfe686
update aqua to 0.11.0 (#32) 2023-05-30 17:42:43 +03:00
renovate[bot]
8ea3fdcb19
Add renovate.json (#24)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-30 17:12:09 +03:00
Dima
d5d96c1f68
update aqua to 0.10.6 (#28) 2023-05-03 18:49:33 +03:00
Dima
9e3ef257a7
update imports order (#27) 2023-02-23 14:31:05 +03:00
mikhail-1e20
16701cf166
docs: README minor update (#26) 2023-02-22 08:17:26 +03:00
Dima
7998503155
update aqua to 0.9.4 (#25) 2023-02-10 11:58:25 +03:00
Dima
38e5e14774
update aqua (#23) 2022-11-30 15:34:13 +03:00
Dima
e1970cdbe3
update aqua (#22) 2022-10-12 10:57:49 +03:00
Valery Antopol
802e4c3810
feat: add basic syntax highlighting for AIR (#21) 2022-08-26 18:19:45 +03:00
Dima
7c7e80bd75
resolve relative paths for imports (#20) 2022-08-25 15:30:22 +03:00
Dima
ae72f62dbe
Find nearest node_modules between project path and aqua file (#19) 2022-08-10 15:06:57 +03:00
Dima
7a71f0fbbe
Go-to for structs and imports (#18) 2022-07-26 17:16:48 +03:00
DieMyst
03169bef44 validate improts 2022-06-02 16:26:01 +03:00
DieMyst
9136b322fc update readme 2022-06-02 14:35:57 +03:00
Dima
95fe2adfc9
Definitions between files (#16) 2022-06-02 13:42:48 +03:00
DieMyst
8be467370b rename extension 2022-05-25 12:04:15 +03:00
DieMyst
4d35b17f9a fix 2022-05-24 17:31:34 +03:00
Dima
620534b6ec
Go-to-definition for extension (#15) 2022-05-24 17:27:55 +03:00
Dima
f2866f8075
Extension with language server (#14) 2022-05-17 15:06:52 +03:00
folex
f387caa792
Add join and a lot more highlighting rules (#13) 2022-01-18 15:56:24 +03:00
Pavel
b5f81af561
New syntax rules (modules-related, constants) (#12)
* Add syntax rules for module, export etc.

* Add syntax for constants
2021-09-17 15:35:48 +03:00
folex
f90d98d9e5
Add nil, <<- (#10) 2021-08-12 13:57:06 +03:00
folex
c3e78a2a19
Remove "install compiler" from readme (#9) 2021-06-24 16:43:58 +03:00
Dzmitry Lahoda
29c1d264ea
Add link to extension on marketplace (#7) 2021-06-24 16:43:00 +03:00
folex
775c025174
add 'co' to control.flow (#8) 2021-06-24 16:41:33 +03:00
Pavel
bdb97b1788
Improvements (#6)
* Add more tokens coloring

* Repurpose several token types

* Make it easier for users to change highlighting in settings

* Better align of types highlighting with popular languages token scheme

* Better rules arrangement and addition of comments

* Update readme
2021-06-01 13:57:57 +03:00
Pavel
e756255578
Fix publishing to marketplace (#5) 2021-05-27 15:04:28 +03:00
Pavel Murygin
a3ae73dd86 Add publishing to the vscode marketplace 2021-05-27 13:14:41 +03:00
Pavel Murygin
d95e145869 Fix vsignore file 2021-05-27 13:07:41 +03:00
Pavel Murygin
801ffbd26e Add info about aqua to the readme 2021-05-27 12:59:20 +03:00
Pavel Murygin
c97c220177 move vscode plugin into the repo root 2021-05-25 12:57:56 +03:00
Pavel
03148eae86
Fix version calculation (#4)
Fix version calculation
2021-05-25 12:51:51 +03:00
Pavel Murygin
73c68481c3 fix versioning 2021-05-25 11:53:01 +03:00
Pavel
433ce73acc
Vsix (#3)
Packaging as `.vsix` extension
2021-05-25 11:39:01 +03:00
58 changed files with 9835 additions and 303 deletions

14
.eslintrc.json Normal file
View File

@ -0,0 +1,14 @@
{
"env": {
"browser": true,
"commonjs": true,
"es2021": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest"
},
"plugins": ["@typescript-eslint"],
"rules": {}
}

8
.github/renovate.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"extends": [
"github>fluencelabs/renovate",
"github>fluencelabs/renovate:npm"
],
"ignorePaths": ["api/aqua-api-example/**"],
"enabledManagers": ["npm"]
}

64
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: 'Build and release Aqua VSCE'
on:
push:
branches:
- 'main'
workflow_dispatch:
jobs:
publish:
name: 'Publish'
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get update && sudo apt-get --yes --force-yes install jq
- name: Get version from npm and increment
run: |
VERSION="1.0.${{ github.run_number }}"
PKG_NAME="$(cat package.json | jq -r .name)"
# save info to env
echo "FINAL_VERSION=$VERSION" | tee -a $GITHUB_ENV
echo "PKG_NAME=$PKG_NAME" | tee -a $GITHUB_ENV
echo "PKG_FILE=${PKG_NAME}-${VERSION}.vsix" | tee -a $GITHUB_ENV
- name: Set version to ${{ env.FINAL_VERSION }}
run: |
yarn version --new-version ${{ env.FINAL_VERSION }} --no-git-tag-version
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- name: Package and publish
run: |
npm i
npm i -g vsce
vsce package
vsce publish -p ${{ secrets.VSCE_PAT }}
- name: Create release
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.FINAL_VERSION }}
name: Aqua VSCE ${{ env.FINAL_VERSION }}
body: |
Version: ${{ env.FINAL_VERSION }}
files: |
${{ env.PKG_FILE }}
draft: true
prerelease: false

34
.github/workflows/run-tests.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: 'test'
on:
pull_request:
paths-ignore:
- '**.md'
- '.github/**'
- '!.github/workflows/tests.yml'
- '!.github/workflows/run-tests.yml'
push:
branches:
- 'main'
paths-ignore:
- '**.md'
- '.github/**'
- '!.github/workflows/tests.yml'
- '!.github/workflows/run-tests.yml'
concurrency:
group: '${{ github.workflow }}-${{ github.ref }}'
cancel-in-progress: true
jobs:
tests:
name: 'Integration tests'
uses: ./.github/workflows/tests.yml
with:
ref: ${{ github.ref }}
unit-tests:
name: 'Unit tests'
uses: ./.github/workflows/unit-tests.yml
with:
ref: ${{ github.ref }}

53
.github/workflows/tests.yml vendored Normal file
View File

@ -0,0 +1,53 @@
name: Run tests with workflow_call
on:
workflow_call:
inputs:
ref:
description: 'git ref to checkout to'
type: string
default: 'main'
fcli-version:
description: 'fcli version to use'
type: string
default: 'main'
env:
FORCE_COLOR: true
jobs:
aqua-vscode:
name: 'Run integration tests'
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: fluencelabs/aqua-vscode
ref: ${{ inputs.ref }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm'
- name: Setup fcli
uses: fluencelabs/setup-fluence@v1
with:
artifact: fcli
version: ${{ inputs.fcli-version }}
continue-on-error: true
- name: Install dependencies
run: npm ci
- name: Run before-tests
run: npm run before-tests
- name: Run tests
uses: coactions/setup-xvfb@v1
with:
run: npm run test

39
.github/workflows/unit-tests.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: Run tests with workflow_call
on:
workflow_call:
inputs:
ref:
description: 'git ref to checkout to'
type: string
default: 'main'
env:
FORCE_COLOR: true
jobs:
aqua-vscode:
name: 'Run unit tests'
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: fluencelabs/aqua-vscode
ref: ${{ inputs.ref }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
uses: coactions/setup-xvfb@v1
with:
run: npm run test:unit

View File

@ -1,97 +0,0 @@
name: "build vscode syntax highlight"
on:
push:
jobs:
npm-publish:
name: "Publish"
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
### Extract branch name
- name: Extract branch name
if: github.event_name != 'pull_request'
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV
id: extract_branch
- name: Extract branch name
if: github.event_name == 'pull_request'
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v2
### Calculate FINAL_VERSION
- name: Install jq
run: sudo apt-get update && sudo apt-get --yes --force-yes install jq
- name: Get version from npm and increment
run: |
cd vscode-highlight
# install semver and add it to PATH
yarn global add semver
PATH="$(yarn global bin):$PATH"
# sanitize branch name so it can be used as a semver suffix (replace [^0-9a-zA-Z-] with hyphen)
SANITIZED_BRANCH="$(echo -n "${{ env.BRANCH_NAME }}" | tr -C '[:alnum:]-' -)"
# get package name from package.json
PKG_NAME="$(cat package.json | jq -r .name)"
# take all versions from npm and replace single quotes with double quotes
NPM_VERSIONS=$(yarn info --silent "$PKG_NAME" versions 2>/dev/null | tr \' \")
# take only versions that contain branch name
NPM_VERSIONS_FILTERED=$(echo $NPM_VERSIONS | jq -r ".[] | select(contains(\"$SANITIZED_BRANCH\"))")
# flatten into a single line
NPM_VERSIONS_FLATTENED=$(echo $NPM_VERSIONS_FILTERED | awk '{print}' ORS=' ')
# sort versions according to semver, take highest (last)
LAST_NPM_VERSION="$(semver -p $(echo $NPM_VERSIONS_FLATTENED) | tail -n1 || true)"
# increment prerelease part of the version
PRERELEASE_NPM_VERSION="$(semver --increment prerelease --preid "$SANITIZED_BRANCH" "${LAST_NPM_VERSION}" || true)"
# take local version
LOCAL_VERSION="$(cat package.json | jq -r .version)"
# set prerelease part on local version
LOCAL_PRERELEASE_VERSION="$(semver --increment prerelease --preid "$SANITIZED_BRANCH" "${LOCAL_VERSION}-0")" # added '-0' here to avoid semver erroneously increment patch octet. Any suffix works, '-0' is chosen deliberately.
# take the highest version
MAX_VERSION="$(semver "$LOCAL_PRERELEASE_VERSION" "$PRERELEASE_NPM_VERSION" | tail -n1)"
# save info to env
echo "FINAL_VERSION=$MAX_VERSION" | tee -a $GITHUB_ENV
echo "PKG_NAME=$PKG_NAME" | tee -a $GITHUB_ENV
echo "PKG_FILE=vscode-highlight/${PKG_NAME}-${FINAL_VERSION}.tgz" | tee -a $GITHUB_ENV
### Set version
- name: Set version to ${{ env.FINAL_VERSION }}
run: |
cd vscode-highlight
yarn version --new-version ${{ env.FINAL_VERSION }} --no-git-tag-version
### Pack npm package
- uses: actions/setup-node@v1
with:
node-version: "15"
registry-url: "https://registry.npmjs.org"
- run: |
cd vscode-highlight
npm pack
### Create a pre-release
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.FINAL_VERSION }}
release_name: VSCode syntax highlighting plugin ${{ env.FINAL_VERSION }}
files: |
${{ env.PKG_FILE }}
body: |
Version: ${{ env.FINAL_VERSION }}
draft: false
prerelease: false

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
node_modules
*.vsix
*.tgz
.vscode-test
server/out
client/out
integration-tests/out
integration-tests/test-workspace/fluenceProject
!integration-tests/test-workspace/fluenceProject/src/aqua/test.aqua

8
.prettierrc.js Normal file
View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

6
.vscode-test.js Normal file
View File

@ -0,0 +1,6 @@
const { defineConfig } = require('@vscode/test-cli');
module.exports = defineConfig({
workspaceFolder: './integration-tests/test-workspace/',
files: 'integration-tests/out/**/*.test.js',
});

View File

@ -3,15 +3,13 @@
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"version": "0.2.0",
"configurations": [
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
]
"args": ["--extensionDevelopmentPath=${workspaceFolder}"]
}
]
}
}

View File

@ -1,4 +1,6 @@
.vscode/**
.vscode-test/**
.gitignore
vsc-extension-quickstart.md
.github
integration-tests
**/src/test

View File

@ -6,4 +6,4 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
## [Unreleased]
- Initial release
- Initial release

13
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,13 @@
## Contribute Code
You are welcome to contribute to Fluence!
Things you need to know:
1. You need to **agree to the [Contributor License Agreement](https://gist.github.com/fluencelabs-org/3f4cbb3cc14c1c0fb9ad99d8f7316ed7) (CLA)**. This is a common practice in all major Open Source projects. At the current moment, we are unable to accept contributions made on behalf of a company. Only individual contributions will be accepted.
2. **Not all proposed contributions can be accepted**. Some features may, e.g., just fit a third-party add-on better. The contribution must fit the overall direction of Fluence and really improve it. The more effort you invest, the better you should clarify in advance whether the contribution fits: the best way would be to just open an issue to discuss the contribution you plan to make.
### Contributor License Agreement
When you contribute, you have to be aware that your contribution is covered by **[Apache License 2.0](./LICENSE)**, but might relicensed under few other software licenses mentioned in the **Contributor License Agreement**. In particular, you need to agree to the Contributor License Agreement. If you agree to its content, you simply have to click on the link posted by the CLA assistant as a comment to the pull request. Click it to check the CLA, then accept it on the following screen if you agree to it. The CLA assistant will save this decision for upcoming contributions and will notify you if there is any change to the CLA in the meantime.

201
LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,3 +1,53 @@
# Collection of tools for aqua language
# Aqua Syntax Highlighting
The tool enables syntax highlighting for [Aqua](https://github.com/fluencelabs/aqua) programming language, compilation on file changes, and go-to definition in Visual Studio.
## Installation and Usage
Installation is pretty simple:
1. Install [the extension](https://marketplace.visualstudio.com/items?itemName=FluenceLabs.aqua).
2. Configure colors for Aqua-specific tokens if needed (see below).
Add the following lines to the [`settings.json`](https://code.visualstudio.com/docs/getstarted/settings) file. Feel free to choose colors according to your favorite theme. In the example below, services will be highlighted as green and all keywords that affect the topology will be highlighted as red.
```json
"editor.tokenColorCustomizations": {
"textMateRules": [
{
"scope": "keyword.topology.aqua",
"settings": {
"foreground": "#FF0000",
}
},
{
"scope": "support.service.aqua",
"settings": {
"foreground": "#00FF00",
}
}
]
}
```
More details can be found [here](vsc-extension-quickstart.md).
NOTE: if you're going to change pattern names, check out the naming rules in [TextMate Grammar doc](https://macromates.com/manual/en/language_grammars). You have to use the predefined pattern naming scheme, or the syntax won't be highlighted.
## Support
Please, file an [issue](https://github.com/fluencelabs/aqua-vscode/issues) if you find a bug. You can also contact us at [Discord](https://discord.com/invite/5qSnPZKh7u) or [Telegram](https://t.me/fluence_project). We will do our best to resolve the issue ASAP.
## Contributing
Any interested person is welcome to contribute to the project. Please, make sure you read and follow some basic [rules](./CONTRIBUTING.md).
## License
All software code is copyright (c) Fluence Labs, Inc. under the [Apache-2.0](./LICENSE) license.
TBD

195
client/package-lock.json generated Normal file
View File

@ -0,0 +1,195 @@
{
"name": "aqua-ls-client",
"version": "0.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "aqua-ls-client",
"version": "0.0.1",
"dependencies": {
"vscode-languageclient": "9.0.1"
},
"devDependencies": {
"@types/vscode": "1.94.0"
},
"engines": {
"vscode": "1.94.0"
}
},
"node_modules/@types/vscode": {
"version": "1.94.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.94.0.tgz",
"integrity": "sha512-UyQOIUT0pb14XSqJskYnRwD2aG0QrPVefIfrW1djR+/J4KeFQ0i1+hjZoaAmeNf3Z2jleK+R2hv+EboG/m8ruw==",
"dev": true
},
"node_modules/balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/vscode-jsonrpc": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
"integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/vscode-languageclient": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz",
"integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==",
"dependencies": {
"minimatch": "^5.1.0",
"semver": "^7.3.7",
"vscode-languageserver-protocol": "3.17.5"
},
"engines": {
"vscode": "^1.82.0"
}
},
"node_modules/vscode-languageserver-protocol": {
"version": "3.17.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
"integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
"dependencies": {
"vscode-jsonrpc": "8.2.0",
"vscode-languageserver-types": "3.17.5"
}
},
"node_modules/vscode-languageserver-types": {
"version": "3.17.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
"integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
},
"dependencies": {
"@types/vscode": {
"version": "1.94.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.94.0.tgz",
"integrity": "sha512-UyQOIUT0pb14XSqJskYnRwD2aG0QrPVefIfrW1djR+/J4KeFQ0i1+hjZoaAmeNf3Z2jleK+R2hv+EboG/m8ruw==",
"dev": true
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"requires": {
"balanced-match": "^1.0.0"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"requires": {
"brace-expansion": "^2.0.1"
}
},
"semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"vscode-jsonrpc": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
"integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="
},
"vscode-languageclient": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz",
"integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==",
"requires": {
"minimatch": "^5.1.0",
"semver": "^7.3.7",
"vscode-languageserver-protocol": "3.17.5"
}
},
"vscode-languageserver-protocol": {
"version": "3.17.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
"integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
"requires": {
"vscode-jsonrpc": "8.2.0",
"vscode-languageserver-types": "3.17.5"
}
},
"vscode-languageserver-types": {
"version": "3.17.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
"integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}

20
client/package.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "aqua-ls-client",
"description": "VSCode part of an aqua language server",
"author": "Fluence Labs",
"version": "0.0.1",
"publisher": "vscode",
"repository": {
"type": "git",
"url": "https://github.com/fluencelabs/aqua"
},
"engines": {
"vscode": "1.94.0"
},
"dependencies": {
"vscode-languageclient": "9.0.1"
},
"devDependencies": {
"@types/vscode": "1.94.0"
}
}

47
client/src/extension.ts Normal file
View File

@ -0,0 +1,47 @@
import * as path from 'path';
import type { ExtensionContext } from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient/node';
let client: LanguageClient;
export function activate(context: ExtensionContext) {
// The server is implemented in node
const serverModule = context.asAbsolutePath(path.join('server', 'out', 'server.js'));
// The debug options for the server
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
const debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
// If the extension is launched in debug mode then the debug server options are used
// Otherwise the run options are used
const serverOptions: ServerOptions = {
run: {
module: serverModule,
transport: TransportKind.ipc,
},
debug: {
module: serverModule,
transport: TransportKind.ipc,
options: debugOptions,
},
};
// Options to control the language client
const clientOptions: LanguageClientOptions = {
// Register the server for aqua source files
documentSelector: [{ pattern: '**/*.aqua' }],
};
// Create the language client and start the client.
client = new LanguageClient('aqua-language-server', 'Aqua Language Server', serverOptions, clientOptions);
// Start the client. This will also launch the server
client.start();
}
export function deactivate(): Thenable<void> | undefined {
if (!client) {
return undefined;
}
return client.stop();
}

12
client/tsconfig.json Normal file
View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es2020",
"outDir": "out",
"rootDir": "src",
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules"],
"extends": "@tsconfig/node16-strictest/tsconfig.json"
}

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -ex
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd "$SCRIPT_DIR/test-workspace"
# Install deps for npm package
npm i -C npmPackage/
# Prepare fluence project
fluence init -t minimal fluenceProject --no-input
cd fluenceProject
fluence dep i

View File

@ -0,0 +1,108 @@
import * as assert from 'assert';
import * as path from 'path';
import * as vscode from 'vscode';
function delay(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function waitFor(cond: () => boolean, timeout: number): Promise<boolean> {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
if (cond()) {
return true;
}
await delay(100);
}
return false;
}
suite('Extension Test Suite', () => {
async function waitForExtensionActivation(timeout: number): Promise<void> {
const activated = waitFor(() => {
return (
vscode.extensions.all.find((extension) => {
return extension.isActive && extension.id === 'FluenceLabs.aqua';
}) !== undefined
);
}, timeout);
assert.ok(activated, `Aqua extension was not activated after ${timeout}ms`);
}
async function openDocument(relPath: string): Promise<vscode.TextDocument> {
assert.ok(vscode.workspace.workspaceFolders?.length === 1, 'Test workspace should contain one folder');
const rootPath = vscode.workspace.workspaceFolders[0]!.uri.fsPath;
const filePath = path.join(rootPath, relPath);
const fileUri = vscode.Uri.file(filePath);
const document = await vscode.workspace.openTextDocument(fileUri);
await waitForExtensionActivation(10000);
return document;
}
async function getDiagnostics(uri: vscode.Uri, timeout: number): Promise<vscode.Diagnostic[]> {
let diagnostics: vscode.Diagnostic[] = [];
const got = await waitFor(() => {
diagnostics = vscode.languages.getDiagnostics(uri);
return diagnostics.length > 0;
}, timeout);
assert.ok(got, `No diagnostics provided for ${uri.toString()} in ${timeout}ms`);
return diagnostics;
}
test('Semantic errors in single file', async () => {
const document = await openDocument('singleFile/file.aqua');
const diagnostics = await getDiagnostics(document.uri, 10000);
assert.ok(
diagnostics.find((diagnostic) => {
return (
diagnostic.severity === vscode.DiagnosticSeverity.Error &&
diagnostic.message.includes('Wrong value type')
);
}),
'No error diagnostics provided',
);
}).timeout(10000);
test('Semantic errors in npm package', async () => {
const document = await openDocument('npmPackage/main.aqua');
const diagnostics = await getDiagnostics(document.uri, 10000);
assert.ok(
diagnostics.find((diagnostic) => {
return (
diagnostic.severity === vscode.DiagnosticSeverity.Error &&
diagnostic.message.includes('Wrong value type')
);
}),
'No error diagnostics provided',
);
}).timeout(10000);
test('Semantic errors in fluence project', async () => {
const document = await openDocument('fluenceProject/src/aqua/test.aqua');
const diagnostics = await getDiagnostics(document.uri, 10000);
assert.ok(
diagnostics.find((diagnostic) => {
return (
diagnostic.severity === vscode.DiagnosticSeverity.Error &&
diagnostic.message.includes('Wrong value type')
);
}),
'No error diagnostics provided',
);
}).timeout(10000);
});

View File

@ -0,0 +1,7 @@
aqua Test declares *
use "@fluencelabs/aqua-lib/builtin.aqua" as Builtin
func test() -> i64:
res <- Builtin.Op.concat_strings("a", "b")
<- res

View File

@ -0,0 +1,7 @@
aqua Main declares *
use "@fluencelabs/aqua-lib/builtin.aqua" as Builtin
func main() -> i64:
res <- Builtin.Op.concat_strings("a", "b")
<- res

View File

@ -0,0 +1,22 @@
{
"name": "Test Aqua NPM Package",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "Test Aqua NPM Package",
"version": "1.0.0",
"license": "Apache-2.0",
"dependencies": {
"@fluencelabs/aqua-lib": "0.12.1"
}
},
"node_modules/@fluencelabs/aqua-lib": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/@fluencelabs/aqua-lib/-/aqua-lib-0.12.1.tgz",
"integrity": "sha512-iqCoBlsc7Zr9eqFg2CBKsUUgu44viBLnUkP0fhz8vsYYzNi54/zBEpi8Vtr7JPZwPsH/ee09FSstPf6aGKiERw==",
"license": "MIT"
}
}
}

View File

@ -0,0 +1,12 @@
{
"name": "Test Aqua NPM Package",
"version": "1.0.0",
"files": [
"main.aqua"
],
"author": "Fluence Labs",
"license": "Apache-2.0",
"dependencies": {
"@fluencelabs/aqua-lib": "0.12.1"
}
}

View File

@ -0,0 +1,4 @@
aqua Test
func test() -> string:
<- 42

View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "ES5",
"outDir": "out",
"rootDir": "src",
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules"],
"extends": "@tsconfig/node16-strictest/tsconfig.json"
}

View File

@ -1,6 +1,6 @@
{
"comments": {
"lineComment": "--",
"lineComment": ";"
},
"brackets": [
["[", "]"],
@ -10,10 +10,12 @@
["[", "]"],
["(", ")"],
["\"", "\""],
["%", "%"]
],
"surroundingPairs": [
["[", "]"],
["(", ")"],
["\"", "\""],
["%", "%"]
]
}
}

View File

@ -0,0 +1,23 @@
{
"comments": {
"lineComment": "--"
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["%", "%"]
],
"surroundingPairs": [
["[", "]"],
["(", ")"],
["\"", "\""],
["%", "%"]
]
}

5040
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

157
package.json Normal file
View File

@ -0,0 +1,157 @@
{
"name": "aqua",
"displayName": "Aqua",
"description": "Aqua language support powered by the Aqua Language Server",
"author": "Fluence Labs",
"version": "1.1.0",
"publisher": "FluenceLabs",
"icon": "icon.png",
"repository": {
"type": "git",
"url": "https://github.com/fluencelabs/aqua"
},
"categories": [
"Programming Languages"
],
"keywords": [
"aqua vscode extension"
],
"engines": {
"vscode": "1.94.0"
},
"activationEvents": [
"onLanguage:aqua"
],
"main": "./client/out/extension",
"contributes": {
"languages": [
{
"id": "aqua",
"aliases": [
"aqua"
],
"extensions": [
".aqua"
],
"configuration": "./language-configurations/aqua.json"
},
{
"id": "air",
"aliases": [
"AIR"
],
"extensions": [
".air"
],
"configuration": "./language-configurations/air.json"
}
],
"grammars": [
{
"language": "aqua",
"scopeName": "source.aqua",
"path": "./syntaxes/aqua.tmLanguage.json"
},
{
"language": "air",
"scopeName": "source.air",
"path": "./syntaxes/air.tmLanguage.json"
}
],
"configuration": {
"type": "object",
"title": "Aqua",
"properties": {
"aquaSettings.imports": {
"definitions": {
"legacyImports": {
"description": "Legacy format of imports - just an array of paths",
"type": "array",
"items": {
"type": "string"
}
},
"structuredImports": {
"description": "Structured format of imports - dict of settings for path prefixes",
"type": "object",
"additionalProperties": {
"description": "Settings for path prefix - dict of locations for import prefixes",
"type": "object",
"additionalProperties": {
"description": "Location for import prefix",
"type": [
"string",
"array"
],
"items": {
"type": "string"
}
}
}
}
},
"scope": "resource",
"type": [
"object",
"array"
],
"if": {
"type": "object"
},
"then": {
"$ref": "#/definitions/structuredImports"
},
"else": {
"$ref": "#/definitions/legacyImports"
},
"default": {},
"description": "Adds imports for aqua file or project"
},
"aquaSettings.fluencePath": {
"scope": "resource",
"type": [
"string",
"null"
],
"default": null,
"description": "Path to fluence CLI executable"
},
"aquaSettings.fluenceCallDelay": {
"scope": "resource",
"type": "number",
"default": 5000,
"description": "Minimal delay (ms) between calls to fluence CLI (for one file)"
}
}
}
},
"scripts": {
"before-tests": "bash integration-tests/before-tests.sh",
"test": "npm run compile && vscode-test",
"test:unit": "npm run test -C server",
"vscode:prepublish": "npm run compile",
"compile": "tsc -b",
"watch": "tsc -b -w",
"lint": "eslint ./client/src ./server/src --ext .ts,.tsx",
"postinstall": "cd client && npm install && cd ../server && npm install && cd .."
},
"devDependencies": {
"@tsconfig/node16-strictest": "1.0.4",
"@types/mocha": "9.1.1",
"@types/node": "14.18.63",
"@typescript-eslint/eslint-plugin": "7.9.0",
"@typescript-eslint/parser": "7.9.0",
"@vscode/test-cli": "0.0.9",
"@vscode/test-electron": "2.4.1",
"@types/vscode": "1.94.0",
"eslint": "8.57.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-n": "15.7.0",
"eslint-plugin-promise": "6.1.1",
"mocha": "9.2.2",
"prettier": "2.6.2",
"typescript": "4.9.5"
}
}

8
renovate.json Normal file
View File

@ -0,0 +1,8 @@
{
"extends": [
"github>fluencelabs/renovate",
"github>fluencelabs/renovate:npm"
],
"ignorePaths": ["api/aqua-api-example/**"],
"enabledManagers": ["npm"]
}

3
server/.mocharc.cjs Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
spec: 'src/test/**/*.test.ts',
};

2221
server/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

28
server/package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "aqua-ls-server",
"description": "Implementation of an aqua language server in node.",
"version": "0.0.1",
"author": "Fluence Labs",
"engines": {
"node": "22"
},
"repository": {
"type": "git",
"url": "https://github.com/fluencelabs/aqua"
},
"dependencies": {
"@fluencelabs/aqua-language-server-api": "0.14.11",
"global-dirs": "4.0.0",
"vscode-languageserver": "9.0.1",
"vscode-languageserver-textdocument": "1.0.12",
"vscode-uri": "3.0.8"
},
"devDependencies": {
"@types/mocha": "10.0.6",
"ts-mocha": "10.0.0"
},
"scripts": {
"test": "ts-mocha",
"get-root": "npm root --global"
}
}

56
server/src/cli.ts Normal file
View File

@ -0,0 +1,56 @@
import { exec } from 'child_process';
import { dirname } from 'path';
import type { Imports } from './imports';
import { normalizeImports } from './imports';
export class FluenceCli {
readonly cliPath: string;
/**
* @param cliPath Path to `fluence` executable.
* Defaults to `fluence` (i.e. it should be in PATH).
*/
constructor(cliPath?: string) {
this.cliPath = cliPath || 'fluence';
}
/**
* Returns output of `fluence aqua imports`
* in dir of @param filePath.
*/
async imports(filePath: string): Promise<Imports> {
const cwd = dirname(filePath);
const result = await this.runJson(['aqua', 'imports'], cwd);
try {
return normalizeImports(result);
} catch (e) {
if (e instanceof Error) {
throw new Error(`Error converting imports from fluence: ${e.message}`);
} else {
throw e;
}
}
}
/**
* Runs `fluence` with given arguments and returns its stdout as JSON.
*/
private async runJson(args: string[], cwd?: string | undefined): Promise<JSON> {
const cmd = `${this.cliPath} ${args.join(' ')}`;
return new Promise((resolve, reject) => {
exec(cmd, { cwd }, (err, stdout, _) => {
if (err) {
reject(err);
} else
try {
const result = JSON.parse(stdout);
resolve(result);
} catch (e) {
reject(e);
}
});
});
}
}

68
server/src/imports.ts Normal file
View File

@ -0,0 +1,68 @@
export type Imports = Record<string, Record<string, string[]>>;
// Normalize imports to the new format
// Legacy format of an array of paths is converted to the new format
// Empty imports are converted to an empty object
export function normalizeImports(imports: unknown): Imports {
// Empty imports
if (imports === undefined || imports === null) {
return {};
}
// Legacy imports - array of paths
if (Array.isArray(imports) && imports.every((i) => typeof i === 'string')) {
return {
'/': {
'': imports as string[],
},
};
}
const isStringArray = (v: unknown): v is string[] => {
return Array.isArray(v) && v.every((i) => typeof i === 'string');
};
// New imports - object of objects of paths or arrays of paths
// Inner single paths are normalized to arrays
if (typeof imports === 'object') {
for (const info of Object.values(imports)) {
if (typeof info !== 'object') {
throw new Error(`Invalid imports: ${JSON.stringify(imports)}`);
}
for (const [importPrefix, locations] of Object.entries(info)) {
if (typeof locations === 'string') {
info[importPrefix] = [locations];
} else if (!isStringArray(locations)) {
throw new Error(`Invalid imports: ${JSON.stringify(imports)}`);
}
}
}
return imports as Imports;
}
throw new Error(`Invalid imports: ${JSON.stringify(imports)}`);
}
// Deep merge two import settings, overriding the first with the second
export function uniteImports(pre: Imports, post: Imports): Imports {
const result: Imports = { ...pre };
for (const [pathPrefix, info] of Object.entries(post)) {
const resultInfo = result[pathPrefix];
if (resultInfo) {
for (const [importPrefix, paths] of Object.entries(info)) {
const importInfo = resultInfo[importPrefix];
if (importInfo) {
resultInfo[importPrefix] = [...importInfo, ...paths];
} else {
resultInfo[importPrefix] = paths;
}
}
} else {
result[pathPrefix] = info;
}
}
return result;
}

74
server/src/info.ts Normal file
View File

@ -0,0 +1,74 @@
import type { DocumentUri, Position } from 'vscode-languageserver';
import type { TokenInfo, TokenLink, TokenLocation } from '@fluencelabs/aqua-language-server-api/aqua-lsp-api';
import { locInLoc, posInToken } from './utils';
/**
* Class that incapsulates information
* about tokens inside a document
*/
export class DocumentInfo {
private links: TokenLink[];
private tokens: TokenInfo[];
private path: string;
constructor(path: string, links: TokenLink[], tokens: TokenInfo[]) {
this.path = path;
this.links = links;
this.tokens = tokens;
}
/**
* Find token info at position
* @param pos position to check
* @returns token info if found
*/
infoAt(pos: Position): TokenInfo | undefined {
const info = this.tokens.find((token) => posInToken(this.path, pos, token.location));
if (info) {
return info;
}
// Fallback: if token info is not found
// try to find its definition and its info
const def = this.defAt(pos);
if (def) {
return this.tokens.find((token) => locInLoc(def, token.location));
}
return undefined;
}
/**
* Find definition location at position
* @param pos Position to check
* @returns Definition location if found
*/
defAt(pos: Position): TokenLocation | undefined {
return this.links.find((link) => posInToken(this.path, pos, link.current))?.definition;
}
}
/**
* Info manager for documents
*/
export class InfoManager {
private documents: Map<DocumentUri, DocumentInfo> = new Map();
updateDocumentInfo(uri: DocumentUri, info: DocumentInfo) {
this.documents.set(uri, info);
}
infoAt(uri: DocumentUri, pos: Position): TokenInfo | undefined {
return this.documents.get(uri)?.infoAt(pos);
}
defAt(uri: DocumentUri, pos: Position): TokenLocation | undefined {
return this.documents.get(uri)?.defAt(pos);
}
removeDocumentInfo(uri: DocumentUri) {
this.documents.delete(uri);
}
}

165
server/src/server.ts Normal file
View File

@ -0,0 +1,165 @@
import {
createConnection,
DiagnosticSeverity,
DidChangeConfigurationNotification,
InitializeParams,
InitializeResult,
ProposedFeatures,
TextDocuments,
TextDocumentSyncKind,
} from 'vscode-languageserver/node';
import type { WorkspaceFolder } from 'vscode-languageserver-protocol';
import { TextDocument } from 'vscode-languageserver-textdocument';
import type { DefinitionParams, Hover, HoverParams, MarkupContent } from 'vscode-languageserver';
import { MarkupKind } from 'vscode-languageserver';
import { compileAqua } from './validation';
import { FluenceCli } from './cli';
import { Settings, SettingsManager } from './settings';
import { InfoManager } from './info';
import { tokenToLocation } from './utils';
import { typeToString } from './types';
// Create a connection to the server, using Node's IPC as a transport.
// Also include all preview / proposed LSP features.
const connection = createConnection(ProposedFeatures.all);
// Create a simple text document manager.
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
let hasConfigurationCapability = false;
let hasWorkspaceFolderCapability = false;
let folders: WorkspaceFolder[] = [];
function createSettingsManager(cliPath?: string, cliCallDelay?: number, defaultSettings?: Settings): SettingsManager {
const cli = new FluenceCli(cliPath);
const configuration = hasConfigurationCapability ? connection.workspace : undefined;
return new SettingsManager({ cli, cliCallDelay, defaultSettings }, configuration);
}
let documentSettings = createSettingsManager();
const documentInfos = new InfoManager();
connection.onDidChangeConfiguration((change) => {
connection.console.log(`onDidChangeConfiguration event ${JSON.stringify(change)}`);
documentSettings = createSettingsManager(
change.settings.aquaSettings.fluencePath,
change.settings.aquaSettings.fluenceCallDelay,
change.settings.aquaSettings,
);
// Revalidate all open text documents
documents.all().forEach(validateDocument);
});
// Only keep settings for open documents
documents.onDidClose((e) => {
documentSettings.removeDocumentSettings(e.document.uri);
documentInfos.removeDocumentInfo(e.document.uri);
});
connection.onInitialize((params: InitializeParams) => {
connection.console.log('onInitialize event');
const capabilities = params.capabilities;
hasConfigurationCapability = !!(capabilities.workspace && !!capabilities.workspace.configuration);
hasWorkspaceFolderCapability = !!(capabilities.workspace && !!capabilities.workspace.workspaceFolders);
if (params.workspaceFolders) {
folders = params.workspaceFolders;
}
const result: InitializeResult = {
capabilities: {
textDocumentSync: TextDocumentSyncKind.Full,
definitionProvider: true,
hoverProvider: true,
},
};
if (hasWorkspaceFolderCapability) {
result.capabilities.workspace = {
workspaceFolders: {
supported: true,
},
};
}
return result;
});
connection.onInitialized(async () => {
connection.console.log('onInitialized event');
if (hasConfigurationCapability) {
connection.client.register(DidChangeConfigurationNotification.type, {
section: 'aquaSettings',
});
}
if (hasWorkspaceFolderCapability) {
connection.workspace.onDidChangeWorkspaceFolders((event) => {
folders = folders.concat(event.added);
folders = folders.filter((f) => !event.removed.includes(f));
});
}
});
documents.onDidSave(async (change) => {
connection.console.log('onDidSave event');
await validateDocument(change.document);
});
documents.onDidOpen(async (change) => {
connection.console.log('onDidOpen event');
await validateDocument(change.document);
});
connection.onHover(({ textDocument, position }: HoverParams): Hover | null => {
connection.console.log('onHover event');
const info = documentInfos.infoAt(textDocument.uri, position);
if (info) {
const typeStr = typeToString(info.type);
const content: MarkupContent = { kind: MarkupKind.PlainText, value: typeStr };
return { contents: content };
}
return null;
});
connection.onDefinition(({ textDocument, position }: DefinitionParams) => {
connection.console.log('onDefinition event');
const def = documentInfos.defAt(textDocument.uri, position);
return def ? [tokenToLocation(def)] : [];
});
async function validateDocument(textDocument: TextDocument): Promise<void> {
const settings = await documentSettings.getDocumentSettings(textDocument.uri);
connection.console.log(`validateDocument ${textDocument.uri} with settings ${JSON.stringify(settings)}`);
const [diagnostics, info] = await compileAqua(settings, textDocument);
documentInfos.updateDocumentInfo(textDocument.uri, info);
// Send the computed diagnostics to VSCode.
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
// Request additional imports update if there are errors
if (diagnostics.some((d) => d.severity === DiagnosticSeverity.Error)) {
documentSettings.requestImportsUpdate(textDocument.uri);
}
}
// Make the text document manager listen on the connection
// for open, change and close text document events
documents.listen(connection);
// Listen on the connection
connection.listen();

166
server/src/settings.ts Normal file
View File

@ -0,0 +1,166 @@
import type { Configuration } from 'vscode-languageserver/lib/common/configuration';
import { URI } from 'vscode-uri';
import type { Imports } from './imports';
import { normalizeImports, uniteImports } from './imports';
import type { FluenceCli } from './cli';
export interface Settings {
imports: Imports;
}
/**
* Document info stored in `SettingsManager` cache
*/
class DocumentSettingsInfo {
/* Settings from configuration (or default) */
private settings: Settings;
/* Additional imports from CLI */
private imports: Imports = {};
private importsLastUpdated = 0;
private importsUpdateRequested = true;
constructor(settings: Settings) {
this.settings = settings;
}
getSettings(): Settings {
return {
...this.settings,
// Imports from settings override imports from CLI
imports: uniteImports(this.imports, this.settings.imports),
};
}
requestImportsUpdate() {
this.importsUpdateRequested = true;
}
isImportsUpdateNeeded(delay?: number): boolean {
// Update additional imports not more often than once `delay`
// and only if there is a request to update
const isUpdateReady = delay ? Date.now() - this.importsLastUpdated > delay : true;
return isUpdateReady && this.importsUpdateRequested;
}
updateImports(imports: Imports) {
this.imports = imports;
this.importsLastUpdated = Date.now();
this.importsUpdateRequested = false;
}
}
export interface SettingsManagerConfig {
cli: FluenceCli;
cliCallDelay?: number | undefined;
defaultSettings?: Settings | undefined;
}
/**
* Compilation settings manager for documents
*/
export class SettingsManager {
private readonly defaultSettings: Settings = {
imports: {},
};
private documents: Map<string, DocumentSettingsInfo> = new Map();
private readonly cli: FluenceCli;
private readonly cliCallDelay: number | undefined;
private readonly configuration: Configuration | undefined;
constructor(config: SettingsManagerConfig, configuration?: Configuration) {
this.cli = config.cli;
this.configuration = configuration;
if (config.defaultSettings) {
this.defaultSettings = config.defaultSettings;
}
if (config.cliCallDelay) {
this.cliCallDelay = config.cliCallDelay;
}
}
/**
* Get settings for document or global settings if document settings are not available
*
* @param uri Document uri
* @returns Settings for the document
*/
async getDocumentSettings(uri: string): Promise<Settings> {
const info = await this.updateDocument(uri);
return info.getSettings();
}
/**
* Remove document settings from cache
*
* @param uri Document uri
*/
removeDocumentSettings(uri: string): void {
this.documents.delete(uri);
}
/**
* Set flag to request additional imports update.
* This flag will be reset after first successful update.
* NOTE: Imports are updated no more than once in 5 seconds.
*/
requestImportsUpdate(uri: string) {
this.documents.get(uri)?.requestImportsUpdate();
}
/**
* Update document info in cache:
* 1. Get settings from configuration (or default)
* 2. Get additional imports from CLI (if needed)
* @param uri document uri
* @returns updated document info
*/
private async updateDocument(uri: string): Promise<DocumentSettingsInfo> {
let info = this.documents.get(uri);
if (!info) {
const settings = await this.getDocumentConfiguration(uri);
info = new DocumentSettingsInfo(settings);
}
if (info.isImportsUpdateNeeded(this.cliCallDelay)) {
const path = URI.parse(uri).fsPath;
try {
const imports = await this.cli.imports(path);
info.updateImports(imports);
} catch (e) {
// try-catch is needed, because server will crash if there will be no Fluence CLI installed
console.error('Cannot update imports: ', e);
}
}
this.documents.set(uri, info);
return info;
}
private async getDocumentConfiguration(uri: string): Promise<Settings> {
if (this.configuration) {
// TODO: Handle errors
const settings = await this.configuration.getConfiguration({
scopeUri: uri,
section: 'aquaSettings',
});
if (settings) {
try {
settings.imports = normalizeImports(settings.imports);
} catch (e) {
// TODO: Maybe show some notification to user?
// Don't know how to handle it better.
console.error('Cannot normalize imports from settings: ', e);
settings.imports = {};
}
return settings;
}
}
return this.defaultSettings;
}
}

View File

@ -0,0 +1,30 @@
aqua Simple
export main
func getStr() -> string:
<- "test string"
func consumeStr(str: string) -> string:
<- str
service Srv("test-srv"):
consumeStr(str: string) -> string
ability Ab:
field: string
arrow(s: string) -> string
func main() -> string:
-- Definition
testVar <- getStr()
-- Use as argument to function
newVar1 <- consumeStr(testVar)
-- Use as argument to service
newVar2 <- Srv.consumeStr(testVar)
-- Use as argument to ability creation
ab = Ab(field = testVar, arrow = consumeStr)
-- Use as argument to ability call
newVar3 <- ab.arrow(testVar)
-- Use in return statement
<- testVar

View File

@ -0,0 +1,109 @@
import * as assert from 'assert';
import { normalizeImports, uniteImports } from '../imports';
describe('Imports Test Suite', () => {
describe('normalizeImports', () => {
it('should normalize empty imports', async () => {
assert.deepStrictEqual(normalizeImports(undefined), {});
assert.deepStrictEqual(normalizeImports(null), {});
});
it('should normalize legacy imports', async () => {
const imports = ['a', 'b', 'c'];
const normalized = {
'/': {
'': imports,
},
};
assert.deepStrictEqual(normalizeImports(imports), normalized);
});
it('should normalize imports', async () => {
const imports = {
'/': {
'': ['a', 'b', 'c'],
},
};
assert.deepStrictEqual(normalizeImports(imports), imports);
});
it('should normalize imports with single paths', async () => {
const imports = {
'/': {
'': 'a',
},
};
const normalized = {
'/': {
'': ['a'],
},
};
assert.deepStrictEqual(normalizeImports(imports), normalized);
});
it('should throw on invalid imports', async () => {
assert.throws(() => normalizeImports(123));
assert.throws(() => normalizeImports(['a', 123]));
assert.throws(() => normalizeImports({ a: 123 }));
assert.throws(() => normalizeImports({ a: { b: 123 } }));
assert.throws(() => normalizeImports({ a: { b: ['a', 123] } }));
});
});
describe('uniteImports', () => {
it('should unite distinct imports', async () => {
const lhs = {
'/left': {
'': ['l'],
},
};
const rhs = {
'/right': {
'': ['r'],
},
};
const result = { ...lhs, ...rhs };
assert.deepStrictEqual(uniteImports(lhs, rhs), result);
});
it('should unite path-intersecting imports', async () => {
const lhs = {
'/': {
left: ['l'],
},
};
const rhs = {
'/': {
right: ['r'],
},
};
const result = {
'/': {
left: ['l'],
right: ['r'],
},
};
assert.deepStrictEqual(uniteImports(lhs, rhs), result);
});
it('should unite path-prefix-intersecting imports', async () => {
const lhs = {
'/': {
'': ['l'],
},
};
const rhs = {
'/': {
'': ['r'],
},
};
const result = {
'/': {
'': ['l', 'r'],
},
};
assert.deepStrictEqual(uniteImports(lhs, rhs), result);
});
});
});

View File

@ -0,0 +1,109 @@
import * as assert from 'assert';
import * as path from 'path';
import * as fs from 'fs/promises';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { Location, Position, Range } from 'vscode-languageserver';
import { compileAqua } from '../validation';
import { DocumentInfo } from '../info';
import { pathToUri, tokenToLocation } from '../utils';
import { ScalarType } from '@fluencelabs/aqua-language-server-api/aqua-lsp-api';
/**
* Load document from file, compile it and return info
* @param relPath path relative to test folder
* @returns document, document info after compilation
*/
async function openDocument(relPath: string): Promise<[TextDocument, DocumentInfo]> {
const absPath = path.join(__dirname, relPath);
const content = await fs.readFile(absPath, 'utf-8');
const document = TextDocument.create(pathToUri(absPath), 'aqua', 0, content);
// Compile without imports
const [_, info] = await compileAqua({ imports: {} }, document);
return [document, info];
}
/**
* Find all locations of a variable in a document
* @param name variable name
* @param doc text document to search in
* @returns locations of variable in document
*/
function locationsOf(name: string, doc: TextDocument): Location[] {
const regex = new RegExp(`(?<=\\b)${name}(?=\\b)`, 'g');
return [...doc.getText().matchAll(regex)].map((match) => {
// `index` will always be presented, see
// https://github.com/microsoft/TypeScript/issues/36788
const index = match.index as number;
return {
uri: doc.uri,
range: {
start: doc.positionAt(index),
end: doc.positionAt(index + match[0].length),
},
};
});
}
/**
* Generate all positions in a range
* @param doc text document
* @param range range
* @returns positions in range
*/
function genRange(doc: TextDocument, range: Range): Position[] {
const positions: Position[] = [];
const begOff = doc.offsetAt(range.start);
const endOff = doc.offsetAt(range.end);
for (let off = begOff; off < endOff; off++) {
positions.push(doc.positionAt(off));
}
return positions;
}
describe('DocumentInfo Test Suite', () => {
describe('infoAt', () => {
it('should return type information on each occurrence (simple)', async () => {
const [document, docInfo] = await openDocument('aqua/simple.aqua');
const locations = locationsOf('testVar', document);
assert.strictEqual(locations.length, 6, 'Not all occurrences found');
for (const loc of locations) {
for (const pos of genRange(document, loc.range)) {
const info = docInfo.infoAt(pos);
assert.ok(info, 'Info not found');
const type = info.type as ScalarType;
assert.strictEqual(type.tag, 'scalar', 'Wrong type tag');
assert.strictEqual(type.name, 'string', 'Wrong type');
}
}
});
});
describe('defAt', () => {
it('should return definition location on each occurrence (simple)', async () => {
const [document, docInfo] = await openDocument('aqua/simple.aqua');
const locations = locationsOf('testVar', document);
assert.strictEqual(locations.length, 6, 'Not all occurrences found');
const definition = locations[0];
for (const loc of locations.slice(1)) {
for (const pos of genRange(document, loc.range)) {
const def = docInfo.defAt(pos);
assert.ok(def, 'Definition not found');
assert.deepStrictEqual(tokenToLocation(def), definition, 'Wrong definition location');
}
}
});
});
});

81
server/src/types.ts Normal file
View File

@ -0,0 +1,81 @@
import type {
AbilityType,
ArrayType,
CanonStreamType,
OptionType,
ServiceType,
StreamMapType,
StreamType,
StructType,
Type,
} from '@fluencelabs/aqua-language-server-api/aqua-lsp-api';
const collectionPrefix = {
array: '[]',
stream: '*',
canon: '#',
streammap: '%',
option: '?',
};
function collectionToString(
type: ArrayType | StreamType | CanonStreamType | StreamMapType | OptionType,
depth: number,
) {
const elementType = typeToStringInner(type.element, depth);
const prefix = collectionPrefix[type.tag];
return prefix + elementType;
}
function namedToString(type: AbilityType | StructType | ServiceType, depth: number) {
let fieldsStr = Object.entries(type.fields).map(function ([name, fieldType]) {
const fieldTypeStr = typeToStringInner(fieldType, depth + 1);
return `${name}: ${fieldTypeStr}`;
});
return `${type.name}(${fieldsStr.join(', ')})`;
}
function typeToStringInner(type: Type, depth: number): string {
switch (type.tag) {
case 'nil':
return '∅';
case 'array':
case 'option':
case 'stream':
case 'streammap':
case 'canon':
return collectionToString(type, depth);
case 'struct':
case 'ability':
case 'service':
if (depth >= 1) {
return type.name;
}
return namedToString(type, depth);
case 'labeled':
const args = Object.entries(type.args).map(function ([name, argType]) {
const fieldTypeStr = typeToStringInner(argType, depth + 1);
return `${name}: ${fieldTypeStr}`;
});
return args.join(', ');
case 'unlabeled':
return type.types.map((t) => typeToStringInner(t, depth + 1)).join(', ');
case 'arrow':
const domainStr = typeToStringInner(type.domain, depth + 1);
const codomainStr = typeToStringInner(type.codomain, depth + 1);
return `func (${domainStr}) -> ${codomainStr}`;
case 'top':
return 'top';
case 'bottom':
return 'bottom';
case 'scalar':
return type.name;
default:
const _exhaustiveCheck: never = type;
return _exhaustiveCheck;
}
}
export function typeToString(type: Type): string {
return typeToStringInner(type, 0);
}

80
server/src/utils.ts Normal file
View File

@ -0,0 +1,80 @@
import url from 'url';
import type { Position } from 'vscode-languageserver-textdocument';
import type { DocumentUri, Location } from 'vscode-languageserver';
import type { TokenLocation } from '@fluencelabs/aqua-language-server-api/aqua-lsp-api';
/**
* Check if position is inside token
* @param path path to file with token
* @param position position to check
* @param token token to check
* @returns true if position is inside token
* @note this ignores token's file name
* as position does not contain such info
*/
export function posInToken(path: string, position: Position, token: TokenLocation): boolean {
return (
token.name == path &&
token.startLine <= position.line &&
token.startCol <= position.character &&
token.endLine >= position.line &&
token.endCol >= position.character
);
}
/**
* Check if if location is inside other location
* @param lhs location to check
* @param rhs enclosing location
* @returns true if rhs is enclosing lhs
*/
export function locInLoc(lhs: TokenLocation, rhs: TokenLocation): boolean {
return (
lhs.name == rhs.name &&
rhs.startLine <= lhs.startLine &&
rhs.startCol <= lhs.startCol &&
rhs.endLine >= lhs.endLine &&
rhs.endCol >= lhs.endCol
);
}
/**
* Convert URI to file path
* @param uri URI to convert
* @returns file path
*/
export function uriToPath(uri: DocumentUri) {
return url.fileURLToPath(uri);
}
/**
* Convert file path to URI
* @param path file path to convert
* @returns URI
*/
export function pathToUri(path: string) {
return url.format(url.pathToFileURL(path));
}
/**
* Convert token location to location
* @param loc token location
* @returns location
*/
export function tokenToLocation(loc: TokenLocation): Location {
return {
uri: pathToUri(loc.name),
range: {
start: {
line: loc.startLine,
character: loc.startCol,
},
end: {
line: loc.endLine,
character: loc.endCol,
},
},
};
}

107
server/src/validation.ts Normal file
View File

@ -0,0 +1,107 @@
import * as fs from 'fs';
import * as Path from 'path';
import type { TextDocument } from 'vscode-languageserver-textdocument';
import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver/node';
import { AquaLSP, ErrorInfo, TokenLink, WarningInfo } from '@fluencelabs/aqua-language-server-api/aqua-lsp-api';
import type { Settings } from './settings';
import { DocumentInfo } from './info';
import { uriToPath } from './utils';
function infoToDiagnostic(textDocument: TextDocument, info: ErrorInfo | WarningInfo): Diagnostic {
const severity = info.infoType === 'error' ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning;
const diagnostic: Diagnostic = {
severity: severity,
range: {
start: textDocument.positionAt(info.start),
end: textDocument.positionAt(info.end),
},
message: info.message,
};
if (info.location) {
const message = info.infoType === 'error' ? 'Compilation error' : 'Compilation warning';
diagnostic.relatedInformation = [
{
location: {
uri: info.location,
range: Object.assign({}, diagnostic.range),
},
message: message,
},
];
}
return diagnostic;
}
export async function compileAqua(
settings: Settings,
textDocument: TextDocument,
): Promise<[Diagnostic[], DocumentInfo]> {
const path = uriToPath(textDocument.uri);
// compile aqua and get result
const result = await AquaLSP.compile(path, settings.imports);
const diagnostics: Diagnostic[] = [];
const links: TokenLink[] = [];
const docPath = Path.parse(path);
// empty string for already resolved paths in 'importLocations'
const linksSearch = ['', docPath.dir];
result.importLocations.map(function (ti) {
// add extension for imports without extension
let importPath: string;
if (ti.path.endsWith('.aqua')) {
importPath = ti.path;
} else {
importPath = ti.path + '.aqua';
}
const path = linksSearch.map((i) => Path.join(i, importPath)).find(fs.existsSync);
if (path) {
links.push({
current: ti.current,
definition: {
name: path,
startLine: 0,
startCol: 0,
endLine: 0,
endCol: 0,
},
});
} else {
console.log(`Cannot find path for '${ti}'`)
}
});
if (result.warnings) {
// Add all warnings related to the file to Diagnostic
const warnings = result.warnings
.filter((w) => w.location == null || w.location === path)
.map((w) => infoToDiagnostic(textDocument, w));
diagnostics.push(...warnings);
}
if (result.errors) {
// Add all errors related to the file to Diagnostic
const errors = result.errors
.filter((e) => e.location == null || e.location === path)
.map((e) => infoToDiagnostic(textDocument, e));
diagnostics.push(...errors);
}
const locations = result.locations.concat(links);
const info = new DocumentInfo(path, locations, result.tokens);
return [diagnostics, info];
}

15
server/tsconfig.json Normal file
View File

@ -0,0 +1,15 @@
{
"allowJs": true,
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"strict": true,
"outDir": "out",
"rootDir": "src"
},
"include": ["src"],
"exclude": ["node_modules", "src/test"],
"extends": "@tsconfig/node16-strictest/tsconfig.json"
}

View File

@ -0,0 +1,100 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "air",
"patterns": [
{
"include": "#keywords"
},
{
"include": "#constants"
},
{
"include": "#strings"
},
{
"include": "#comments"
},
{
"include": "#variables"
},
{
"include": "#lambda"
}
],
"repository": {
"keywords": {
"patterns": [
{
"name": "keyword.instruction.air",
"match": "\\b(ap|call|canon|fold|par|next|match|mismatch|new|null|seq|xor)\\b"
}
]
},
"constants": {
"patterns": [
{
"name": "constant.language.air",
"match": "%init_peer_id%|%last_error%"
},
{
"name": "constant.numeric.air",
"match": "\\b\\d+\\b"
},
{
"name": "constant.language.boolean.air",
"match": "\\b(true|false)\\b"
}
]
},
"strings": {
"name": "string.quoted.double.air",
"begin": "\"",
"end": "\"",
"patterns": []
},
"comments": {
"name": "comment.line.air",
"begin": ";",
"end": "$"
},
"lambda": {
"//": "AIR lambdas",
"begin": "\\.\\$",
"end": "!",
"beginCaptures": {
"0": { "name": "punctuation.paren.open" }
},
"endCaptures": {
"0": { "name": "punctuation.paren.close" }
},
"name": "expression.group",
"patterns": [
{
"//": "Field accessor",
"name": "support.function.method.call",
"match": "\\.\\w+"
},
{
"//": "Array acessor",
"name": "keyword.control.other",
"match": "\\[[A-Za-z0-9\\-_\\\"]+\\]"
}
]
},
"variables": {
"patterns": [
{
"//": "Stream and canonicalized stream variables start with $ or # respectively",
"name": "variable.language.stream",
"match": "[\\$\\#][A-Za-z_\\-][A-Za-z0-9_\\-]*"
},
{
"//": "Scalar variables",
"name": "variable.other.scalar",
"match": "[A-Za-z_\\-][A-Za-z0-9_\\-]*"
}
]
}
},
"scopeName": "source.air"
}

View File

@ -0,0 +1,196 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "aqua",
"patterns": [
{
"include": "#comments"
},
{
"include": "#keywords"
},
{
"include": "#constants"
},
{
"include": "#strings"
},
{
"include": "#semantics"
},
{
"include": "#todo-keyword"
}
],
"repository": {
"keywords": {
"patterns": [
{
"name": "keyword.control.flow.aqua",
"match": "\\b(try|catch|par|if|else|otherwise|for|co|join|parseq)\\b"
},
{
"name": "keyword.control.other.aqua",
"match": "(<<-|<-|->)"
},
{
"name": "keyword.operator.math.aqua",
"match": "(\\+|-|\/|(?<=[^:]\\s*)\\*|%|\\*\\*|>=|<=|>|<)"
},
{
"name": "keyword.operator.logical.aqua",
"match": "=="
},
{
"name": "keyword.control.other.aqua",
"match": "(\\[\\]|\\*|\\?|=|\\?=)"
},
{
"name": "keyword.control.topology.aqua",
"match": "\\b(on|via)\\b"
},
{
"name": "keyword.control.declaration.aqua",
"match": "\\b(func|service|data|ability|alias|const)\\b"
},
{
"name": "keyword.operator.logical.aqua",
"match": "(\\|\\||&&|!(?=\\s*\\w))"
},
{
"name": "keyword.operator.control.aqua",
"match": "(?<=\\w\\s*)!"
},
{
"name": "keyword.control.import.aqua",
"match": "\\b(import|module|export|declares|from|as|use|aqua)\\b"
}
]
},
"constants": {
"patterns": [
{
"name": "constant.language.topology.aqua",
"match": "%init_peer_id%|%last_error%|%HOST_PEER_ID%|HOST_PEER_ID|INIT_PEER_ID"
},
{
"name": "constant.language.numeric.aqua",
"match": "\\b-?\\d+(\\.\\d*)?\\b"
},
{
"name": "constant.language.boolean.aqua",
"match": "\\b(true|false)\\b"
},
{
"name": "constant.language.option.nil.aqua",
"match": "\\bnil\\b"
}
]
},
"strings": {
"name": "string.quoted.double.aqua",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.aqua",
"match": "\\\\."
}
]
},
"comments": {
"name": "comment.line.aqua",
"begin": "--",
"end": "$",
"patterns": [{ "include": "#todo-keyword" }]
},
"todo-keyword": {
"begin": "TODO:",
"end": "$",
"name": "keyword.todo"
},
"semantics": {
"patterns": [
{
"name": "entity.name.type.primitive.aqua",
"match": "\\b(string|bool|u8|u16|u32|u64|i8|i16|i32|i64|f32|f64)\\b"
},
{
"//": "Matches type name defined with alias clause",
"name": "entity.name.type.aqua",
"match": "(?<=alias\\s*)[A-Z]\\w*(?=\\s*:)"
},
{
"//": "Matches type specifiers in declarations",
"name": "entity.name.type.specifier.aqua",
"match": "(?<=:\\s*)(?:\\[\\]|\\*|\\?)*[A-Za-z]\\w*"
},
{
"//": "Defines tokens for data definitions ('data XXX:')",
"name": "entity.name.type.data.aqua",
"match": "\\b(?<=(data)\\s+)[A-Z][A-Za-z0-9_]+(?=:)\\b"
},
{
"//": "Defines tokens for service definitions ('service YYY:')",
"name": "entity.name.type.service.aqua",
"match": "\\b(?<=(service)\\s+)[A-Z][A-Za-z0-9_]+(?=(\\(\"\\w*\"\\))?:)\\b"
},
{
"//": "Defines tokens for ability definitions ('ability YYY:')",
"name": "entity.name.type.ability.aqua",
"match": "\\b(?<=(ability)\\s+)[A-Z][A-Za-z0-9_]+(?=:)\\b"
},
{
"//": "Method name in 'Ability.field.method(args)'",
"name": "support.function.method.call.aqua",
"match": "(?<=\\.)[a-z][a-zA-Z0-9_]+(?=\\()"
},
{
"//": "Ability name in 'Ability.method(args)' or 'Ability.field'",
"name": "support.type.ability.aqua",
"match": "\\b(?<=[^\\.])[A-Za-z]\\w*(?=\\.)"
},
{
"//": "Field name in 'Ability.field.method(args)' or 'Ability.field'",
"name": "support.other.field.aqua",
"match": "(?<=\\.)(?>[A-Za-z]\\w*)\\b(?!\\s*\\()"
},
{
"//": "Matches function arguments",
"name": "variable.parameter.value.aqua",
"match": "(?<=[,\\(]\\s*)[A-Za-z]\\w*(?=\\s*:)"
},
{
"//": "Matches function ability arguments",
"name": "variable.parameter.ability.aqua",
"match": "(?<=func\\s*[A-Za-z]\\w*\\s*{\\s*(?:[A-Za-z]\\w*\\s*,\\s*)*)[A-Za-z]\\w*\\b"
},
{
"//": "Matches defined variables",
"name": "variable.other.definition.aqua",
"match": "\\b[A-Za-z]\\w*(?=\\s*(?:,\\s*[A-Za-z]\\w*)*\\s*(?:<-|=))"
},
{
"//": "Matches declared variables",
"name": "variable.other.declaration.aqua",
"match": "\\b[A-Za-z]\\w*(?=:)"
},
{
"//": "Matches function definition",
"name": "entity.name.function.aqua",
"match": "\\b(?<=func\\s*)[A-Za-z]\\w*(?=\\s*(?:\\(|\\{))"
},
{
"//": "Matches method definition, function usage or aggregate creation",
"name": "entity.name.function.usage.aqua",
"match": "\\b[A-Za-z]\\w*(?=\\s*(?:\\(|\\{))"
},
{
"//": "Matches variables anywhere",
"name": "variable.other.any.aqua",
"match": "\\b[A-Za-z]\\w*\\b"
}
]
}
},
"scopeName": "source.aqua"
}

26
tsconfig.json Normal file
View File

@ -0,0 +1,26 @@
{
"allowJs": true,
"declaration": true,
"compilerOptions": {
"module": "commonjs",
"target": "es2020",
"outDir": "out",
"rootDir": "src",
"sourceMap": true
},
"types": ["node"],
"include": [],
"exclude": ["node_modules", ".vscode-test"],
"references": [
{
"path": "./client"
},
{
"path": "./server"
},
{
"path": "./integration-tests"
}
],
"extends": "@tsconfig/node16-strictest/tsconfig.json"
}

View File

@ -1,3 +0,0 @@
node_modules
*.vsix
*.tgz

View File

@ -1,65 +0,0 @@
# aqua README
This is the README for your extension "aqua". After writing up a brief description, we recommend including the following sections.
## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
## Extension Settings
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
For example:
This extension contributes the following settings:
* `myExtension.enable`: enable/disable this extension
* `myExtension.thing`: set to `blah` to do something
## Known Issues
Calling out known issues can help limit users opening duplicate issues against your extension.
## Release Notes
Users appreciate release notes as you update your extension.
### 1.0.0
Initial release of ...
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
-----------------------------------------------------------------------------------------------------------
## Working with Markdown
**Note:** You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux)
* Toggle preview (`Shift+CMD+V` on macOS or `Shift+Ctrl+V` on Windows and Linux)
* Press `Ctrl+Space` (Windows, Linux) or `Cmd+Space` (macOS) to see a list of Markdown snippets
### For more information
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
**Enjoy!**

View File

@ -1,33 +0,0 @@
{
"name": "aqua-syntax-highlight",
"displayName": "aqua",
"description": "aqua language support",
"version": "1.0.0",
"engines": {
"vscode": "^1.56.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [
{
"id": "aqua",
"aliases": [
"aqua"
],
"extensions": [
".aqua"
],
"configuration": "./language-configuration.json"
}
],
"grammars": [
{
"language": "aqua",
"scopeName": "source.aqua",
"path": "./syntaxes/aqua.tmLanguage.json"
}
]
}
}

View File

@ -1,65 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "aqua",
"patterns": [
{
"include": "#keywords"
},
{
"include": "#strings"
},
{
"include": "#comments"
},
{
"include": "#semantics"
}
],
"repository": {
"keywords": {
"patterns": [
{
"name": "keyword.control.aqua",
"match": "\\b(if|else|otherwise|use|try|catch|on|via|for|par|use|<-)\\b"
},
{
"name": "keyword.operator.logical.aqua",
"match": "\\b(eqs|neq)\\b"
},
{
"name": "keyword.declaration.aqua",
"match": "\\b(func|service|data|alias)\\b"
},
{
"name": "keyword.control.import",
"match": "\\b(import)\\b"
}
]
},
"strings": {
"name": "string.quoted.double.aqua",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.aqua",
"match": "\\\\."
}
]
},
"comments": {
"name": "comment.line.aqua",
"begin": "--",
"end": "$"
},
"semantics": {
"patterns": [
{
"name": "storage.type.aqua",
"match": "\\b(string|bool|u8|u16|u32|u64|s8|s16|s32|s64|f32|f64)\\b"
}
]
}
},
"scopeName": "source.aqua"
}

View File

@ -1,29 +0,0 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension.
* `syntaxes/aqua.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization.
* `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets.
## Get up and running straight away
* Make sure the language configuration settings in `language-configuration.json` are accurate.
* Press `F5` to open a new window with your extension loaded.
* Create a new file with a file name suffix matching your language.
* Verify that syntax highlighting works and that the language configuration settings are working.
## Make changes
* You can relaunch the extension from the debug toolbar after making changes to the files listed above.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Add more language features
* To add features such as intellisense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs
## Install your extension
* To start using your extension with Visual Studio Code copy it into the `<user home>/.vscode/extensions` folder and restart Code.
* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension.