├── .github └── workflows │ ├── ignore_words │ ├── release.yml │ ├── spellcheck.yml │ └── test.yml ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── asset ├── codicon │ ├── codicon.css │ └── codicon.ttf ├── dark.png ├── keymap.js ├── light.png ├── logo.png ├── query.js └── simplified_logo.svg ├── language-configuration.json ├── lib └── js │ ├── src │ ├── Agda.bs.js │ ├── Command.bs.js │ ├── Config.bs.js │ ├── Connection │ │ ├── Connection.bs.js │ │ ├── Connection__Command.bs.js │ │ ├── Connection__Download.bs.js │ │ ├── Connection__Error.bs.js │ │ ├── Connection__Process.bs.js │ │ ├── Connection__Scheduler.bs.js │ │ ├── Connection__TCP.bs.js │ │ ├── Connection__Target.bs.js │ │ ├── Connection__URI.bs.js │ │ ├── Download │ │ │ ├── Connection__Download__GitHub.bs.js │ │ │ ├── Connection__Download__Platform.bs.js │ │ │ ├── Connection__Download__Unzip.bs.js │ │ │ └── Connection__Download__Util.bs.js │ │ ├── Process │ │ │ └── Connection__Process__Exec.bs.js │ │ └── Target │ │ │ ├── ALS │ │ │ ├── Connection__Target__ALS.bs.js │ │ │ ├── Connection__Target__ALS__Error.bs.js │ │ │ └── LSP │ │ │ │ ├── Connection__Target__ALS__LSP.bs.js │ │ │ │ └── Connection__Target__ALS__LSP__Binding.bs.js │ │ │ ├── Agda │ │ │ ├── Connection__Target__Agda.bs.js │ │ │ └── Connection__Target__Agda__Error.bs.js │ │ │ └── Connection__Target__IPC.bs.js │ ├── Editor.bs.js │ ├── Goal.bs.js │ ├── Highlighting.bs.js │ ├── Highlighting │ │ ├── Highlighting__AgdaAspect.bs.js │ │ ├── Highlighting__Decoration.bs.js │ │ └── Highlighting__SemanticToken.bs.js │ ├── InputMethod │ │ ├── Buffer.bs.js │ │ ├── IM.bs.js │ │ └── Translator.bs.js │ ├── Main.bs.js │ ├── Node │ │ ├── N.bs.js │ │ ├── Node__Fs.bs.js │ │ ├── Node__Net.bs.js │ │ └── Node__Util.bs.js │ ├── Parser │ │ ├── Parser.bs.js │ │ └── SourceFile.bs.js │ ├── Registry.bs.js │ ├── Request.bs.js │ ├── Resource.bs.js │ ├── Response.bs.js │ ├── State │ │ ├── State.bs.js │ │ ├── State__Command.bs.js │ │ ├── State__Connection.bs.js │ │ ├── State__Goal.bs.js │ │ ├── State__InputMethod.bs.js │ │ ├── State__Memento.bs.js │ │ ├── State__Response.bs.js │ │ ├── State__SwitchVersion.bs.js │ │ └── State__View.bs.js │ ├── Tokens.bs.js │ ├── Util │ │ ├── AVLTree.bs.js │ │ ├── Chan.bs.js │ │ ├── OS.bs.js │ │ └── Util.bs.js │ └── View │ │ ├── Common.bs.js │ │ ├── Component │ │ ├── Item.bs.js │ │ ├── Link.bs.js │ │ └── RichText.bs.js │ │ ├── Hook.bs.js │ │ ├── Panel │ │ ├── Body.bs.js │ │ ├── CandidateSymbols.bs.js │ │ ├── Emacs │ │ │ ├── Emacs__Parser.bs.js │ │ │ └── Emacs__Parser2.bs.js │ │ ├── Header.bs.js │ │ ├── Keyboard.bs.js │ │ ├── Panel.bs.js │ │ └── Prompt.bs.js │ │ ├── Root.bs.js │ │ ├── Singleton.bs.js │ │ ├── View.bs.js │ │ └── WebviewPanel.bs.js │ └── test │ ├── RunTestFromCLI.bs.js │ ├── TestSuiteAdapter.bs.js │ └── tests │ ├── Connection │ ├── Test__Connection__Process.bs.js │ └── Test__Connection__Resolver.bs.js │ ├── Parser │ ├── Test__Parser.bs.js │ ├── Test__Parser__Agda.bs.js │ ├── Test__Parser__Emacs2.bs.js │ ├── Test__Parser__Response.bs.js │ ├── Test__Parser__SExpression.bs.js │ └── Test__Parser__SourceFile.bs.js │ ├── Test.bs.js │ ├── Test__Auto.bs.js │ ├── Test__CaseSplit.bs.js │ ├── Test__ComputeNormalForm.bs.js │ ├── Test__Config.bs.js │ ├── Test__Connection.bs.js │ ├── Test__EditorIM.bs.js │ ├── Test__Highlighting.bs.js │ ├── Test__PromptIM.bs.js │ ├── Test__Refine.bs.js │ ├── Test__SolveConstraints.bs.js │ ├── Test__Tokens.bs.js │ ├── Test__Util.bs.js │ └── TextEditor │ ├── Test__AgdaOffset.bs.js │ └── Test__LineEnding.bs.js ├── package-lock.json ├── package.json ├── rescript.json ├── src ├── Agda.res ├── Command.res ├── Config.res ├── Connection │ ├── Connection.res │ ├── Connection__Command.res │ ├── Connection__Download.res │ ├── Connection__Error.res │ ├── Connection__Process.res │ ├── Connection__Scheduler.res │ ├── Connection__TCP.res │ ├── Connection__Target.res │ ├── Connection__URI.res │ ├── Download │ │ ├── Connection__Download__GitHub.res │ │ ├── Connection__Download__Platform.res │ │ ├── Connection__Download__Unzip.res │ │ └── Connection__Download__Util.res │ ├── Process │ │ └── Connection__Process__Exec.res │ └── Target │ │ ├── ALS │ │ ├── Connection__Target__ALS.res │ │ ├── Connection__Target__ALS__Error.res │ │ └── LSP │ │ │ ├── Connection__Target__ALS__LSP.res │ │ │ └── Connection__Target__ALS__LSP__Binding.res │ │ ├── Agda │ │ ├── Connection__Target__Agda.res │ │ └── Connection__Target__Agda__Error.res │ │ └── Connection__Target__IPC.res ├── Editor.res ├── Goal.res ├── Highlighting.res ├── Highlighting │ ├── Highlighting__AgdaAspect.res │ ├── Highlighting__Decoration.res │ └── Highlighting__SemanticToken.res ├── InputMethod │ ├── Buffer.res │ ├── IM.res │ └── Translator.res ├── Main.res ├── Node │ ├── N.res │ ├── Node__Fs.res │ ├── Node__Net.res │ └── Node__Util.res ├── Parser │ ├── Parser.res │ └── SourceFile.res ├── Registry.res ├── Request.res ├── Resource.res ├── Response.res ├── State │ ├── State.res │ ├── State__Command.res │ ├── State__Connection.res │ ├── State__Goal.res │ ├── State__InputMethod.res │ ├── State__Memento.res │ ├── State__Response.res │ ├── State__SwitchVersion.res │ └── State__View.res ├── Tokens.res ├── Util │ ├── AVLTree.res │ ├── Chan.res │ ├── OS.res │ └── Util.res └── View │ ├── Common.res │ ├── Component │ ├── Item.res │ ├── Link.res │ └── RichText.res │ ├── Hook.res │ ├── Panel │ ├── Body.res │ ├── CandidateSymbols.res │ ├── Emacs │ │ ├── Emacs__Parser.res │ │ └── Emacs__Parser2.res │ ├── Header.res │ ├── Keyboard.res │ ├── Panel.res │ └── Prompt.res │ ├── Root.res │ ├── Singleton.res │ ├── View.res │ └── WebviewPanel.res ├── style ├── style.less └── variables.less ├── syntaxes ├── agda.tmLanguage.json ├── forester.tmLanguage.json ├── markdown.tmLanguage.json ├── org.tmLanguage.json ├── restructuredtext.tmLanguage.json ├── tex.tmLanguage.json └── typst.tmLanguage.json ├── test ├── RunTestFromCLI.res ├── TestSuiteAdapter.res └── tests │ ├── Connection │ ├── Test__Connection__Process.res │ └── Test__Connection__Resolver.res │ ├── Parser │ ├── Response │ │ ├── Issue95-2.6.1-Unix.in │ │ ├── Issue95-2.6.1-Unix.out │ │ ├── Issue95.agda │ │ ├── QuotationMark-2.6.0-Unix.in │ │ ├── QuotationMark-2.6.0-Unix.out │ │ └── QuotationMark.agda │ ├── SExpression │ │ ├── 01.in │ │ ├── 01.out │ │ ├── 02.in │ │ ├── 02.out │ │ ├── 03.in │ │ ├── 03.out │ │ ├── 04.in │ │ └── 04.out │ ├── SourceFile │ │ ├── 01.agda.in │ │ ├── 01.agda.out │ │ ├── Issue126.agda.in │ │ ├── Issue126.agda.out │ │ ├── Issue56.agda.in │ │ ├── Issue56.agda.out │ │ ├── Issue96.agda.in │ │ ├── Issue96.agda.out │ │ ├── literate.lagda.in │ │ ├── literate.lagda.md.in │ │ ├── literate.lagda.md.out │ │ ├── literate.lagda.org.in │ │ ├── literate.lagda.org.out │ │ ├── literate.lagda.out │ │ ├── literate.lagda.rst.in │ │ └── literate.lagda.rst.out │ ├── Test__Parser.res │ ├── Test__Parser__Agda.res │ ├── Test__Parser__Emacs2.res │ ├── Test__Parser__Response.res │ ├── Test__Parser__SExpression.res │ └── Test__Parser__SourceFile.res │ ├── Test.res │ ├── Test__Auto.res │ ├── Test__CaseSplit.res │ ├── Test__ComputeNormalForm.res │ ├── Test__Config.res │ ├── Test__Connection.res │ ├── Test__EditorIM.res │ ├── Test__Highlighting.res │ ├── Test__PromptIM.res │ ├── Test__Refine.res │ ├── Test__SolveConstraints.res │ ├── Test__Tokens.res │ ├── Test__Util.res │ ├── TextEditor │ ├── Test__AgdaOffset.res │ └── Test__LineEnding.res │ └── assets │ ├── Auto.agda │ ├── CaseSplit.agda │ ├── ComputeNormalForm.agda │ ├── GotoDefinition.agda │ ├── InputMethod.agda │ ├── Issue158.agda │ ├── Issue158.agda.out │ ├── Issue173.agda │ ├── Issue180.agda │ ├── Issue204.agda │ ├── Issue204.agda.out │ └── Load.agda └── webpack.config.js /.github/workflows/ignore_words: -------------------------------------------------------------------------------- 1 | als 2 | Nd 3 | notIn 4 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 5 | 6 | name: Deploy Extension 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | 15 | - name: Install dependencies 16 | run: npm version && npm install 17 | 18 | - name: Build stuff 19 | run: npm run vscode:prepublish 20 | 21 | - name: Publish to Open VSX Registry 22 | uses: HaaLeo/publish-vscode-extension@v1 23 | with: 24 | pat: ${{ secrets.OPEN_VSX }} 25 | continue-on-error: true 26 | 27 | - name: Publish to Visual Studio Marketplace 28 | uses: HaaLeo/publish-vscode-extension@v1 29 | with: 30 | pat: ${{ secrets.VSCE_PAT }} 31 | registryUrl: https://marketplace.visualstudio.com -------------------------------------------------------------------------------- /.github/workflows/spellcheck.yml: -------------------------------------------------------------------------------- 1 | name: Spell Checker 2 | 3 | on: [push, pull_request] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} 7 | cancel-in-progress: true 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | misc: 14 | permissions: 15 | contents: read 16 | pull-requests: read 17 | name: spell checker 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Ensure git safe directory 22 | run: | 23 | git config --global --add safe.directory $(pwd) 24 | - name: check spell 25 | run: | 26 | python3 -m venv ./venv 27 | source ./venv/bin/activate 28 | pip install codespell 29 | # exclude files which may be synchronized from other places 30 | git ls-files | grep -Ev "^asset|package-lock\.json" | xargs -t codespell --ignore-words .github/workflows/ignore_words 2>/dev/null 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Testing 2 | test/globalStoragePath 3 | *.agdai 4 | 5 | 6 | .DS_Store 7 | *.vsix 8 | 9 | # Editor 10 | # NOTE: Exceptions like launch.json should be placed ahead 11 | .vscode-test 12 | 13 | # OCaml 14 | .DS_Store 15 | .merlin 16 | .bsb.lock 17 | npm-debug.log 18 | /lib/bs/ 19 | /node_modules/ 20 | 21 | 22 | # Logs 23 | logs 24 | *.log 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | lerna-debug.log* 29 | 30 | # Diagnostic reports (https://nodejs.org/api/report.html) 31 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 32 | 33 | # Runtime data 34 | pids 35 | *.pid 36 | *.seed 37 | *.pid.lock 38 | 39 | # Directory for instrumented libs generated by jscoverage/JSCover 40 | lib-cov 41 | 42 | # Coverage directory used by tools like istanbul 43 | coverage 44 | *.lcov 45 | 46 | # nyc test coverage 47 | .nyc_output 48 | 49 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 50 | .grunt 51 | 52 | # Bower dependency directory (https://bower.io/) 53 | bower_components 54 | 55 | # node-waf configuration 56 | .lock-wscript 57 | 58 | # Compiled binary addons (https://nodejs.org/api/addons.html) 59 | build/Release 60 | 61 | # Dependency directories 62 | node_modules/ 63 | jspm_packages/ 64 | 65 | # TypeScript v1 declaration files 66 | typings/ 67 | 68 | # TypeScript cache 69 | *.tsbuildinfo 70 | 71 | # Optional npm cache directory 72 | .npm 73 | 74 | # Optional eslint cache 75 | .eslintcache 76 | 77 | # Microbundle cache 78 | .rpt2_cache/ 79 | .rts2_cache_cjs/ 80 | .rts2_cache_es/ 81 | .rts2_cache_umd/ 82 | 83 | # Optional REPL history 84 | .node_repl_history 85 | 86 | # Output of 'npm pack' 87 | *.tgz 88 | 89 | # Yarn Integrity file 90 | .yarn-integrity 91 | 92 | # dotenv environment variables file 93 | .env 94 | .env.test 95 | 96 | # parcel-bundler cache (https://parceljs.org/) 97 | .cache 98 | 99 | # Next.js build output 100 | .next 101 | 102 | # Nuxt.js build / generate output 103 | .nuxt 104 | dist 105 | 106 | # Gatsby files 107 | .cache/ 108 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 109 | # https://nextjs.org/blog/next-9-1#public-directory-support 110 | # public 111 | 112 | # vuepress build output 113 | .vuepress/dist 114 | 115 | # Serverless directories 116 | .serverless/ 117 | 118 | # FuseBox cache 119 | .fusebox/ 120 | 121 | # DynamoDB Local files 122 | .dynamodb/ 123 | 124 | # TernJS port file 125 | .tern-port 126 | 127 | # Yarn cache 128 | .yarn/* 129 | yarn.lock 130 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "preLaunchTask": "build" 17 | }, 18 | { 19 | "name": "Extension Tests", 20 | "type": "extensionHost", 21 | "request": "launch", 22 | "runtimeExecutable": "${execPath}", 23 | "args": [ 24 | "--extensionDevelopmentPath=${workspaceFolder}", 25 | "--extensionTestsPath=${workspaceFolder}/lib/js/test/TestSuiteAdapter.bs.js" 26 | ] 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "clean", 7 | "problemMatcher": [], 8 | "label": "clean" 9 | }, 10 | { 11 | "type": "npm", 12 | "script": "build", 13 | "group": { 14 | "kind": "build", 15 | "isDefault": true 16 | }, 17 | "problemMatcher": [], 18 | "label": "build" 19 | }, 20 | { 21 | "type": "npm", 22 | "script": "vscode:prepublish", 23 | "problemMatcher": [], 24 | "label": "vscode:prepublish" 25 | }, 26 | { 27 | "type": "npm", 28 | "script": "test", 29 | "group": { 30 | "kind": "test", 31 | "isDefault": true 32 | }, 33 | "problemMatcher": [], 34 | "label": "test" 35 | }, 36 | { 37 | "type": "npm", 38 | "script": "vfx-dry-run", 39 | "problemMatcher": [], 40 | "label": "vfx-dry-run" 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | test/** 4 | .gitignore 5 | vsc-extension-quickstart.md 6 | **/jsconfig.json 7 | **/*.map 8 | **/.eslintrc.json 9 | node_modules 10 | 11 | lib/** 12 | src/** 13 | style/** 14 | .merlin 15 | bsconfig.json 16 | webpack.config.js 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This is a Visual Studio Code extension for Agda. 4 | 5 | Having some frontend development skills will definitely help you contribute to this project (but don't worry, you'll manage even if you don't have them) 6 | 7 | ### Language 8 | 9 | This project is written in [ReScript](https://rescript-lang.org/). It's essentially OCaml that compiles to JavaScript, so that we don't have to write JavaScript ourselves. 10 | 11 | ### Framework 12 | 13 | We use [React](https://rescript-lang.org/docs/react/latest/introduction) as the frontend framework. It comes with a nice binding for ReScript. 14 | 15 | # Setup 16 | 17 | You'll need to install [Node.js](https://nodejs.org/) for building the project. 18 | 19 | After cloning the files, download dependencies and build files with: 20 | 21 | ```bash 22 | npm install 23 | npm run build 24 | ``` 25 | 26 | Fire up this command to enter the "watch mode" so that you don't have to rebuild stuff manually: 27 | 28 | ```bash 29 | npm run dev 30 | ``` 31 | 32 | Press F5 in VS Code and you should have a extension development host with agda-mode running! 33 | 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ting-gian LUA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /asset/codicon/codicon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banacorn/agda-mode-vscode/620994cf253770ce913c01a77726ccb04d05c860/asset/codicon/codicon.ttf -------------------------------------------------------------------------------- /asset/dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banacorn/agda-mode-vscode/620994cf253770ce913c01a77726ccb04d05c860/asset/dark.png -------------------------------------------------------------------------------- /asset/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banacorn/agda-mode-vscode/620994cf253770ce913c01a77726ccb04d05c860/asset/light.png -------------------------------------------------------------------------------- /asset/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banacorn/agda-mode-vscode/620994cf253770ce913c01a77726ccb04d05c860/asset/logo.png -------------------------------------------------------------------------------- /asset/simplified_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | logotype 4 | Simplified Agda Logo. 5 | 6 | 7 | 8 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "--", 4 | "blockComment": ["{-", "-}"] 5 | }, 6 | "brackets": [ 7 | ["(", ")"], 8 | ["{", "}"], 9 | ["{!", "!}"], 10 | ["{-#", "#-}"] 11 | ], 12 | "autoClosingPairs": [ 13 | { 14 | "open": "\"", 15 | "close": "\"", 16 | "notIn": ["comment", "string"] 17 | }, 18 | { 19 | "open": "{!", 20 | "close": "!}", 21 | "notIn": ["comment", "string"] 22 | }, 23 | { 24 | "open": "{-#", 25 | "close": "#-}", 26 | "notIn": ["comment", "string"] 27 | }, 28 | { 29 | "open": "⦃", 30 | "close": "⦄", 31 | "notIn": ["comment", "string"] 32 | }, 33 | { 34 | "open": "⦇", 35 | "close": "⦈", 36 | "notIn": ["comment", "string"] 37 | } 38 | ], 39 | "surroundingPairs": [ 40 | ["(", ")"], 41 | ["{", "}"], 42 | ["[", "]"], 43 | ["\"", "\""], 44 | ["'", "'"], 45 | ["{!", "!}"], 46 | ["{-#", "#-}"], 47 | ["{{", "}}"], 48 | ["⦃", "⦄"], 49 | ["(|", "|)"], 50 | ["⦇", "⦈"] 51 | ], 52 | // "wordPattern" won't match words that start with a backslash because it will 53 | // hinder the activation of other autocompletion-based input methods like 54 | // `latex-input`. 55 | // see https://github.com/banacorn/agda-mode-vscode/issues/184 56 | "wordPattern": "(?!\\\\)[^\\s\\n\\.\\;\\{\\}\\(\\)\\@\\\"]+", 57 | "onEnterRules": [ 58 | { 59 | // Indent if a line ends with any of `=` `:` `⦃` `⦇` 60 | "beforeText": "[\\s\\n\\.\\;\\{\\}\\(\\)\\@\\\"][=:⦃⦇]\\s*$", 61 | "action": { 62 | "indent": "indent" 63 | } 64 | }, 65 | { 66 | // Indent if a line starts with any of the following words 67 | "beforeText": "^\\s*(module|data|record)($|[\\s\\n\\.\\;\\{\\}\\(\\)\\@\\\"])", 68 | "action": { 69 | "indent": "indent" 70 | } 71 | }, 72 | { 73 | // Indent if a line ends with any of the following keywords 74 | "beforeText": "(^|\\s)(abstract|constructor|import|infix[lr]?|field|instance|interleaved|macro|mutual|opaque|open|pattern|postulate|primitive|private|syntax|tactic|variable)\\s*$", 75 | "action": { 76 | "indent": "indent" 77 | } 78 | } 79 | ] 80 | } 81 | -------------------------------------------------------------------------------- /lib/js/src/Connection/Connection__Download.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Nodepath = require("node:path"); 5 | var Config$AgdaModeVscode = require("../Config.bs.js"); 6 | var Connection__URI$AgdaModeVscode = require("./Connection__URI.bs.js"); 7 | var Connection__Target$AgdaModeVscode = require("./Connection__Target.bs.js"); 8 | var Connection__Download__Util$AgdaModeVscode = require("./Download/Connection__Download__Util.bs.js"); 9 | var Connection__Download__GitHub$AgdaModeVscode = require("./Download/Connection__Download__GitHub.bs.js"); 10 | 11 | function toString(x) { 12 | if (typeof x !== "object") { 13 | return "Cannot find compatible Agda Language Server release for download. Prebuilts are only available for download on Ubuntu, Windows, and macOS (arm64, x64).\nPlease build from source if you are on a different platform. \nSee https://github.com/agda/agda-language-server for more information."; 14 | } 15 | switch (x.TAG) { 16 | case "CannotFetchALSReleases" : 17 | return "Cannot fetch releases of Agda Language Server: " + Connection__Download__GitHub$AgdaModeVscode.$$Error.toString(x._0); 18 | case "CannotDownloadALS" : 19 | return "Failed download the Agda Language Server: " + Connection__Download__GitHub$AgdaModeVscode.$$Error.toString(x._0); 20 | case "CannotConnectToALS" : 21 | return Connection__Target$AgdaModeVscode.$$Error.toString(x._0); 22 | 23 | } 24 | } 25 | 26 | var $$Error = { 27 | toString: toString 28 | }; 29 | 30 | function makeRepo(memento, globalStorageUri) { 31 | return { 32 | username: "agda", 33 | repository: "agda-language-server", 34 | userAgent: "agda/agda-mode-vscode", 35 | memento: memento, 36 | globalStoragePath: globalStorageUri.fsPath, 37 | cacheInvalidateExpirationSecs: 86400 38 | }; 39 | } 40 | 41 | async function getReleaseManifest(memento, globalStorageUri) { 42 | var match = await Connection__Download__GitHub$AgdaModeVscode.ReleaseManifest.$$fetch(makeRepo(memento, globalStorageUri)); 43 | var error = match[0]; 44 | if (error.TAG === "Ok") { 45 | return { 46 | TAG: "Ok", 47 | _0: error._0, 48 | [Symbol.for("name")]: "Ok" 49 | }; 50 | } else { 51 | return { 52 | TAG: "Error", 53 | _0: { 54 | TAG: "CannotFetchALSReleases", 55 | _0: error._0, 56 | [Symbol.for("name")]: "CannotFetchALSReleases" 57 | }, 58 | [Symbol.for("name")]: "Error" 59 | }; 60 | } 61 | } 62 | 63 | async function download(memento, globalStorageUri, fetchSpec) { 64 | var reportProgress = await Connection__Download__Util$AgdaModeVscode.Progress.report("Agda Language Server"); 65 | var globalStoragePath = globalStorageUri.fsPath; 66 | var error = await Connection__Download__GitHub$AgdaModeVscode.download(fetchSpec, memento, globalStoragePath, reportProgress); 67 | if (error.TAG !== "Ok") { 68 | return { 69 | TAG: "Error", 70 | _0: { 71 | TAG: "CannotDownloadALS", 72 | _0: error._0, 73 | [Symbol.for("name")]: "CannotDownloadALS" 74 | }, 75 | [Symbol.for("name")]: "Error" 76 | }; 77 | } 78 | var destPath = Connection__URI$AgdaModeVscode.parse(Nodepath.join(globalStoragePath, fetchSpec.saveAsFileName, "als")); 79 | await Config$AgdaModeVscode.Connection.addAgdaPath(destPath); 80 | var e = await Connection__Target$AgdaModeVscode.fromURI(destPath); 81 | if (e.TAG === "Ok") { 82 | return { 83 | TAG: "Ok", 84 | _0: e._0, 85 | [Symbol.for("name")]: "Ok" 86 | }; 87 | } else { 88 | return { 89 | TAG: "Error", 90 | _0: { 91 | TAG: "CannotConnectToALS", 92 | _0: e._0, 93 | [Symbol.for("name")]: "CannotConnectToALS" 94 | }, 95 | [Symbol.for("name")]: "Error" 96 | }; 97 | } 98 | } 99 | 100 | exports.$$Error = $$Error; 101 | exports.makeRepo = makeRepo; 102 | exports.getReleaseManifest = getReleaseManifest; 103 | exports.download = download; 104 | /* node:path Not a pure module */ 105 | -------------------------------------------------------------------------------- /lib/js/src/Connection/Connection__Error.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Connection__Target$AgdaModeVscode = require("./Connection__Target.bs.js"); 5 | var Connection__Command$AgdaModeVscode = require("./Connection__Command.bs.js"); 6 | var Connection__Download$AgdaModeVscode = require("./Connection__Download.bs.js"); 7 | var Connection__Target__ALS__Error$AgdaModeVscode = require("./Target/ALS/Connection__Target__ALS__Error.bs.js"); 8 | var Connection__Target__Agda__Error$AgdaModeVscode = require("./Target/Agda/Connection__Target__Agda__Error.bs.js"); 9 | 10 | function toString(attempts) { 11 | return ( 12 | attempts.targets.length === 0 ? "Tried to connect with the path from the configuration but there are none.\n" : "Tried to connect with the path from the configuration but all failed:\n" + attempts.targets.map(Connection__Target$AgdaModeVscode.$$Error.toString).join("\n") + "\n" 13 | ) + ( 14 | attempts.commands.length === 0 ? "" : attempts.commands.map(Connection__Command$AgdaModeVscode.$$Error.toString).join("\n") 15 | ); 16 | } 17 | 18 | var Attempts = { 19 | toString: toString 20 | }; 21 | 22 | function toString$1(x) { 23 | switch (x.TAG) { 24 | case "PlatformNotSupported" : 25 | var platform = x._1; 26 | return toString(x._0) + "\nTried to download the Agda Language Server but the platform `" + platform.os + "/" + platform.dist + "` is not supported.\n"; 27 | case "NoDownloadALS" : 28 | return toString(x._0) + "\nPrebuilt Agda Language Server available for download but you opted not to.\n"; 29 | case "DownloadALS" : 30 | return toString(x._0) + "\nTried to download the Agda Language Server but failed:\n" + Connection__Download$AgdaModeVscode.$$Error.toString(x._1); 31 | 32 | } 33 | } 34 | 35 | var Aggregated = { 36 | Attempts: Attempts, 37 | toString: toString$1 38 | }; 39 | 40 | function toString$2(x) { 41 | switch (x.TAG) { 42 | case "Agda" : 43 | return Connection__Target__Agda__Error$AgdaModeVscode.toString(x._0); 44 | case "ALS" : 45 | return Connection__Target__ALS__Error$AgdaModeVscode.toString(x._0); 46 | case "Aggregated" : 47 | return [ 48 | "Error", 49 | toString$1(x._0) 50 | ]; 51 | 52 | } 53 | } 54 | 55 | exports.Aggregated = Aggregated; 56 | exports.toString = toString$2; 57 | /* Connection__Target-AgdaModeVscode Not a pure module */ 58 | -------------------------------------------------------------------------------- /lib/js/src/Connection/Connection__Scheduler.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Caml = require("rescript/lib/js/caml.js"); 5 | var Chan$AgdaModeVscode = require("../Util/Chan.bs.js"); 6 | var Util$AgdaModeVscode = require("../Util/Util.bs.js"); 7 | 8 | function make() { 9 | return { 10 | tally: 0, 11 | allDone: Chan$AgdaModeVscode.make(), 12 | deferredLastResponses: [] 13 | }; 14 | } 15 | 16 | function runNonLast(self, handler, response) { 17 | self.tally = self.tally + 1 | 0; 18 | handler(response).finally(function () { 19 | self.tally = self.tally - 1 | 0; 20 | if (self.tally === 0) { 21 | return Chan$AgdaModeVscode.emit(self.allDone, undefined); 22 | } 23 | 24 | }); 25 | } 26 | 27 | function addLast(self, priority, response) { 28 | self.deferredLastResponses.push([ 29 | priority, 30 | response 31 | ]); 32 | } 33 | 34 | function onceDone(self) { 35 | if (self.tally === 0) { 36 | return Promise.resolve(); 37 | } else { 38 | return Chan$AgdaModeVscode.once(self.allDone); 39 | } 40 | } 41 | 42 | async function runLast(self, handler) { 43 | await onceDone(self); 44 | self.deferredLastResponses.sort(function (x, y) { 45 | return Caml.int_compare(x[0], y[0]); 46 | }); 47 | var deferredLastResponses = self.deferredLastResponses.map(function (prim) { 48 | return prim[1]; 49 | }); 50 | deferredLastResponses.unshift("CompleteHighlightingAndMakePromptReappear"); 51 | await Util$AgdaModeVscode.Promise_.oneByOne(deferredLastResponses.map(function (res) { 52 | return function () { 53 | return handler(res); 54 | }; 55 | })); 56 | } 57 | 58 | var Module = { 59 | make: make, 60 | addLast: addLast, 61 | runNonLast: runNonLast, 62 | runLast: runLast 63 | }; 64 | 65 | exports.Module = Module; 66 | exports.make = make; 67 | exports.addLast = addLast; 68 | exports.runNonLast = runNonLast; 69 | exports.runLast = runLast; 70 | /* Chan-AgdaModeVscode Not a pure module */ 71 | -------------------------------------------------------------------------------- /lib/js/src/Connection/Connection__TCP.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Nodenet = require("node:net"); 5 | var Util$AgdaModeVscode = require("../Util/Util.bs.js"); 6 | 7 | function toString(x) { 8 | if (x.TAG === "Timeout") { 9 | return "Expected to connect within " + String(x._0) + "ms"; 10 | } else { 11 | return Util$AgdaModeVscode.JsError.toString(x._0); 12 | } 13 | } 14 | 15 | var $$Error = { 16 | toString: toString 17 | }; 18 | 19 | function probe(url, timeoutOpt) { 20 | var timeout = timeoutOpt !== undefined ? timeoutOpt : 1000; 21 | var connection = new Promise((function (resolve, param) { 22 | var socket = new Nodenet.Socket(); 23 | socket.connect(url.port, url.hostname, (function () { 24 | 25 | })).once("connect", (function () { 26 | socket.destroy(undefined); 27 | resolve({ 28 | TAG: "Ok", 29 | _0: undefined, 30 | [Symbol.for("name")]: "Ok" 31 | }); 32 | })).once("error", (function (exn) { 33 | resolve({ 34 | TAG: "Error", 35 | _0: { 36 | TAG: "OnError", 37 | _0: exn, 38 | [Symbol.for("name")]: "OnError" 39 | }, 40 | [Symbol.for("name")]: "Error" 41 | }); 42 | })).once("timeout", (function () { 43 | resolve({ 44 | TAG: "Error", 45 | _0: { 46 | TAG: "Timeout", 47 | _0: timeout, 48 | [Symbol.for("name")]: "Timeout" 49 | }, 50 | [Symbol.for("name")]: "Error" 51 | }); 52 | })); 53 | })); 54 | var timeout$1 = async function () { 55 | await Util$AgdaModeVscode.Promise_.$$setTimeout(timeout); 56 | return { 57 | TAG: "Error", 58 | _0: { 59 | TAG: "Timeout", 60 | _0: timeout, 61 | [Symbol.for("name")]: "Timeout" 62 | }, 63 | [Symbol.for("name")]: "Error" 64 | }; 65 | }; 66 | return Promise.race([ 67 | connection, 68 | timeout$1() 69 | ]); 70 | } 71 | 72 | exports.$$Error = $$Error; 73 | exports.probe = probe; 74 | /* node:net Not a pure module */ 75 | -------------------------------------------------------------------------------- /lib/js/src/Connection/Connection__URI.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Nodeurl = require("node:url"); 5 | var Nodepath = require("node:path"); 6 | var Untildify = require("untildify"); 7 | var OS$AgdaModeVscode = require("../Util/OS.bs.js"); 8 | 9 | function parse(path) { 10 | var result; 11 | try { 12 | result = new Nodeurl.URL(path); 13 | } 14 | catch (exn){ 15 | result = undefined; 16 | } 17 | var result$1 = result !== undefined && result.protocol === "lsp:" ? result : undefined; 18 | if (result$1 !== undefined) { 19 | return { 20 | TAG: "URL", 21 | _0: result$1, 22 | [Symbol.for("name")]: "URL" 23 | }; 24 | } 25 | var path$1 = Untildify(path); 26 | var path$2 = Nodepath.normalize(path$1); 27 | var path$3 = OS$AgdaModeVscode.onUnix ? path$2 : path$2.replace(/^\\([a-zA-Z])\\/, "$1\:\\"); 28 | return { 29 | TAG: "Filepath", 30 | _0: path$3, 31 | [Symbol.for("name")]: "Filepath" 32 | }; 33 | } 34 | 35 | function toString(path) { 36 | if (path.TAG === "Filepath") { 37 | return Nodepath.normalize(path._0); 38 | } else { 39 | return path._0.toString(); 40 | } 41 | } 42 | 43 | function equal(x, y) { 44 | if (x.TAG === "Filepath") { 45 | if (y.TAG === "Filepath") { 46 | return x._0 === y._0; 47 | } else { 48 | return false; 49 | } 50 | } else if (y.TAG === "Filepath") { 51 | return false; 52 | } else { 53 | return x._0.toString() === y._0.toString(); 54 | } 55 | } 56 | 57 | exports.parse = parse; 58 | exports.toString = toString; 59 | exports.equal = equal; 60 | /* node:url Not a pure module */ 61 | -------------------------------------------------------------------------------- /lib/js/src/Connection/Download/Connection__Download__Platform.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Getos = require("getos"); 5 | var Nodeos = require("node:os"); 6 | 7 | function determine() { 8 | return new Promise((function (resolve, param) { 9 | Getos(function (error, raw) { 10 | if (!(error == null)) { 11 | return resolve({ 12 | TAG: "Error", 13 | _0: raw, 14 | [Symbol.for("name")]: "Error" 15 | }); 16 | } 17 | var match = Nodeos.platform(); 18 | switch (match) { 19 | case "darwin" : 20 | var match$1 = Nodeos.arch(); 21 | switch (match$1) { 22 | case "arm64" : 23 | return resolve({ 24 | TAG: "Ok", 25 | _0: "MacOS_Arm", 26 | [Symbol.for("name")]: "Ok" 27 | }); 28 | case "x64" : 29 | return resolve({ 30 | TAG: "Ok", 31 | _0: "MacOS_Intel", 32 | [Symbol.for("name")]: "Ok" 33 | }); 34 | default: 35 | return resolve({ 36 | TAG: "Error", 37 | _0: raw, 38 | [Symbol.for("name")]: "Error" 39 | }); 40 | } 41 | case "linux" : 42 | var match$2 = raw.dist; 43 | if (match$2 === "Ubuntu") { 44 | return resolve({ 45 | TAG: "Ok", 46 | _0: "Ubuntu", 47 | [Symbol.for("name")]: "Ok" 48 | }); 49 | } else { 50 | return resolve({ 51 | TAG: "Error", 52 | _0: raw, 53 | [Symbol.for("name")]: "Error" 54 | }); 55 | } 56 | case "win32" : 57 | return resolve({ 58 | TAG: "Ok", 59 | _0: "Windows", 60 | [Symbol.for("name")]: "Ok" 61 | }); 62 | default: 63 | return resolve({ 64 | TAG: "Error", 65 | _0: raw, 66 | [Symbol.for("name")]: "Error" 67 | }); 68 | } 69 | }); 70 | })); 71 | } 72 | 73 | function toAssetName(platform) { 74 | switch (platform) { 75 | case "Windows" : 76 | return "windows"; 77 | case "Ubuntu" : 78 | return "ubuntu"; 79 | case "MacOS_Arm" : 80 | return "macos-arm64"; 81 | case "MacOS_Intel" : 82 | return "macos-x64"; 83 | 84 | } 85 | } 86 | 87 | exports.determine = determine; 88 | exports.toAssetName = toAssetName; 89 | /* getos Not a pure module */ 90 | -------------------------------------------------------------------------------- /lib/js/src/Connection/Download/Connection__Download__Unzip.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Nodefs = require("node:fs"); 5 | var Unzipper = require("unzipper"); 6 | 7 | var Unzipper$1 = {}; 8 | 9 | function run(src, dest) { 10 | return new Promise((function (resolve, param) { 11 | var readStream = Nodefs.createReadStream(src); 12 | readStream.once("close", resolve); 13 | readStream.pipe(Unzipper.Extract({ 14 | path: dest 15 | })); 16 | })); 17 | } 18 | 19 | exports.Unzipper = Unzipper$1; 20 | exports.run = run; 21 | /* node:fs Not a pure module */ 22 | -------------------------------------------------------------------------------- /lib/js/src/Connection/Target/Agda/Connection__Target__Agda__Error.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Parser$AgdaModeVscode = require("../../../Parser/Parser.bs.js"); 5 | var Connection__Process$AgdaModeVscode = require("../../Connection__Process.bs.js"); 6 | 7 | function toString(x) { 8 | if (typeof x !== "object") { 9 | return [ 10 | "Connection Error", 11 | "Connection via TCP not supported yet" 12 | ]; 13 | } 14 | switch (x.TAG) { 15 | case "Process" : 16 | return [ 17 | "Process Error", 18 | Connection__Process$AgdaModeVscode.$$Event.toString(x._0) 19 | ]; 20 | case "AgdaError" : 21 | return [ 22 | "Agda Error", 23 | x._0 24 | ]; 25 | case "ResponseParseError" : 26 | return [ 27 | "Internal Parse Error", 28 | Parser$AgdaModeVscode.$$Error.toString(x._0) 29 | ]; 30 | 31 | } 32 | } 33 | 34 | var Process; 35 | 36 | exports.Process = Process; 37 | exports.toString = toString; 38 | /* Parser-AgdaModeVscode Not a pure module */ 39 | -------------------------------------------------------------------------------- /lib/js/src/Connection/Target/Connection__Target__IPC.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ 3 | -------------------------------------------------------------------------------- /lib/js/src/Highlighting/Highlighting__Decoration.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Vscode = require("vscode"); 5 | var Editor$AgdaModeVscode = require("../Editor.bs.js"); 6 | 7 | function toVSCodeDecorations(input, editor) { 8 | var backgroundColorDict = {}; 9 | var foregroundColorDict = {}; 10 | var addFaceToDict = function (face, range) { 11 | if (face.TAG === "Background") { 12 | var color = face._0; 13 | var ranges = backgroundColorDict[color]; 14 | if (ranges !== undefined) { 15 | ranges.push(range); 16 | } else { 17 | backgroundColorDict[color] = [range]; 18 | } 19 | return ; 20 | } 21 | var color$1 = face._0; 22 | var ranges$1 = foregroundColorDict[color$1]; 23 | if (ranges$1 !== undefined) { 24 | ranges$1.push(range); 25 | } else { 26 | foregroundColorDict[color$1] = [range]; 27 | } 28 | }; 29 | input.forEach(function (param) { 30 | var range = param[1]; 31 | var match = param[0]; 32 | var theme = Vscode.window.activeColorTheme.kind; 33 | if (theme === 2) { 34 | return addFaceToDict(match.dark, range); 35 | } else { 36 | return addFaceToDict(match.light, range); 37 | } 38 | }); 39 | var backgroundDecorations = Object.entries(backgroundColorDict).map(function (param) { 40 | var ranges = param[1]; 41 | return [ 42 | Editor$AgdaModeVscode.Decoration.highlightBackgroundWithColor(editor, param[0], ranges), 43 | ranges 44 | ]; 45 | }); 46 | var foregroundDecorations = Object.entries(foregroundColorDict).map(function (param) { 47 | var ranges = param[1]; 48 | return [ 49 | Editor$AgdaModeVscode.Decoration.decorateTextWithColor(editor, param[0], ranges), 50 | ranges 51 | ]; 52 | }); 53 | return foregroundDecorations.concat(backgroundDecorations); 54 | } 55 | 56 | exports.toVSCodeDecorations = toVSCodeDecorations; 57 | /* vscode Not a pure module */ 58 | -------------------------------------------------------------------------------- /lib/js/src/Node/N.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Caml_exceptions = require("rescript/lib/js/caml_exceptions.js"); 5 | 6 | var Exception = /* @__PURE__ */Caml_exceptions.create("N-AgdaModeVscode.Exception"); 7 | 8 | var Net; 9 | 10 | var Util; 11 | 12 | var Fs; 13 | 14 | exports.Exception = Exception; 15 | exports.Net = Net; 16 | exports.Util = Util; 17 | exports.Fs = Fs; 18 | /* No side effect */ 19 | -------------------------------------------------------------------------------- /lib/js/src/Node/Node__Fs.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Nodefs = require("node:fs"); 5 | 6 | async function readFile(filepath) { 7 | var fileHandle = await Nodefs.promises.open(filepath, "r"); 8 | var buffer = await fileHandle.readFile(); 9 | await fileHandle.close(); 10 | return buffer.toString(); 11 | } 12 | 13 | exports.readFile = readFile; 14 | /* node:fs Not a pure module */ 15 | -------------------------------------------------------------------------------- /lib/js/src/Node/Node__Net.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | 5 | var Socket = {}; 6 | 7 | exports.Socket = Socket; 8 | /* No side effect */ 9 | -------------------------------------------------------------------------------- /lib/js/src/Node/Node__Util.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ 3 | -------------------------------------------------------------------------------- /lib/js/src/Registry.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Core__Dict = require("@rescript/core/lib/js/src/Core__Dict.bs.js"); 5 | var Core__Array = require("@rescript/core/lib/js/src/Core__Array.bs.js"); 6 | var Core__Option = require("@rescript/core/lib/js/src/Core__Option.bs.js"); 7 | var Util$AgdaModeVscode = require("./Util/Util.bs.js"); 8 | var State$AgdaModeVscode = require("./State/State.bs.js"); 9 | var Resource$AgdaModeVscode = require("./Resource.bs.js"); 10 | var Highlighting$AgdaModeVscode = require("./Highlighting.bs.js"); 11 | 12 | function make(state) { 13 | if (state === undefined) { 14 | return { 15 | state: undefined, 16 | semanticTokens: Resource$AgdaModeVscode.make() 17 | }; 18 | } 19 | var semanticTokens = Highlighting$AgdaModeVscode.getSemanticTokens(state.highlighting); 20 | return { 21 | state: state, 22 | semanticTokens: semanticTokens 23 | }; 24 | } 25 | 26 | var dict = {}; 27 | 28 | function getEntry(fileName) { 29 | return dict[fileName]; 30 | } 31 | 32 | function getState(fileName) { 33 | return Core__Option.flatMap(dict[fileName], (function (x) { 34 | return x.state; 35 | })); 36 | } 37 | 38 | function getAllStates() { 39 | return Core__Array.filterMap(Object.values(dict), (function (getEntry) { 40 | return getEntry.state; 41 | })); 42 | } 43 | 44 | function add(fileName, state) { 45 | var entry = dict[fileName]; 46 | if (entry !== undefined) { 47 | var state$1 = entry.state; 48 | if (state$1 !== undefined) { 49 | entry.state = state$1; 50 | } else { 51 | dict[fileName] = make(state); 52 | } 53 | return ; 54 | } 55 | dict[fileName] = make(state); 56 | } 57 | 58 | function remove(fileName) { 59 | Core__Dict.$$delete(dict, fileName); 60 | } 61 | 62 | async function removeAndDestroy(fileName) { 63 | var entry = dict[fileName]; 64 | if (entry !== undefined) { 65 | Core__Dict.$$delete(dict, fileName); 66 | return Core__Option.forEach(entry.state, (function (state) { 67 | State$AgdaModeVscode.destroy(state, false); 68 | })); 69 | } 70 | 71 | } 72 | 73 | async function removeAndDestroyAll() { 74 | await Util$AgdaModeVscode.Promise_.oneByOne(Object.keys(dict).map(function (pair) { 75 | return function () { 76 | return removeAndDestroy(pair); 77 | }; 78 | })); 79 | } 80 | 81 | function isEmpty() { 82 | return Object.keys(dict).length === 0; 83 | } 84 | 85 | async function requestSemanticTokens(fileName) { 86 | var entry = dict[fileName]; 87 | if (entry !== undefined) { 88 | return await Resource$AgdaModeVscode.get(entry.semanticTokens); 89 | } 90 | var entry$1 = make(undefined); 91 | dict[fileName] = entry$1; 92 | return await Resource$AgdaModeVscode.get(entry$1.semanticTokens); 93 | } 94 | 95 | var Module_Entry = {}; 96 | 97 | var Module = { 98 | Entry: Module_Entry, 99 | getState: getState, 100 | getEntry: getEntry, 101 | getAllStates: getAllStates, 102 | add: add, 103 | remove: remove, 104 | removeAndDestroy: removeAndDestroy, 105 | removeAndDestroyAll: removeAndDestroyAll, 106 | isEmpty: isEmpty, 107 | requestSemanticTokens: requestSemanticTokens 108 | }; 109 | 110 | var Entry = Module_Entry; 111 | 112 | exports.Module = Module; 113 | exports.Entry = Entry; 114 | exports.getState = getState; 115 | exports.getEntry = getEntry; 116 | exports.getAllStates = getAllStates; 117 | exports.add = add; 118 | exports.remove = remove; 119 | exports.removeAndDestroy = removeAndDestroy; 120 | exports.removeAndDestroyAll = removeAndDestroyAll; 121 | exports.isEmpty = isEmpty; 122 | exports.requestSemanticTokens = requestSemanticTokens; 123 | /* Util-AgdaModeVscode Not a pure module */ 124 | -------------------------------------------------------------------------------- /lib/js/src/Resource.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Util$AgdaModeVscode = require("./Util/Util.bs.js"); 5 | 6 | function make() { 7 | var match = Util$AgdaModeVscode.Promise_.pending(); 8 | return { 9 | state: { 10 | TAG: "Pending", 11 | _0: match[0], 12 | _1: match[1], 13 | [Symbol.for("name")]: "Pending" 14 | } 15 | }; 16 | } 17 | 18 | async function get(self) { 19 | var value = self.state; 20 | if (value.TAG === "Pending") { 21 | return await value._0; 22 | } else { 23 | return value._0; 24 | } 25 | } 26 | 27 | function set(self, value) { 28 | var match = self.state; 29 | if (match.TAG !== "Pending") { 30 | self.state = { 31 | TAG: "Acquired", 32 | _0: value, 33 | [Symbol.for("name")]: "Acquired" 34 | }; 35 | return ; 36 | } 37 | match._1(value); 38 | self.state = { 39 | TAG: "Acquired", 40 | _0: value, 41 | [Symbol.for("name")]: "Acquired" 42 | }; 43 | } 44 | 45 | var Module = { 46 | make: make, 47 | get: get, 48 | set: set 49 | }; 50 | 51 | exports.Module = Module; 52 | exports.make = make; 53 | exports.get = get; 54 | exports.set = set; 55 | /* Util-AgdaModeVscode Not a pure module */ 56 | -------------------------------------------------------------------------------- /lib/js/src/State/State__Connection.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Vscode = require("vscode"); 5 | var Core__Option = require("@rescript/core/lib/js/src/Core__Option.bs.js"); 6 | var Chan$AgdaModeVscode = require("../Util/Chan.bs.js"); 7 | var Config$AgdaModeVscode = require("../Config.bs.js"); 8 | var Connection$AgdaModeVscode = require("../Connection/Connection.bs.js"); 9 | var State__View$AgdaModeVscode = require("./State__View.bs.js"); 10 | var Connection__Download__Platform$AgdaModeVscode = require("../Connection/Download/Connection__Download__Platform.bs.js"); 11 | 12 | async function askUserAboutDownloadPolicy() { 13 | var result = await Vscode.window.showWarningMessage("Cannot find Agda or Agda Language Server", { 14 | modal: true, 15 | detail: "Do you want to download and install the latest Agda Language Server?" 16 | }, Config$AgdaModeVscode.Connection.DownloadPolicy.toString("Yes"), Config$AgdaModeVscode.Connection.DownloadPolicy.toString("No")); 17 | return Core__Option.mapOr(result, "No", Config$AgdaModeVscode.Connection.DownloadPolicy.fromString); 18 | } 19 | 20 | async function sendRequest(state, handleResponse, request) { 21 | var sendRequestAndHandleResponses = async function (connection, state, request, handler) { 22 | var onResponse = async function (response) { 23 | await handler(response); 24 | return Chan$AgdaModeVscode.emit(state.channels.log, { 25 | TAG: "ResponseHandled", 26 | _0: response, 27 | [Symbol.for("name")]: "ResponseHandled" 28 | }); 29 | }; 30 | Chan$AgdaModeVscode.emit(state.channels.log, { 31 | TAG: "RequestSent", 32 | _0: request, 33 | [Symbol.for("name")]: "RequestSent" 34 | }); 35 | var error = await Connection$AgdaModeVscode.sendRequest(connection, state.document, request, onResponse); 36 | if (error.TAG !== "Ok") { 37 | return await State__View$AgdaModeVscode.Panel.displayConnectionError(state, error._0); 38 | } 39 | var status = error._0; 40 | await State__View$AgdaModeVscode.Panel.displayConnectionStatus(state, status); 41 | if (status.TAG === "Agda") { 42 | state.agdaVersion = status._0; 43 | } else { 44 | state.agdaVersion = status._1; 45 | } 46 | }; 47 | var connection = state.connection; 48 | if (connection !== undefined) { 49 | return await sendRequestAndHandleResponses(connection, state, request, handleResponse); 50 | } 51 | var platform = await Connection__Download__Platform$AgdaModeVscode.determine(); 52 | var error = await Connection$AgdaModeVscode.make(state.memento, Config$AgdaModeVscode.Connection.getAgdaPaths(), [ 53 | "als", 54 | "agda" 55 | ], platform, askUserAboutDownloadPolicy, Connection$AgdaModeVscode.LatestALS.alreadyDownloaded(state.globalStorageUri), Connection$AgdaModeVscode.LatestALS.download(state.memento, state.globalStorageUri)); 56 | if (error.TAG !== "Ok") { 57 | return await State__View$AgdaModeVscode.Panel.displayConnectionError(state, error._0); 58 | } 59 | var connection$1 = error._0; 60 | state.connection = connection$1; 61 | return await sendRequestAndHandleResponses(connection$1, state, request, handleResponse); 62 | } 63 | 64 | async function sendRequestAndCollectResponses(state, request) { 65 | var responses = { 66 | contents: [] 67 | }; 68 | var responseHandler = async function (response) { 69 | responses.contents.push(response); 70 | }; 71 | await sendRequest(state, responseHandler, request); 72 | return responses.contents; 73 | } 74 | 75 | exports.askUserAboutDownloadPolicy = askUserAboutDownloadPolicy; 76 | exports.sendRequest = sendRequest; 77 | exports.sendRequestAndCollectResponses = sendRequestAndCollectResponses; 78 | /* vscode Not a pure module */ 79 | -------------------------------------------------------------------------------- /lib/js/src/State/State__Memento.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Caml_option = require("rescript/lib/js/caml_option.js"); 5 | 6 | var Any = {}; 7 | 8 | function make(memento) { 9 | if (memento !== undefined) { 10 | return { 11 | TAG: "Memento", 12 | _0: Caml_option.valFromOption(memento), 13 | [Symbol.for("name")]: "Memento" 14 | }; 15 | } else { 16 | return { 17 | TAG: "Mock", 18 | _0: {}, 19 | [Symbol.for("name")]: "Mock" 20 | }; 21 | } 22 | } 23 | 24 | function get(context, key) { 25 | if (context.TAG === "Memento") { 26 | return context._0.get(key); 27 | } else { 28 | return context._0[key]; 29 | } 30 | } 31 | 32 | function getWithDefault(context, key, defaultValue) { 33 | if (context.TAG === "Memento") { 34 | return context._0.get(key, defaultValue); 35 | } 36 | var value = context._0[key]; 37 | if (value !== undefined) { 38 | return Caml_option.valFromOption(value); 39 | } else { 40 | return defaultValue; 41 | } 42 | } 43 | 44 | function keys(context) { 45 | if (context.TAG === "Memento") { 46 | return context._0.keys(); 47 | } else { 48 | return Object.keys(context._0); 49 | } 50 | } 51 | 52 | function set(context, key, value) { 53 | if (context.TAG === "Memento") { 54 | return context._0.update(key, value); 55 | } else { 56 | return Promise.resolve((context._0[key] = value, undefined)); 57 | } 58 | } 59 | 60 | function toString(context) { 61 | if (context.TAG === "Memento") { 62 | var context$1 = context._0; 63 | var entries = context$1.keys().map(function (key) { 64 | var value = context$1.get(key); 65 | if (value !== undefined) { 66 | return key + ": " + Caml_option.valFromOption(value); 67 | } else { 68 | return key + ": None"; 69 | } 70 | }); 71 | return "Memento: {\n" + entries.join("\n") + "}"; 72 | } 73 | var entries$1 = Object.entries(context._0).map(function (param) { 74 | return param[0] + ": " + String(param[1]); 75 | }); 76 | return "Mock: {\n" + entries$1.join("\n") + "}"; 77 | } 78 | 79 | var Module = { 80 | make: make, 81 | get: get, 82 | getWithDefault: getWithDefault, 83 | keys: keys, 84 | set: set, 85 | toString: toString 86 | }; 87 | 88 | exports.Any = Any; 89 | exports.Module = Module; 90 | exports.make = make; 91 | exports.get = get; 92 | exports.getWithDefault = getWithDefault; 93 | exports.keys = keys; 94 | exports.set = set; 95 | exports.toString = toString; 96 | /* No side effect */ 97 | -------------------------------------------------------------------------------- /lib/js/src/Util/AVLTree.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Caml_option = require("rescript/lib/js/caml_option.js"); 5 | var Core__Option = require("@rescript/core/lib/js/src/Core__Option.bs.js"); 6 | 7 | var $$Node = {}; 8 | 9 | function find(self, key) { 10 | return Core__Option.map(Caml_option.nullable_to_opt(self.find(key)), (function (prim) { 11 | return prim.getValue(); 12 | })); 13 | } 14 | 15 | function max(self) { 16 | return Core__Option.map(Caml_option.nullable_to_opt(self.max()), (function (prim) { 17 | return prim.getValue(); 18 | })); 19 | } 20 | 21 | function min(self) { 22 | return Core__Option.map(Caml_option.nullable_to_opt(self.min()), (function (prim) { 23 | return prim.getValue(); 24 | })); 25 | } 26 | 27 | function upperBound(self, key) { 28 | return Core__Option.map(Caml_option.nullable_to_opt(self.upperBound(key)), (function (prim) { 29 | return prim.getValue(); 30 | })); 31 | } 32 | 33 | function lowerBound(self, key) { 34 | return Core__Option.map(Caml_option.nullable_to_opt(self.lowerBound(key)), (function (prim) { 35 | return prim.getValue(); 36 | })); 37 | } 38 | 39 | function floor(self, key) { 40 | return Core__Option.map(Caml_option.nullable_to_opt(self.floor(key)), (function (prim) { 41 | return prim.getValue(); 42 | })); 43 | } 44 | 45 | function ceil(self, key) { 46 | return Core__Option.map(Caml_option.nullable_to_opt(self.ceil(key)), (function (prim) { 47 | return prim.getValue(); 48 | })); 49 | } 50 | 51 | function toArray(self) { 52 | var accum = []; 53 | self.traverseInOrder(function (node) { 54 | var value = node.getValue(); 55 | accum.push(value); 56 | }); 57 | return accum; 58 | } 59 | 60 | exports.$$Node = $$Node; 61 | exports.find = find; 62 | exports.max = max; 63 | exports.min = min; 64 | exports.upperBound = upperBound; 65 | exports.lowerBound = lowerBound; 66 | exports.floor = floor; 67 | exports.ceil = ceil; 68 | exports.toArray = toArray; 69 | /* No side effect */ 70 | -------------------------------------------------------------------------------- /lib/js/src/Util/Chan.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Eventemitter3 = require("eventemitter3"); 5 | 6 | function emit0(arg1, obj) { 7 | return obj.emit(arg1); 8 | } 9 | 10 | function emit2(arg1, arg2, arg3, obj) { 11 | return obj.emit(arg1, arg2, arg3); 12 | } 13 | 14 | function eventNames(arg1, obj) { 15 | return obj.eventNames(arg1); 16 | } 17 | 18 | function on(prim0, prim1, prim2) { 19 | return prim0.addListener(prim1, prim2); 20 | } 21 | 22 | function on2(prim0, prim1, prim2) { 23 | return prim0.addListener(prim1, prim2); 24 | } 25 | 26 | function on3(prim0, prim1, prim2) { 27 | return prim0.addListener(prim1, prim2); 28 | } 29 | 30 | function once2(arg1, arg2, obj) { 31 | return obj.once(arg1, arg2); 32 | } 33 | 34 | function removeListener(prim0, prim1, prim2) { 35 | return prim0.off(prim1, prim2); 36 | } 37 | 38 | function removeListener2(prim0, prim1, prim2) { 39 | return prim0.off(prim1, prim2); 40 | } 41 | 42 | function removeListener3(prim0, prim1, prim2) { 43 | return prim0.off(prim1, prim2); 44 | } 45 | 46 | var EventEmitter3 = { 47 | emit0: emit0, 48 | emit2: emit2, 49 | eventNames: eventNames, 50 | on: on, 51 | on2: on2, 52 | on3: on3, 53 | once2: once2, 54 | removeListener: removeListener, 55 | removeListener2: removeListener2, 56 | removeListener3: removeListener3 57 | }; 58 | 59 | function make(prim) { 60 | return new Eventemitter3.EventEmitter(); 61 | } 62 | 63 | function emit(self, x) { 64 | self.emit("data", x); 65 | } 66 | 67 | function on$1(self, callback) { 68 | self.addListener("data", callback); 69 | return function () { 70 | self.off("data", callback); 71 | }; 72 | } 73 | 74 | function once(self) { 75 | return new Promise((function (resolve, param) { 76 | self.once("data", resolve); 77 | })); 78 | } 79 | 80 | function pipe(self, other) { 81 | return on$1(self, (function (val) { 82 | emit(other, val); 83 | })); 84 | } 85 | 86 | function destroy(self) { 87 | self.removeAllListeners(); 88 | } 89 | 90 | var Module = { 91 | make: make, 92 | emit: emit, 93 | on: on$1, 94 | once: once, 95 | pipe: pipe, 96 | destroy: destroy 97 | }; 98 | 99 | exports.EventEmitter3 = EventEmitter3; 100 | exports.Module = Module; 101 | exports.make = make; 102 | exports.emit = emit; 103 | exports.on = on$1; 104 | exports.once = once; 105 | exports.pipe = pipe; 106 | exports.destroy = destroy; 107 | /* eventemitter3 Not a pure module */ 108 | -------------------------------------------------------------------------------- /lib/js/src/Util/OS.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Nodeos = require("node:os"); 5 | 6 | var match = Nodeos.platform(); 7 | 8 | var onUnix = match === "win32" ? false : true; 9 | 10 | exports.onUnix = onUnix; 11 | /* match Not a pure module */ 12 | -------------------------------------------------------------------------------- /lib/js/src/View/Hook.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Caml_option = require("rescript/lib/js/caml_option.js"); 6 | var Core__Option = require("@rescript/core/lib/js/src/Core__Option.bs.js"); 7 | var Chan$AgdaModeVscode = require("../Util/Chan.bs.js"); 8 | var Webapi__Dom__Element = require("rescript-webapi/lib/js/src/Webapi/Dom/Webapi__Dom__Element.bs.js"); 9 | 10 | function recv(reqChan, resChan, handler) { 11 | React.useEffect((function () { 12 | return Chan$AgdaModeVscode.on(reqChan, (function (req) { 13 | handler(req).then(function (res) { 14 | Chan$AgdaModeVscode.emit(resChan, res); 15 | }); 16 | })); 17 | }), []); 18 | } 19 | 20 | function on(chan, handler) { 21 | React.useEffect((function () { 22 | return Chan$AgdaModeVscode.on(chan, handler); 23 | }), []); 24 | } 25 | 26 | function useFocus() { 27 | var htmlElRef = React.useRef(null); 28 | var setFocus = function (param) { 29 | Core__Option.forEach(Core__Option.flatMap(Caml_option.nullable_to_opt(htmlElRef.current), Webapi__Dom__Element.asHtmlElement), (function (prim) { 30 | prim.focus(); 31 | })); 32 | }; 33 | return [ 34 | htmlElRef, 35 | setFocus 36 | ]; 37 | } 38 | 39 | exports.recv = recv; 40 | exports.on = on; 41 | exports.useFocus = useFocus; 42 | /* react Not a pure module */ 43 | -------------------------------------------------------------------------------- /lib/js/src/View/Panel/Body.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Item$AgdaModeVscode = require("../Component/Item.bs.js"); 6 | var JsxPPXReactSupportU = require("rescript/lib/js/jsxPPXReactSupportU.js"); 7 | 8 | function Body(props) { 9 | var items = props.items; 10 | if (items.length !== 0) { 11 | return React.createElement("div", { 12 | className: "agda-mode-body" 13 | }, React.createElement("ul", undefined, items.map(function (item, i) { 14 | return JsxPPXReactSupportU.createElementWithKey(String(i), Item$AgdaModeVscode.make, { 15 | item: item 16 | }); 17 | }))); 18 | } else { 19 | return React.createElement(React.Fragment, {}); 20 | } 21 | } 22 | 23 | var make = Body; 24 | 25 | exports.make = make; 26 | /* react Not a pure module */ 27 | -------------------------------------------------------------------------------- /lib/js/src/View/Panel/CandidateSymbols.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | 6 | function CandidateSymbols(props) { 7 | var onChooseSymbol = props.onChooseSymbol; 8 | var index = props.index; 9 | var candidates = props.candidates; 10 | var rowStart = Math.imul(index / 10 | 0, 10); 11 | var row = candidates.slice(rowStart, rowStart + 10 | 0); 12 | var match = candidates[index]; 13 | return React.createElement("div", { 14 | className: "agda-mode-keyboard-candidates" 15 | }, match !== undefined ? row.map(function (key, i) { 16 | var isSelected = (rowStart + i | 0) === index; 17 | return React.createElement("button", { 18 | key: key, 19 | className: "agda-mode-key " + ( 20 | isSelected ? "selected" : "" 21 | ), 22 | onClick: (function (param) { 23 | onChooseSymbol(key); 24 | }) 25 | }, key); 26 | }) : React.createElement(React.Fragment, {})); 27 | } 28 | 29 | var make = CandidateSymbols; 30 | 31 | exports.make = make; 32 | /* react Not a pure module */ 33 | -------------------------------------------------------------------------------- /lib/js/src/View/Panel/Header.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | 6 | function Header(props) { 7 | var header = props.header; 8 | var status = React.createElement("div", { 9 | className: "agda-mode-header-status" 10 | }, props.status); 11 | switch (header.TAG) { 12 | case "Plain" : 13 | return React.createElement("div", { 14 | className: "agda-mode-header" 15 | }, header._0, status); 16 | case "Success" : 17 | return React.createElement("div", { 18 | className: "agda-mode-header success" 19 | }, header._0, status); 20 | case "Warning" : 21 | return React.createElement("div", { 22 | className: "agda-mode-header warning" 23 | }, header._0, status); 24 | case "Error" : 25 | return React.createElement("div", { 26 | className: "agda-mode-header error" 27 | }, header._0, status); 28 | 29 | } 30 | } 31 | 32 | var make = Header; 33 | 34 | exports.make = make; 35 | /* react Not a pure module */ 36 | -------------------------------------------------------------------------------- /lib/js/src/View/Panel/Keyboard.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Caml = require("rescript/lib/js/caml.js"); 5 | var React = require("react"); 6 | var Translator$AgdaModeVscode = require("../../InputMethod/Translator.bs.js"); 7 | var CandidateSymbols$AgdaModeVscode = require("./CandidateSymbols.bs.js"); 8 | 9 | function reducer(state, action) { 10 | if (typeof action !== "object") { 11 | switch (action) { 12 | case "Activate" : 13 | var translation = Translator$AgdaModeVscode.translate("", undefined); 14 | return { 15 | sequence: "", 16 | translation: translation, 17 | candidateIndex: 0 18 | }; 19 | case "Deactivate" : 20 | return ; 21 | default: 22 | 23 | } 24 | } 25 | if (state === undefined) { 26 | return ; 27 | } 28 | if (typeof action === "object") { 29 | return { 30 | sequence: action._0, 31 | translation: action._1, 32 | candidateIndex: action._2 33 | }; 34 | } 35 | switch (action) { 36 | case "BrowseUp" : 37 | return { 38 | sequence: state.sequence, 39 | translation: state.translation, 40 | candidateIndex: Caml.int_max(0, state.candidateIndex - 10 | 0) 41 | }; 42 | case "BrowseRight" : 43 | return { 44 | sequence: state.sequence, 45 | translation: state.translation, 46 | candidateIndex: Caml.int_min(state.translation.candidateSymbols.length - 1 | 0, state.candidateIndex + 1 | 0) 47 | }; 48 | case "BrowseDown" : 49 | return { 50 | sequence: state.sequence, 51 | translation: state.translation, 52 | candidateIndex: Caml.int_min(state.translation.candidateSymbols.length - 1 | 0, state.candidateIndex + 10 | 0) 53 | }; 54 | case "BrowseLeft" : 55 | return { 56 | sequence: state.sequence, 57 | translation: state.translation, 58 | candidateIndex: Caml.int_max(0, state.candidateIndex - 1 | 0) 59 | }; 60 | 61 | } 62 | } 63 | 64 | function Keyboard(props) { 65 | var state = props.state; 66 | if (state === undefined) { 67 | return React.createElement("div", { 68 | className: "agda-mode-keyboard deactivated" 69 | }); 70 | } 71 | var translation = state.translation; 72 | var onInsertChar = props.onInsertChar; 73 | return React.createElement("div", { 74 | className: "agda-mode-keyboard" + ( 75 | props.prompting ? " prompting" : "" 76 | ) 77 | }, React.createElement("div", { 78 | className: "agda-mode-keyboard-sequence-and-candidates" 79 | }, React.createElement("div", { 80 | className: "agda-mode-keyboard-sequence" 81 | }, state.sequence), React.createElement(CandidateSymbols$AgdaModeVscode.make, { 82 | candidates: translation.candidateSymbols, 83 | index: state.candidateIndex, 84 | onChooseSymbol: props.onChooseSymbol 85 | })), React.createElement("div", { 86 | className: "agda-mode-keyboard-suggestions" 87 | }, translation.keySuggestions.map(function (key) { 88 | return React.createElement("button", { 89 | key: key, 90 | className: "agda-mode-key", 91 | onClick: (function (param) { 92 | onInsertChar(key); 93 | }) 94 | }, key); 95 | }))); 96 | } 97 | 98 | var make = Keyboard; 99 | 100 | exports.reducer = reducer; 101 | exports.make = make; 102 | /* react Not a pure module */ 103 | -------------------------------------------------------------------------------- /lib/js/src/View/Root.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var VSCode = require("rescript-vscode/lib/js/src/VSCode.bs.js"); 6 | var Caml_option = require("rescript/lib/js/caml_option.js"); 7 | var Core__Option = require("@rescript/core/lib/js/src/Core__Option.bs.js"); 8 | var Client = require("react-dom/client"); 9 | var Chan$AgdaModeVscode = require("../Util/Chan.bs.js"); 10 | var View$AgdaModeVscode = require("./View.bs.js"); 11 | var Json$JsonCombinators = require("@glennsl/rescript-json-combinators/lib/js/src/Json.bs.js"); 12 | var Panel$AgdaModeVscode = require("./Panel/Panel.bs.js"); 13 | 14 | var vscode = acquireVsCodeApi(); 15 | 16 | var onRequest = Chan$AgdaModeVscode.make(); 17 | 18 | var onEventToView = Chan$AgdaModeVscode.make(); 19 | 20 | VSCode.Api.onMessage(function (stringifiedJSON) { 21 | var json = JSON.parse(stringifiedJSON); 22 | var match = Json$JsonCombinators.decode(json, View$AgdaModeVscode.RequestOrEventToView.decode); 23 | if (match.TAG !== "Ok") { 24 | return ; 25 | } 26 | var $$event = match._0; 27 | if ($$event.TAG === "Request") { 28 | return Chan$AgdaModeVscode.emit(onRequest, $$event._0); 29 | } else { 30 | return Chan$AgdaModeVscode.emit(onEventToView, $$event._0); 31 | } 32 | }); 33 | 34 | var onResponse = Chan$AgdaModeVscode.make(); 35 | 36 | Chan$AgdaModeVscode.on(onResponse, (function (response) { 37 | vscode.postMessage(View$AgdaModeVscode.ResponseOrEventFromView.encode({ 38 | TAG: "Response", 39 | _0: response, 40 | [Symbol.for("name")]: "Response" 41 | })); 42 | })); 43 | 44 | var onEventFromView = Chan$AgdaModeVscode.make(); 45 | 46 | Chan$AgdaModeVscode.on(onEventFromView, (function ($$event) { 47 | vscode.postMessage(View$AgdaModeVscode.ResponseOrEventFromView.encode({ 48 | TAG: "Event", 49 | _0: $$event, 50 | [Symbol.for("name")]: "Event" 51 | })); 52 | })); 53 | 54 | Core__Option.forEach(Caml_option.nullable_to_opt(document.getElementById("root")), (function (rootElement) { 55 | Client.createRoot(rootElement).render(React.createElement(Panel$AgdaModeVscode.make, { 56 | onRequest: onRequest, 57 | onEventToView: onEventToView, 58 | onResponse: onResponse, 59 | onEventFromView: onEventFromView 60 | })); 61 | })); 62 | 63 | exports.vscode = vscode; 64 | exports.onRequest = onRequest; 65 | exports.onEventToView = onEventToView; 66 | exports.onResponse = onResponse; 67 | exports.onEventFromView = onEventFromView; 68 | /* vscode Not a pure module */ 69 | -------------------------------------------------------------------------------- /lib/js/src/View/Singleton.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Caml_option = require("rescript/lib/js/caml_option.js"); 5 | var Core__Option = require("@rescript/core/lib/js/src/Core__Option.bs.js"); 6 | var WebviewPanel$AgdaModeVscode = require("./WebviewPanel.bs.js"); 7 | 8 | var handle = { 9 | contents: undefined 10 | }; 11 | 12 | function make(extensionPath) { 13 | var panel = handle.contents; 14 | if (panel !== undefined) { 15 | return Caml_option.valFromOption(panel); 16 | } 17 | var panel$1 = WebviewPanel$AgdaModeVscode.make("Agda", extensionPath); 18 | handle.contents = Caml_option.some(panel$1); 19 | WebviewPanel$AgdaModeVscode.onceDestroyed(panel$1).finally(function () { 20 | handle.contents = undefined; 21 | }); 22 | return panel$1; 23 | } 24 | 25 | function get() { 26 | return handle.contents; 27 | } 28 | 29 | function destroy() { 30 | Core__Option.forEach(handle.contents, WebviewPanel$AgdaModeVscode.destroy); 31 | handle.contents = undefined; 32 | } 33 | 34 | var Panel = { 35 | make: make, 36 | destroy: destroy, 37 | get: get 38 | }; 39 | 40 | var handle$1 = { 41 | contents: undefined 42 | }; 43 | 44 | function get$1() { 45 | return handle$1.contents; 46 | } 47 | 48 | function make$1(extensionPath) { 49 | var panel = handle$1.contents; 50 | if (panel !== undefined) { 51 | return Caml_option.valFromOption(panel); 52 | } 53 | var panel$1 = WebviewPanel$AgdaModeVscode.make("Agda Debug Buffer", extensionPath); 54 | handle$1.contents = Caml_option.some(panel$1); 55 | WebviewPanel$AgdaModeVscode.onceDestroyed(panel$1).finally(function () { 56 | handle$1.contents = undefined; 57 | }); 58 | return panel$1; 59 | } 60 | 61 | function destroy$1() { 62 | Core__Option.forEach(handle$1.contents, WebviewPanel$AgdaModeVscode.destroy); 63 | handle$1.contents = undefined; 64 | } 65 | 66 | var DebugBuffer = { 67 | get: get$1, 68 | make: make$1, 69 | destroy: destroy$1 70 | }; 71 | 72 | exports.Panel = Panel; 73 | exports.DebugBuffer = DebugBuffer; 74 | /* WebviewPanel-AgdaModeVscode Not a pure module */ 75 | -------------------------------------------------------------------------------- /lib/js/test/RunTestFromCLI.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Nodepath = require("node:path"); 5 | var TestElectron = require("@vscode/test-electron"); 6 | 7 | var testSuiteAdapterFileName = "TestSuiteAdapter.bs.js"; 8 | 9 | var extensionDevelopmentPath = Nodepath.resolve(__dirname, "../"); 10 | 11 | var extensionTestsPath = Nodepath.resolve(__dirname, testSuiteAdapterFileName); 12 | 13 | console.log("Running from the CLI, with\n extensionDevelopmentPath: " + (extensionDevelopmentPath + ("\n extensionTestsPath: " + extensionTestsPath))); 14 | 15 | TestElectron.runTests({ 16 | extensionDevelopmentPath: extensionDevelopmentPath, 17 | extensionTestsPath: extensionTestsPath 18 | }); 19 | 20 | exports.testSuiteAdapterFileName = testSuiteAdapterFileName; 21 | exports.extensionDevelopmentPath = extensionDevelopmentPath; 22 | exports.extensionTestsPath = extensionTestsPath; 23 | /* extensionDevelopmentPath Not a pure module */ 24 | -------------------------------------------------------------------------------- /lib/js/test/TestSuiteAdapter.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Glob = require("glob"); 5 | var Mocha = require("mocha"); 6 | var Nodepath = require("node:path"); 7 | var Caml_exceptions = require("rescript/lib/js/caml_exceptions.js"); 8 | var Caml_js_exceptions = require("rescript/lib/js/caml_js_exceptions.js"); 9 | 10 | var Mocha$1 = {}; 11 | 12 | var Glob$1 = {}; 13 | 14 | var TestFailure = /* @__PURE__ */Caml_exceptions.create("TestSuiteAdapter-AgdaModeVscode.TestFailure"); 15 | 16 | function run() { 17 | var mocha = new Mocha({ 18 | ui: "bdd", 19 | color: true 20 | }); 21 | var testsRoot = Nodepath.resolve(__dirname, "tests"); 22 | return new Promise((function (resolve, reject) { 23 | Glob("**/*.js", { 24 | cwd: testsRoot 25 | }, (function (err, files) { 26 | if (!(err == null)) { 27 | return reject(err); 28 | } 29 | files.forEach(function (file) { 30 | mocha.addFile(Nodepath.resolve(testsRoot, file)); 31 | }); 32 | try { 33 | mocha.run(function (failures) { 34 | if (failures > 0) { 35 | return reject({ 36 | RE_EXN_ID: TestFailure, 37 | _1: String(failures) + " tests failed." 38 | }); 39 | } else { 40 | return resolve(true); 41 | } 42 | }); 43 | return ; 44 | } 45 | catch (raw_exn){ 46 | var exn = Caml_js_exceptions.internalToOCamlException(raw_exn); 47 | console.error(exn); 48 | return reject(exn); 49 | } 50 | })); 51 | })); 52 | } 53 | 54 | exports.Mocha = Mocha$1; 55 | exports.Glob = Glob$1; 56 | exports.TestFailure = TestFailure; 57 | exports.run = run; 58 | /* glob Not a pure module */ 59 | -------------------------------------------------------------------------------- /lib/js/test/tests/Connection/Test__Connection__Process.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Js_exn = require("rescript/lib/js/js_exn.js"); 5 | var Util$AgdaModeVscode = require("../../../src/Util/Util.bs.js"); 6 | var Connection__Process$AgdaModeVscode = require("../../../src/Connection/Connection__Process.bs.js"); 7 | 8 | describe("Process Interface", (function () { 9 | describe("Use `echo` as the testing subject", (function () { 10 | it.skip("should trigger `close`", (async function () { 11 | var $$process = Connection__Process$AgdaModeVscode.make("echo", ["hello"]); 12 | var match = Util$AgdaModeVscode.Promise_.pending(); 13 | var reject = match[2]; 14 | var resolve = match[1]; 15 | var destructor = Connection__Process$AgdaModeVscode.onOutput($$process, (function (output) { 16 | switch (output.TAG) { 17 | case "Stdout" : 18 | var output$1 = output._0; 19 | switch (output$1) { 20 | case "hello\n" : 21 | case "hello\r\n" : 22 | return ; 23 | default: 24 | return reject(Js_exn.raiseError("wrong output: " + output$1)); 25 | } 26 | case "Stderr" : 27 | return resolve(Js_exn.raiseError("Stderr: " + output._0)); 28 | case "Event" : 29 | var $$event = output._0; 30 | if (typeof $$event === "object" && $$event.TAG !== "OnError" && $$event._0 === 0) { 31 | return resolve(); 32 | } 33 | return resolve(Js_exn.raiseError("Event: " + Connection__Process$AgdaModeVscode.$$Event.toString($$event))); 34 | 35 | } 36 | })); 37 | await match[0]; 38 | return destructor(); 39 | })); 40 | })); 41 | describe("Use a non-existing command as the testing subject", (function () { 42 | it("should trigger receive something from stderr", (async function () { 43 | var $$process = Connection__Process$AgdaModeVscode.make("echooo", ["hello"]); 44 | var match = Util$AgdaModeVscode.Promise_.pending(); 45 | var reject = match[2]; 46 | var resolve = match[1]; 47 | var destructor = Connection__Process$AgdaModeVscode.onOutput($$process, (function (output) { 48 | switch (output.TAG) { 49 | case "Stdout" : 50 | return reject(Js_exn.raiseError("wrong output: " + output._0)); 51 | case "Stderr" : 52 | return resolve(); 53 | case "Event" : 54 | return reject(Js_exn.raiseError("Event: " + Connection__Process$AgdaModeVscode.$$Event.toString(output._0))); 55 | 56 | } 57 | })); 58 | await match[0]; 59 | return destructor(); 60 | })); 61 | })); 62 | })); 63 | 64 | var Process; 65 | 66 | exports.Process = Process; 67 | /* Not a pure module */ 68 | -------------------------------------------------------------------------------- /lib/js/test/tests/Connection/Test__Connection__Resolver.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | 5 | describe("Path Searching", (function () { 6 | this.timeout(10000); 7 | })); 8 | 9 | /* Not a pure module */ 10 | -------------------------------------------------------------------------------- /lib/js/test/tests/Parser/Test__Parser.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("rescript/lib/js/curry.js"); 5 | var Assert = require("assert"); 6 | var Parser$AgdaModeVscode = require("../../../src/Parser/Parser.bs.js"); 7 | 8 | describe("when running Parser.escape", (function () { 9 | it("should make escaped backslash explicit", (function () { 10 | var actual = Parser$AgdaModeVscode.$$escape("\\ x -> x"); 11 | Curry._3(Assert.deepEqual, actual, "\\\\ x -> x", undefined); 12 | })); 13 | it("should make escaped newline on Unix explicit", (function () { 14 | var actual = Parser$AgdaModeVscode.$$escape("x\ny"); 15 | Curry._3(Assert.deepEqual, actual, "x\\ny", undefined); 16 | })); 17 | it("should make escaped newline on Windows explicit", (function () { 18 | var actual = Parser$AgdaModeVscode.$$escape("x\r\ny"); 19 | Curry._3(Assert.deepEqual, actual, "x\\r\\ny", undefined); 20 | })); 21 | it("should make escaped double quote explicit", (function () { 22 | var actual = Parser$AgdaModeVscode.$$escape("\"x\""); 23 | Curry._3(Assert.deepEqual, actual, "\\\"x\\\"", undefined); 24 | })); 25 | })); 26 | 27 | describe("when running Parser.unescapeEOL", (function () { 28 | it("should make explicit newline on Unix implicit", (function () { 29 | var actual = Parser$AgdaModeVscode.unescapeEOL("x\\ny"); 30 | Curry._3(Assert.deepEqual, actual, "x\ny", undefined); 31 | })); 32 | it("should make explicit newline on Windows implicit", (function () { 33 | var actual = Parser$AgdaModeVscode.unescapeEOL("x\\r\\ny"); 34 | Curry._3(Assert.deepEqual, actual, "x\r\ny", undefined); 35 | })); 36 | })); 37 | 38 | /* Not a pure module */ 39 | -------------------------------------------------------------------------------- /lib/js/test/tests/Parser/Test__Parser__Agda.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("rescript/lib/js/curry.js"); 5 | var Assert = require("assert"); 6 | var Agda$AgdaModeVscode = require("../../../src/Agda.bs.js"); 7 | var RichText$AgdaModeVscode = require("../../../src/View/Component/RichText.bs.js"); 8 | 9 | describe("when running Agda.Expr.parse", (function () { 10 | it("should parse a plain string", (function () { 11 | var expected = [{ 12 | TAG: "Plain", 13 | _0: "ℕ", 14 | [Symbol.for("name")]: "Plain" 15 | }]; 16 | var actual = Agda$AgdaModeVscode.Expr.parse("ℕ"); 17 | Curry._3(Assert.deepEqual, actual, expected, undefined); 18 | })); 19 | it("should parse a question mark", (function () { 20 | var expected = [{ 21 | TAG: "QuestionMark", 22 | _0: 3, 23 | [Symbol.for("name")]: "QuestionMark" 24 | }]; 25 | var actual = Agda$AgdaModeVscode.Expr.parse("?3"); 26 | Curry._3(Assert.deepEqual, actual, expected, undefined); 27 | })); 28 | it("should parse a underscore", (function () { 29 | var expected = [{ 30 | TAG: "Underscore", 31 | _0: "_4hi", 32 | [Symbol.for("name")]: "Underscore" 33 | }]; 34 | var actual = Agda$AgdaModeVscode.Expr.parse(" _4hi "); 35 | Curry._3(Assert.deepEqual, actual, expected, undefined); 36 | })); 37 | })); 38 | 39 | describe("when running Agda.OutputConstraint.parse", (function () { 40 | it("should parse OfType", (function () { 41 | var expected = { 42 | TAG: "OfType", 43 | _0: RichText$AgdaModeVscode.string("x"), 44 | _1: RichText$AgdaModeVscode.string("ℕ"), 45 | [Symbol.for("name")]: "OfType" 46 | }; 47 | var actual = Agda$AgdaModeVscode.OutputConstraint.parse("x : ℕ"); 48 | Curry._3(Assert.deepEqual, actual, expected, undefined); 49 | })); 50 | it("should parse JustType", (function () { 51 | var expected = { 52 | TAG: "JustType", 53 | _0: RichText$AgdaModeVscode.string("ℕ"), 54 | [Symbol.for("name")]: "JustType" 55 | }; 56 | var actual = Agda$AgdaModeVscode.OutputConstraint.parse("Type ℕ"); 57 | Curry._3(Assert.deepEqual, actual, expected, undefined); 58 | })); 59 | it("should parse JustSort on Windows", (function () { 60 | var expected = { 61 | TAG: "JustSort", 62 | _0: RichText$AgdaModeVscode.string("ℕ\r\n ℕ"), 63 | [Symbol.for("name")]: "JustSort" 64 | }; 65 | var actual = Agda$AgdaModeVscode.OutputConstraint.parse("Sort ℕ\r\n ℕ"); 66 | Curry._3(Assert.deepEqual, actual, expected, undefined); 67 | })); 68 | it("should parse JustSort on Unix", (function () { 69 | var expected = { 70 | TAG: "JustSort", 71 | _0: RichText$AgdaModeVscode.string("ℕ\n ℕ"), 72 | [Symbol.for("name")]: "JustSort" 73 | }; 74 | var actual = Agda$AgdaModeVscode.OutputConstraint.parse("Sort ℕ\n ℕ"); 75 | Curry._3(Assert.deepEqual, actual, expected, undefined); 76 | })); 77 | })); 78 | 79 | /* Not a pure module */ 80 | -------------------------------------------------------------------------------- /lib/js/test/tests/Parser/Test__Parser__Response.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Assert = require("assert"); 5 | var Parser$AgdaModeVscode = require("../../../src/Parser/Parser.bs.js"); 6 | var Response$AgdaModeVscode = require("../../../src/Response.bs.js"); 7 | var Test__Util$AgdaModeVscode = require("../Test__Util.bs.js"); 8 | var Test__Parser__SExpression$AgdaModeVscode = require("./Test__Parser__SExpression.bs.js"); 9 | 10 | function toPrioritizedResponses(exprs) { 11 | return exprs.map(Response$AgdaModeVscode.Prioritized.parse).map(function (x) { 12 | if (x.TAG === "Ok") { 13 | return [x._0]; 14 | } 15 | Assert.fail(Parser$AgdaModeVscode.$$Error.toString(x._0)); 16 | return []; 17 | }).flat(); 18 | } 19 | 20 | describe("when parsing responses", (function () { 21 | Test__Util$AgdaModeVscode.Golden.getGoldenFilepathsSync("../../../../test/tests/Parser/Response").forEach(function (filepath) { 22 | it("should golden test " + filepath, (async function () { 23 | var raw = await Test__Util$AgdaModeVscode.Golden.readFile(filepath); 24 | return Test__Util$AgdaModeVscode.Golden.compare(Test__Util$AgdaModeVscode.Golden.map(Test__Util$AgdaModeVscode.Golden.map(Test__Util$AgdaModeVscode.Golden.map(raw, (function (extra) { 25 | return Test__Parser__SExpression$AgdaModeVscode.parseSExpression([], extra); 26 | })), toPrioritizedResponses), (function (extra) { 27 | return Test__Util$AgdaModeVscode.Strings.unlinesWith(Response$AgdaModeVscode.Prioritized.toString, extra); 28 | }))); 29 | })); 30 | }); 31 | })); 32 | 33 | exports.toPrioritizedResponses = toPrioritizedResponses; 34 | /* Not a pure module */ 35 | -------------------------------------------------------------------------------- /lib/js/test/tests/Parser/Test__Parser__SExpression.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Assert = require("assert"); 5 | var Parser$AgdaModeVscode = require("../../../src/Parser/Parser.bs.js"); 6 | var Test__Util$AgdaModeVscode = require("../Test__Util.bs.js"); 7 | 8 | function parseSExpression(breakpoints, input) { 9 | var output = { 10 | contents: [] 11 | }; 12 | var parser = Parser$AgdaModeVscode.SExpression.makeIncr(function (x) { 13 | if (typeof x !== "object") { 14 | return ; 15 | } 16 | var a = x._0; 17 | if (a.TAG === "Ok") { 18 | output.contents.push(a._0); 19 | return ; 20 | } 21 | var match = a._0; 22 | Assert.fail(Parser$AgdaModeVscode.$$Error.toString({ 23 | TAG: "SExpression", 24 | _0: match[0], 25 | _1: match[1], 26 | [Symbol.for("name")]: "SExpression" 27 | })); 28 | }); 29 | Test__Util$AgdaModeVscode.Strings.breakInput(input.trim(), breakpoints).map(Parser$AgdaModeVscode.splitToLines).flat().forEach(function (extra) { 30 | return Parser$AgdaModeVscode.Incr.feed(parser, extra); 31 | }); 32 | return output.contents; 33 | } 34 | 35 | describe("when parsing S-expressions as a whole", (function () { 36 | Test__Util$AgdaModeVscode.Golden.getGoldenFilepathsSync("../../../../test/tests/Parser/SExpression").forEach(function (filepath) { 37 | it("should golden test " + filepath, (async function () { 38 | var raw = await Test__Util$AgdaModeVscode.Golden.readFile(filepath); 39 | return Test__Util$AgdaModeVscode.Golden.compare(Test__Util$AgdaModeVscode.Golden.map(Test__Util$AgdaModeVscode.Golden.map(raw, (function (extra) { 40 | return parseSExpression([], extra); 41 | })), (function (extra) { 42 | return Test__Util$AgdaModeVscode.Strings.unlinesWith(Parser$AgdaModeVscode.SExpression.toString, extra); 43 | }))); 44 | })); 45 | }); 46 | })); 47 | 48 | describe("when parsing S-expressions incrementally", (function () { 49 | Test__Util$AgdaModeVscode.Golden.getGoldenFilepathsSync("../../../../test/tests/Parser/SExpression").forEach(function (filepath) { 50 | it("should golden test " + filepath, (async function () { 51 | var raw = await Test__Util$AgdaModeVscode.Golden.readFile(filepath); 52 | return Test__Util$AgdaModeVscode.Golden.compare(Test__Util$AgdaModeVscode.Golden.map(Test__Util$AgdaModeVscode.Golden.map(raw, (function (extra) { 53 | return parseSExpression([ 54 | 3, 55 | 23, 56 | 171, 57 | 217, 58 | 1234, 59 | 2342, 60 | 3453 61 | ], extra); 62 | })), (function (extra) { 63 | return Test__Util$AgdaModeVscode.Strings.unlinesWith(Parser$AgdaModeVscode.SExpression.toString, extra); 64 | }))); 65 | })); 66 | }); 67 | })); 68 | 69 | exports.parseSExpression = parseSExpression; 70 | /* Not a pure module */ 71 | -------------------------------------------------------------------------------- /lib/js/test/tests/Test.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Config$AgdaModeVscode = require("../../src/Config.bs.js"); 5 | 6 | before(function () { 7 | Config$AgdaModeVscode.inTestingMode.contents = true; 8 | }); 9 | 10 | /* Not a pure module */ 11 | -------------------------------------------------------------------------------- /lib/js/test/tests/Test__ComputeNormalForm.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("rescript/lib/js/curry.js"); 5 | var Assert = require("assert"); 6 | var Test__Util$AgdaModeVscode = require("./Test__Util.bs.js"); 7 | var State__Connection$AgdaModeVscode = require("../../src/State/State__Connection.bs.js"); 8 | 9 | function run(normalization) { 10 | describe("request to Agda", (function () { 11 | describe("global", (function () { 12 | it("should be responded with the correct answer", (async function () { 13 | var ctx = await Test__Util$AgdaModeVscode.AgdaMode.makeAndLoad("ComputeNormalForm.agda"); 14 | var responses = await State__Connection$AgdaModeVscode.sendRequestAndCollectResponses(ctx.state, { 15 | TAG: "ComputeNormalFormGlobal", 16 | _0: normalization, 17 | _1: "Z + S Z", 18 | [Symbol.for("name")]: "ComputeNormalFormGlobal" 19 | }); 20 | var filteredResponses = responses.filter(Test__Util$AgdaModeVscode.filteredResponse); 21 | return Curry._3(Assert.deepEqual, filteredResponses, [{ 22 | TAG: "DisplayInfo", 23 | _0: { 24 | TAG: "NormalForm", 25 | _0: "S Z", 26 | [Symbol.for("name")]: "NormalForm" 27 | }, 28 | [Symbol.for("name")]: "DisplayInfo" 29 | }], undefined); 30 | })); 31 | it("should be responded with the correct answer", (async function () { 32 | var ctx = await Test__Util$AgdaModeVscode.AgdaMode.makeAndLoad("ComputeNormalForm.agda"); 33 | var responses = await State__Connection$AgdaModeVscode.sendRequestAndCollectResponses(ctx.state, { 34 | TAG: "ComputeNormalFormGlobal", 35 | _0: normalization, 36 | _1: "S Z + S Z", 37 | [Symbol.for("name")]: "ComputeNormalFormGlobal" 38 | }); 39 | var filteredResponses = responses.filter(Test__Util$AgdaModeVscode.filteredResponse); 40 | return Curry._3(Assert.deepEqual, filteredResponses, [{ 41 | TAG: "DisplayInfo", 42 | _0: { 43 | TAG: "NormalForm", 44 | _0: "S (S Z)", 45 | [Symbol.for("name")]: "NormalForm" 46 | }, 47 | [Symbol.for("name")]: "DisplayInfo" 48 | }], undefined); 49 | })); 50 | })); 51 | })); 52 | } 53 | 54 | describe("agda-mode.compute-normal-form[DefaultCompute]", (function () { 55 | run("DefaultCompute"); 56 | })); 57 | 58 | describe("agda-mode.compute-normal-form[IgnoreAbstract]", (function () { 59 | run("IgnoreAbstract"); 60 | })); 61 | 62 | exports.run = run; 63 | /* Not a pure module */ 64 | -------------------------------------------------------------------------------- /lib/js/test/tests/Test__Config.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("rescript/lib/js/curry.js"); 5 | var Assert = require("assert"); 6 | var Config$AgdaModeVscode = require("../../src/Config.bs.js"); 7 | var Connection__URI$AgdaModeVscode = require("../../src/Connection/Connection__URI.bs.js"); 8 | 9 | describe("Config", (function () { 10 | describe("Connection", (function () { 11 | describe("Paths", (function () { 12 | it("getAgdaPaths . setAgdaPaths = id", (async function () { 13 | var expected = []; 14 | await Config$AgdaModeVscode.Connection.setAgdaPaths(expected); 15 | var actual = Config$AgdaModeVscode.Connection.getAgdaPaths(); 16 | Curry._3(Assert.deepEqual, actual, expected, undefined); 17 | var expected$1 = [ 18 | "some/path", 19 | "some/other/path" 20 | ].map(Connection__URI$AgdaModeVscode.parse); 21 | await Config$AgdaModeVscode.Connection.setAgdaPaths(expected$1); 22 | var actual$1 = Config$AgdaModeVscode.Connection.getAgdaPaths(); 23 | return Curry._3(Assert.deepEqual, actual$1, expected$1, undefined); 24 | })); 25 | it("`setAgdaPaths` should remove previous paths", (async function () { 26 | await Config$AgdaModeVscode.Connection.setAgdaPaths(["some/path"].map(Connection__URI$AgdaModeVscode.parse)); 27 | var expected = ["some/other/path"].map(Connection__URI$AgdaModeVscode.parse); 28 | await Config$AgdaModeVscode.Connection.setAgdaPaths(expected); 29 | var actual = Config$AgdaModeVscode.Connection.getAgdaPaths(); 30 | return Curry._3(Assert.deepEqual, actual, expected, undefined); 31 | })); 32 | it("`addAgdaPaths` should be idempotent", (async function () { 33 | var expected = ["some/path"].map(Connection__URI$AgdaModeVscode.parse); 34 | await Config$AgdaModeVscode.Connection.setAgdaPaths(expected); 35 | await Config$AgdaModeVscode.Connection.setAgdaPaths(expected); 36 | var actual = Config$AgdaModeVscode.Connection.getAgdaPaths(); 37 | return Curry._3(Assert.deepEqual, actual, expected, undefined); 38 | })); 39 | })); 40 | })); 41 | })); 42 | 43 | /* Not a pure module */ 44 | -------------------------------------------------------------------------------- /lib/js/test/tests/Test__PromptIM.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ 3 | -------------------------------------------------------------------------------- /lib/js/test/tests/Test__Refine.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("rescript/lib/js/curry.js"); 5 | var Assert = require("assert"); 6 | var Vscode = require("vscode"); 7 | var Caml_option = require("rescript/lib/js/caml_option.js"); 8 | var Test__Util$AgdaModeVscode = require("./Test__Util.bs.js"); 9 | 10 | describe("agda-mode.refine", (function () { 11 | describe("Issue #158", (function () { 12 | var fileContent = { 13 | contents: "" 14 | }; 15 | before(async function () { 16 | fileContent.contents = await Test__Util$AgdaModeVscode.$$File.read(Test__Util$AgdaModeVscode.Path.asset("Issue158.agda")); 17 | }); 18 | after(async function () { 19 | return await Test__Util$AgdaModeVscode.$$File.write(Test__Util$AgdaModeVscode.Path.asset("Issue158.agda"), fileContent.contents); 20 | }); 21 | it("should result in the correct refinement", (async function () { 22 | var ctx = await Test__Util$AgdaModeVscode.AgdaMode.makeAndLoad("Issue158.agda"); 23 | await Test__Util$AgdaModeVscode.AgdaMode.refine(ctx, Caml_option.some(new Vscode.Position(12, 9)), undefined); 24 | var actual = await Test__Util$AgdaModeVscode.$$File.read(Test__Util$AgdaModeVscode.Path.asset("Issue158.agda")); 25 | var expected = await Test__Util$AgdaModeVscode.$$File.read(Test__Util$AgdaModeVscode.Path.asset("Issue158.agda.out")); 26 | return Curry._3(Assert.equal, actual, expected, undefined); 27 | })); 28 | })); 29 | })); 30 | 31 | /* Not a pure module */ 32 | -------------------------------------------------------------------------------- /lib/js/test/tests/Test__SolveConstraints.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("rescript/lib/js/curry.js"); 5 | var Assert = require("assert"); 6 | var Test__Util$AgdaModeVscode = require("./Test__Util.bs.js"); 7 | var State__Connection$AgdaModeVscode = require("../../src/State/State__Connection.bs.js"); 8 | 9 | function run(normalization) { 10 | var fileContent = { 11 | contents: "" 12 | }; 13 | beforeEach(async function () { 14 | fileContent.contents = await Test__Util$AgdaModeVscode.$$File.read(Test__Util$AgdaModeVscode.Path.asset("Issue204.agda")); 15 | }); 16 | afterEach(async function () { 17 | return await Test__Util$AgdaModeVscode.$$File.write(Test__Util$AgdaModeVscode.Path.asset("Issue204.agda"), fileContent.contents); 18 | }); 19 | it("should be responded with the correct responses", (async function () { 20 | var ctx = await Test__Util$AgdaModeVscode.AgdaMode.makeAndLoad("Issue204.agda"); 21 | var responses = await State__Connection$AgdaModeVscode.sendRequestAndCollectResponses(ctx.state, { 22 | TAG: "SolveConstraintsGlobal", 23 | _0: normalization, 24 | [Symbol.for("name")]: "SolveConstraintsGlobal" 25 | }); 26 | var filteredResponses = responses.filter(Test__Util$AgdaModeVscode.filteredResponse); 27 | return Curry._3(Assert.deepEqual, filteredResponses, [ 28 | { 29 | TAG: "InteractionPoints", 30 | _0: [ 31 | 0, 32 | 1 33 | ], 34 | [Symbol.for("name")]: "InteractionPoints" 35 | }, 36 | { 37 | TAG: "SolveAll", 38 | _0: [ 39 | [ 40 | 0, 41 | "4" 42 | ], 43 | [ 44 | 1, 45 | "4" 46 | ] 47 | ], 48 | [Symbol.for("name")]: "SolveAll" 49 | } 50 | ], undefined); 51 | })); 52 | it("should solve all goals", (async function () { 53 | var ctx = await Test__Util$AgdaModeVscode.AgdaMode.makeAndLoad("Issue204.agda"); 54 | await Test__Util$AgdaModeVscode.AgdaMode.solveConstraints(ctx, normalization, undefined); 55 | Curry._3(Assert.deepEqual, ctx.state.goals.length, 0, undefined); 56 | var actual = await Test__Util$AgdaModeVscode.$$File.read(Test__Util$AgdaModeVscode.Path.asset("Issue204.agda")); 57 | var expected = await Test__Util$AgdaModeVscode.$$File.read(Test__Util$AgdaModeVscode.Path.asset("Issue204.agda.out")); 58 | return Curry._3(Assert.equal, actual, expected, undefined); 59 | })); 60 | } 61 | 62 | describe("agda-mode.solve-constraints", (function () { 63 | describe("Simplified", (function () { 64 | run("Simplified"); 65 | })); 66 | describe("Normalised", (function () { 67 | run("Normalised"); 68 | })); 69 | describe("Instantiated", (function () { 70 | run("Instantiated"); 71 | })); 72 | })); 73 | 74 | exports.run = run; 75 | /* Not a pure module */ 76 | -------------------------------------------------------------------------------- /lib/js/test/tests/TextEditor/Test__LineEnding.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("rescript/lib/js/curry.js"); 5 | var Assert = require("assert"); 6 | var Vscode = require("vscode"); 7 | var Agda$AgdaModeVscode = require("../../../src/Agda.bs.js"); 8 | 9 | async function openEditorWithContent(content) { 10 | var textDocument = await Vscode.workspace.openTextDocument({ 11 | content: content, 12 | language: "agda" 13 | }); 14 | return await Vscode.window.showTextDocument(textDocument, undefined); 15 | } 16 | 17 | describe("Conversion of offsets between LF and CRLF line endings", (function () { 18 | describe("Editor.computeCRLFIndices", (function () { 19 | it("should work", (function () { 20 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.OffsetConverter.computeCRLFIndices("1234\r\n78"), [4], undefined); 21 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.OffsetConverter.computeCRLFIndices("12\r\n56\r\n90"), [ 22 | 2, 23 | 6 24 | ], undefined); 25 | })); 26 | })); 27 | describe("Editor.Indices.make", (function () { 28 | it("should work", (function () { 29 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.expose(Agda$AgdaModeVscode.Indices.make(Agda$AgdaModeVscode.OffsetConverter.computeCRLFIndices("12\r\n56\r\n90")))[0], [ 30 | [ 31 | 0, 32 | 2 33 | ], 34 | [ 35 | 3, 36 | 5 37 | ] 38 | ], undefined); 39 | })); 40 | })); 41 | describe("Editor.Indices.convert", (function () { 42 | it("should work", (function () { 43 | var a = Agda$AgdaModeVscode.Indices.make(Agda$AgdaModeVscode.OffsetConverter.computeCRLFIndices("12\r\n56\r\n90")); 44 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.convert(a, 0), 0, undefined); 45 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.expose(a)[1], 0, undefined); 46 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.convert(a, 1), 1, undefined); 47 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.expose(a)[1], 0, undefined); 48 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.convert(a, 2), 2, undefined); 49 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.expose(a)[1], 0, undefined); 50 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.convert(a, 3), 4, undefined); 51 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.expose(a)[1], 1, undefined); 52 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.convert(a, 4), 5, undefined); 53 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.expose(a)[1], 1, undefined); 54 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.convert(a, 5), 6, undefined); 55 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.expose(a)[1], 1, undefined); 56 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.convert(a, 6), 8, undefined); 57 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.expose(a)[1], 2, undefined); 58 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.convert(a, 7), 9, undefined); 59 | Curry._3(Assert.deepEqual, Agda$AgdaModeVscode.Indices.expose(a)[1], 2, undefined); 60 | })); 61 | })); 62 | })); 63 | 64 | exports.openEditorWithContent = openEditorWithContent; 65 | /* Not a pure module */ 66 | -------------------------------------------------------------------------------- /rescript.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agda-mode-vscode", 3 | "jsx": { "version": 4, "mode": "classic" }, 4 | "sources": [ 5 | { 6 | "dir": "src", 7 | "subdirs": true 8 | }, 9 | { 10 | "dir": "test", 11 | "subdirs": true, 12 | "type": "dev" 13 | } 14 | ], 15 | "package-specs": [ 16 | { 17 | "module": "commonjs", 18 | "in-source": false 19 | } 20 | ], 21 | "suffix": ".bs.js", 22 | "namespace": true, 23 | "bs-dependencies": [ 24 | "@glennsl/rescript-json-combinators", 25 | "rescript-vscode", 26 | "rescript-webapi", 27 | "rescript-nodejs", 28 | "@rescript/react", 29 | "@rescript/core" 30 | ], 31 | "bs-dev-dependencies": [ 32 | "rescript-mocha" 33 | ], 34 | "bsc-flags": [ 35 | "-open RescriptCore", 36 | "-bs-g" 37 | ], 38 | "ppx-flags": [] 39 | } -------------------------------------------------------------------------------- /src/Connection/Connection__Command.res: -------------------------------------------------------------------------------- 1 | // module for searching executables in PATH with tools like `which` or `where.exe` 2 | 3 | module Error = { 4 | type t = 5 | | NotFound(string) 6 | | SomethingWentWrong(string, Connection__Process__Exec.Error.t) 7 | | NotValidTarget(string, string, Connection__Target.Error.t) 8 | 9 | let toString = error => 10 | switch error { 11 | | NotFound(command) => "Cannot find `" ++ command ++ "` in PATH" 12 | | SomethingWentWrong(command, e) => 13 | "Cannot find `" ++ 14 | command ++ 15 | "` because: " ++ 16 | Connection__Process__Exec.Error.toString(e) ++ "." 17 | | NotValidTarget(command, path, e) => 18 | "Found `" ++ 19 | command ++ 20 | "` at `" ++ 21 | path ++ 22 | "` but it's not a valid target because: " ++ 23 | Connection__Target.Error.toString(e) 24 | } 25 | } 26 | 27 | // Instead of returning the underlying error, we return `None` as a special case when `which` or `where.exe` is working correctly but the executable is not found. 28 | let searchWith = async (command, name, ~timeout=1000) => { 29 | switch await Connection__Process__Exec.run(command, [name], ~timeout) { 30 | | Ok(stdout) => 31 | let path = String.trim(stdout) // trim the string to remove the trailing newline 32 | switch await Connection__Target.fromRawPath(path) { 33 | | Ok(target) => Ok(target) 34 | | Error(error) => Error(Error.NotValidTarget(name, path, error)) 35 | } 36 | | Error(FromStderr(Some(1), "")) => Error(NotFound(name)) 37 | | Error(FromStderr(Some(1), "INFO: Could not find files for the given pattern(s).\r\n")) => Error(NotFound(name)) 38 | | Error(error) => Error(SomethingWentWrong(name, error)) 39 | } 40 | } 41 | 42 | let search = async (name, ~timeout=1000) => { 43 | if OS.onUnix { 44 | await searchWith("which", name, ~timeout) 45 | } else { 46 | // try `which` first, then `where.exe` 47 | switch await searchWith("which", name, ~timeout) { 48 | | Ok(stdout) => Ok(stdout) 49 | | Error(_) => await searchWith("where.exe", name, ~timeout) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Connection/Connection__Download.res: -------------------------------------------------------------------------------- 1 | module Error = { 2 | type t = 3 | | CannotFetchALSReleases(Connection__Download__GitHub.Error.t) 4 | | CannotDownloadALS(Connection__Download__GitHub.Error.t) 5 | | CannotConnectToALS(Connection__Target.Error.t) 6 | | CannotFindCompatibleALSRelease 7 | 8 | let toString = x => 9 | switch x { 10 | | CannotFetchALSReleases(e) => 11 | "Cannot fetch releases of Agda Language Server: " ++ 12 | Connection__Download__GitHub.Error.toString(e) 13 | 14 | | CannotFindCompatibleALSRelease => "Cannot find compatible Agda Language Server release for download. Prebuilts are only available for download on Ubuntu, Windows, and macOS (arm64, x64).\nPlease build from source if you are on a different platform. \nSee https://github.com/agda/agda-language-server for more information." 15 | | CannotConnectToALS(e) => Connection__Target.Error.toString(e) 16 | | CannotDownloadALS(e) => 17 | "Failed download the Agda Language Server: " ++ Connection__Download__GitHub.Error.toString(e) 18 | } 19 | } 20 | 21 | let makeRepo: (State__Memento.t, VSCode.Uri.t) => Connection__Download__GitHub.Repo.t = ( 22 | memento, 23 | globalStorageUri, 24 | ) => { 25 | username: "agda", 26 | repository: "agda-language-server", 27 | userAgent: "agda/agda-mode-vscode", 28 | memento, 29 | globalStoragePath: VSCode.Uri.fsPath(globalStorageUri), 30 | cacheInvalidateExpirationSecs: 86400, 31 | } 32 | 33 | let getReleaseManifest = async (memento, globalStorageUri) => { 34 | switch await Connection__Download__GitHub.ReleaseManifest.fetch( 35 | makeRepo(memento, globalStorageUri), 36 | ) { 37 | | (Error(error), _) => Error(Error.CannotFetchALSReleases(error)) 38 | | (Ok(manifest), _) => Ok(manifest) 39 | } 40 | } 41 | 42 | // Download the given FetchSpec and return the path of the downloaded file 43 | let download = async (memento, globalStorageUri, fetchSpec) => { 44 | let reportProgress = await Connection__Download__Util.Progress.report("Agda Language Server") // 📺 45 | let globalStoragePath = VSCode.Uri.fsPath(globalStorageUri) 46 | switch await Connection__Download__GitHub.download( 47 | fetchSpec, 48 | memento, 49 | globalStoragePath, 50 | reportProgress, 51 | ) { 52 | | Error(error) => Error(Error.CannotDownloadALS(error)) 53 | | Ok(_isCached) => 54 | // add the path of the downloaded file to the config 55 | let destPath = Connection__URI.parse( 56 | NodeJs.Path.join([globalStoragePath, fetchSpec.saveAsFileName, "als"]), 57 | ) 58 | await Config.Connection.addAgdaPath(destPath) 59 | switch await Connection__Target.fromURI(destPath) { 60 | | Error(e) => Error(Error.CannotConnectToALS(e)) 61 | | Ok(target) => Ok(target) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Connection/Connection__Error.res: -------------------------------------------------------------------------------- 1 | module Aggregated = { 2 | module Attempts = { 3 | type t = { 4 | targets: array, 5 | commands: array, 6 | } 7 | 8 | let toString = attempts => { 9 | if attempts.targets->Array.length == 0 { 10 | "Tried to connect with the path from the configuration but there are none.\n" 11 | } else { 12 | "Tried to connect with the path from the configuration but all failed:\n" ++ 13 | attempts.targets 14 | ->Array.map(Connection__Target.Error.toString) 15 | ->Array.join("\n") ++ "\n" 16 | } ++ if attempts.commands->Array.length == 0 { 17 | "" 18 | } else { 19 | attempts.commands 20 | ->Array.map(Connection__Command.Error.toString) 21 | ->Array.join("\n") 22 | } 23 | } 24 | } 25 | 26 | type t = 27 | | PlatformNotSupported(Attempts.t, Connection__Download__Platform.raw) 28 | | NoDownloadALS(Attempts.t) 29 | | DownloadALS(Attempts.t, Connection__Download.Error.t) 30 | 31 | let toString = x => 32 | switch x { 33 | | PlatformNotSupported(attempts, platform) => 34 | Attempts.toString(attempts) ++ 35 | "\nTried to download the Agda Language Server but the platform `" ++ 36 | platform["os"] ++ 37 | "/" ++ 38 | platform["dist"] ++ "` is not supported.\n" 39 | 40 | | NoDownloadALS(attempts) => 41 | Attempts.toString( 42 | attempts, 43 | ) ++ "\nPrebuilt Agda Language Server available for download but you opted not to.\n" 44 | 45 | | DownloadALS(attempts, error) => 46 | Attempts.toString(attempts) ++ 47 | "\nTried to download the Agda Language Server but failed:\n" ++ 48 | Connection__Download.Error.toString(error) 49 | } 50 | } 51 | 52 | type t = 53 | | Agda(Connection__Target__Agda__Error.t, string) 54 | | ALS(Connection__Target__ALS__Error.t) 55 | | Aggregated(Aggregated.t) 56 | 57 | let toString = x => 58 | switch x { 59 | | Agda(e, _) => Connection__Target__Agda__Error.toString(e) 60 | | ALS(e) => Connection__Target__ALS__Error.toString(e) 61 | | Aggregated(e) => ("Error", Aggregated.toString(e)) 62 | } 63 | -------------------------------------------------------------------------------- /src/Connection/Connection__Scheduler.res: -------------------------------------------------------------------------------- 1 | // This module makes sure that Last Responses are handled after NonLast Responses 2 | // 3 | // There are 2 kinds of Responses 4 | // NonLast Response : 5 | // * get handled first 6 | // * don't invoke `sendAgdaRequest` 7 | // Last Response : 8 | // * have priorities, those with the smallest priority number are executed first 9 | // * only get handled: 10 | // 1. after prompt has reappeared 11 | // 2. after all NonLast Responses 12 | // 3. after all interactive highlighting is complete 13 | // * may invoke `sendAgdaRequest` 14 | module Module: { 15 | type t<'a> 16 | let make: unit => t<'a> 17 | let addLast: (t<'a>, int, Response.t) => unit 18 | let runNonLast: (t<'a>, Response.t => promise<'a>, Response.t) => unit 19 | let runLast: (t<'a>, Response.t => promise<'a>) => promise 20 | } = { 21 | type t<'a> = { 22 | // keep the number of running NonLast Response 23 | mutable tally: int, 24 | allDone: Chan.t, 25 | deferredLastResponses: array<(int, Response.t)>, 26 | } 27 | let make = () => { 28 | tally: 0, 29 | allDone: Chan.make(), 30 | deferredLastResponses: [], 31 | } 32 | // NonLast Responses should fed here 33 | let runNonLast = (self, handler, response) => { 34 | self.tally = self.tally + 1 35 | handler(response) 36 | ->Promise.finally(_ => { 37 | self.tally = self.tally - 1 38 | if self.tally == 0 { 39 | self.allDone->Chan.emit() 40 | } 41 | }) 42 | ->Promise.done 43 | } 44 | // deferred (Last) Responses are queued here 45 | let addLast = (self, priority, response) => { 46 | self.deferredLastResponses->Array.push((priority, response)) 47 | } 48 | // gets resolved once there's no NonLast Responses running 49 | let onceDone = self => 50 | if self.tally == 0 { 51 | Promise.resolve() 52 | } else { 53 | self.allDone->Chan.once 54 | } 55 | // start handling Last Responses, after all NonLast Responses have been handled 56 | let runLast = async (self, handler) => { 57 | await self->onceDone 58 | // sort the deferred Responses by priority (ascending order) 59 | let deferredLastResponses = { 60 | self.deferredLastResponses->Array.sort((x, y) => Int.compare(fst(x), fst(y))) 61 | self.deferredLastResponses->Array.map(snd) 62 | } 63 | 64 | // insert `CompleteHighlightingAndMakePromptReappear` after handling Last Responses 65 | deferredLastResponses->Array.unshift(Response.CompleteHighlightingAndMakePromptReappear) 66 | 67 | let _ = 68 | await deferredLastResponses->Array.map(res => () => handler(res))->Util.Promise_.oneByOne 69 | } 70 | } 71 | 72 | include Module 73 | -------------------------------------------------------------------------------- /src/Connection/Connection__TCP.res: -------------------------------------------------------------------------------- 1 | open NodeJs.Net 2 | module Error = { 3 | type t = 4 | | Timeout(int) 5 | | OnError(Js.Exn.t) 6 | 7 | let toString = x => 8 | switch x { 9 | | Timeout(timeout) => "Expected to connect within " ++ string_of_int(timeout) ++ "ms" 10 | | OnError(exn) => Util.JsError.toString(exn) 11 | } 12 | } 13 | 14 | // see if the TCP port is available 15 | let probe = (url: NodeJs.Url.t, ~timeout=1000) => { 16 | let connection = Promise.make((resolve, _) => { 17 | // connect and resolve `Ok()` on success 18 | let socket = NodeJs.Net.TcpSocket.make() 19 | 20 | socket 21 | ->NodeJs.Net.TcpSocket.connect(~port=url.port, ~host=url.hostname, () => ()) 22 | ->NodeJs.Net.Socket.onConnectOnce(() => { 23 | // destroy the connection afterwards 24 | Socket.destroy(socket, ~error=None)->ignore 25 | resolve(Ok()) 26 | }) 27 | ->NodeJs.Net.Socket.onErrorOnce(exn => resolve(Error(Error.OnError(exn)))) 28 | ->NodeJs.Net.Socket.onTimeoutOnce(() => resolve(Error(Timeout(timeout)))) 29 | ->ignore 30 | }) 31 | 32 | let timeout = async () => { 33 | await Util.Promise_.setTimeout(timeout) 34 | Error(Error.Timeout(timeout)) 35 | } 36 | 37 | Promise.race([connection, timeout()]) 38 | } 39 | -------------------------------------------------------------------------------- /src/Connection/Connection__URI.res: -------------------------------------------------------------------------------- 1 | @module external untildify: string => string = "untildify" 2 | 3 | type t = Filepath(string) | URL(NodeJs.Url.t) 4 | 5 | // trying to parse a raw path as a URL or else a file path 6 | let parse = path => { 7 | let result = try Some(NodeJs.Url.make(path)) catch { 8 | | _ => None 9 | } 10 | // single out the URL with the protocol "lsp:" 11 | let result = switch result { 12 | | Some(url) => 13 | if url.protocol == "lsp:" { 14 | Some(url) 15 | } else { 16 | None 17 | } 18 | | None => None 19 | } 20 | // only treat URLs with the protocol "lsp:" as URLs 21 | switch result { 22 | | Some(url) => URL(url) 23 | | None => 24 | // normailize the path by replacing the tild "~/" with the absolute path of home directory 25 | let path = untildify(path) 26 | let path = NodeJs.Path.normalize(path) 27 | 28 | // on Windows, paths that start with a drive letter like "/c/path/to/agda" will be converted to "c:/path/to/agda" 29 | let path = if OS.onUnix { 30 | path 31 | } else { 32 | path->String.replaceRegExp(%re("/^\\([a-zA-Z])\\/"), "$1\:\\") 33 | } 34 | Filepath(path) 35 | } 36 | } 37 | 38 | let toString = path => 39 | switch path { 40 | | Filepath(path) => NodeJs.Path.normalize(path) 41 | | URL(url) => url.toString() 42 | } 43 | 44 | let equal = (x, y) => 45 | switch (x, y) { 46 | | (Filepath(x), Filepath(y)) => x == y 47 | | (URL(x), URL(y)) => x.toString() == y.toString() 48 | | _ => false 49 | } 50 | -------------------------------------------------------------------------------- /src/Connection/Download/Connection__Download__Platform.res: -------------------------------------------------------------------------------- 1 | // module for determining the which OS the user is using 2 | // see https://github.com/retrohacker/getos for more 3 | 4 | // Platforms with prebuilt executables for download 5 | type raw = {"os": string, "dist": string, "codename": string, "release": string} 6 | type t = Windows | Ubuntu | MacOS_Arm | MacOS_Intel 7 | 8 | // binding to the getos module 9 | @module 10 | external getos: (('e, raw) => unit) => unit = "getos" 11 | 12 | // determine the OS the user is using, returns None if the OS is not supported for downloading prebuilt executables 13 | let determine = (): promise> => 14 | Promise.make((resolve, _) => { 15 | getos((error, raw) => { 16 | switch Js.Nullable.toOption(error) { 17 | | Some(_) => resolve(Error(raw)) 18 | | None => 19 | switch NodeJs.Os.platform() { 20 | | "darwin" => 21 | switch NodeJs.Os.arch() { 22 | | "x64" => resolve(Ok(MacOS_Intel)) 23 | | "arm64" => resolve(Ok(MacOS_Arm)) 24 | | _ => resolve(Error(raw)) 25 | } 26 | | "linux" => 27 | switch raw["dist"] { 28 | | "Ubuntu" => resolve(Ok(Ubuntu)) 29 | | _ => resolve(Error(raw)) 30 | } 31 | | "win32" => resolve(Ok(Windows)) 32 | | _ => resolve(Error(raw)) 33 | } 34 | } 35 | }) 36 | }) 37 | 38 | let toAssetName = platform => 39 | switch platform { 40 | | Windows => "windows" 41 | | Ubuntu => "ubuntu" 42 | | MacOS_Arm => "macos-arm64" 43 | | MacOS_Intel => "macos-x64" 44 | } 45 | -------------------------------------------------------------------------------- /src/Connection/Download/Connection__Download__Unzip.res: -------------------------------------------------------------------------------- 1 | // module for unzipping downloaded files 2 | module Unzipper = { 3 | @module("unzipper") 4 | external extract: {"path": string} => NodeJs.Fs.WriteStream.t = "Extract" 5 | } 6 | 7 | let run = (src, dest) => 8 | Promise.make((resolve, _) => { 9 | // resolve the promise after the read stream has been closed by the Unzipper 10 | let readStream = NodeJs.Fs.createReadStream(src) 11 | readStream->NodeJs.Fs.ReadStream.onCloseOnce(resolve)->ignore 12 | 13 | // start unzipping the file 14 | readStream->NodeJs.Fs.ReadStream.pipe(Unzipper.extract({"path": dest}))->ignore 15 | }) 16 | -------------------------------------------------------------------------------- /src/Connection/Process/Connection__Process__Exec.res: -------------------------------------------------------------------------------- 1 | module Process = Connection__Process 2 | 3 | // module for validating a given path 4 | module Error = { 5 | type t = 6 | | PathMalformed(string) 7 | | // the process has not been responding for 20 seconds 8 | ProcessHanging 9 | // error from the shell 10 | | NotFound(string) 11 | // error from the process' stderr 12 | | FromStderr(option, string) 13 | // from the process' `error` event 14 | | FromOnError(string) 15 | // wrong invoked command 16 | let toString = x => 17 | switch x { 18 | | PathMalformed(msg) => "path malformed: " ++ msg 19 | | ProcessHanging => "process hanging for more than 1 sec" 20 | 21 | | NotFound(_) => "command not found" 22 | | FromStderr(None, msg) => "stderr: \"" ++ msg ++ "\"" 23 | | FromStderr(Some(exitCode), msg) => 24 | "stderr: \"" ++ msg ++ "\" with exit code: " ++ string_of_int(exitCode) 25 | | FromOnError(msg) => "on error: " ++ msg 26 | } 27 | } 28 | 29 | let run = async (path, args, ~timeout=10000): result<'a, Error.t> => { 30 | let process = Process.make(path, args) 31 | let (promise, resolve, _) = Util.Promise_.pending() 32 | 33 | // the path must not be empty 34 | if path == "" { 35 | resolve(Error(Error.PathMalformed("the path must not be empty"))) 36 | } 37 | 38 | // reject if the process hasn't responded for more than `timeout` milliseconds 39 | let hangTimeout = ref( 40 | Some(Js.Global.setTimeout(() => resolve(Error(Error.ProcessHanging)), timeout)), 41 | ) 42 | 43 | let stdout = ref("") 44 | let stderr = ref("") 45 | let destructor = process->Process.onOutput(output => { 46 | // clear timeout as the process has responded 47 | switch hangTimeout.contents { 48 | | Some(timeout) => Js.Global.clearTimeout(timeout) 49 | | None => () 50 | } 51 | 52 | switch output { 53 | | Process.Stdout(output) => stdout := stdout.contents ++ output 54 | | Process.Stderr(output) => stderr := stderr.contents ++ output 55 | | Process.Event(OnDestroyed) => resolve(Ok(stdout.contents)) 56 | | Process.Event(OnExit(0)) => resolve(Ok(stdout.contents)) 57 | | Process.Event(OnExit(127)) => resolve(Error(Error.NotFound(path))) 58 | | Process.Event(OnExit(code)) => 59 | if Process.errorMessageIndicatesNotFound(stderr.contents) { 60 | resolve(Error(Error.NotFound(path))) 61 | } else { 62 | resolve(Error(FromStderr(Some(code), stderr.contents))) 63 | } 64 | | Process.Event(OnError(msg)) => 65 | if msg != "" { 66 | if Process.errorMessageIndicatesNotFound(msg) { 67 | resolve(Error(Error.NotFound(path))) 68 | } else { 69 | resolve(Error(FromOnError(msg))) 70 | } 71 | } else if stderr.contents != "" { 72 | if Process.errorMessageIndicatesNotFound(stderr.contents) { 73 | resolve(Error(Error.NotFound(path))) 74 | } else { 75 | resolve(Error(FromStderr(None, stderr.contents))) 76 | } 77 | } else { 78 | resolve(Ok(stdout.contents)) 79 | } 80 | } 81 | }) 82 | 83 | let result = await promise 84 | destructor() 85 | result 86 | } 87 | -------------------------------------------------------------------------------- /src/Connection/Target/ALS/Connection__Target__ALS__Error.res: -------------------------------------------------------------------------------- 1 | // TODO: sort these errors out 2 | // Errors when sending Command to the server 3 | module CommandErr = { 4 | type t = 5 | | CannotDecodeJSON(string) 6 | | CannotParseCommand(string) 7 | 8 | let toString = x => 9 | switch x { 10 | | CannotDecodeJSON(s) => "Cannot decode JSON: \n" ++ s 11 | | CannotParseCommand(s) => "Cannot read IOTCM: \n" ++ s 12 | } 13 | 14 | let decode = { 15 | open JsonCombinators.Json.Decode 16 | Util.Decode.sum(x => { 17 | switch x { 18 | | "CmdErrCannotDecodeJSON" => Payload(string->map(version => CannotDecodeJSON(version))) 19 | | "CmdErrCannotParseCommand" => Payload(string->map(version => CannotParseCommand(version))) 20 | | tag => 21 | raise(DecodeError("[Connection.Target.ALS.Error.CommandErr] Unknown constructor: " ++ tag)) 22 | } 23 | }) 24 | } 25 | } 26 | 27 | type t = 28 | // the found program is not ALS 29 | | Validation(string) 30 | // Errors from the LSP client 31 | | ConnectionError(Js.Exn.t) 32 | // Errors when sending Command to the server 33 | | SendCommand(CommandErr.t) 34 | // Cannot initialize the connection 35 | | Initialize 36 | // Parsing / Decoding 37 | | CannotDecodeCommandRes(string, JSON.t) 38 | | CannotDecodeResponse(string, JSON.t) 39 | // S-expression parse error 40 | | ResponseParseError(Parser.Error.t) 41 | 42 | let toString = error => 43 | switch error { 44 | | ConnectionError(exn) => 45 | let isECONNREFUSED = 46 | Js.Exn.message(exn)->Option.mapOr(false, String.startsWith("connect ECONNREFUSED", ...)) 47 | 48 | isECONNREFUSED 49 | ? ("Connection Error", "Please enter \":main -d\" in ghci") 50 | : ("Client Internal Connection Error", Js.Exn.message(exn)->Option.getOr("")) 51 | | SendCommand(e) => ("Cannot Send Command", CommandErr.toString(e)) 52 | | Initialize => ("Cannot Initialize Connection", "") 53 | | CannotDecodeCommandRes(msg, json) => ( 54 | "Cannot Send Command", 55 | "Cannot decode the result after sending command" ++ msg ++ "\n" ++ JSON.stringify(json), 56 | ) 57 | | CannotDecodeResponse(msg, json) => ( 58 | "Cannot Parse Response", 59 | "Cannot decode responses from the server" ++ msg ++ "\n" ++ JSON.stringify(json), 60 | ) 61 | | ResponseParseError(e) => ("Internal Parse Error", Parser.Error.toString(e)) 62 | | Validation(msg) => ("Validation Error", msg) 63 | } 64 | -------------------------------------------------------------------------------- /src/Connection/Target/Agda/Connection__Target__Agda__Error.res: -------------------------------------------------------------------------------- 1 | module Process = Connection__Process 2 | 3 | type t = 4 | | ConnectionViaTCPNotSupported 5 | // Child process related error 6 | | Process(Process.Event.t) 7 | // Agda is not happy 8 | | AgdaError(string) 9 | // S-expression parse error 10 | | ResponseParseError(Parser.Error.t) 11 | 12 | let toString = x => 13 | switch x { 14 | | ConnectionViaTCPNotSupported => ("Connection Error", "Connection via TCP not supported yet") 15 | | Process(e) => ("Process Error", Process.Event.toString(e)) 16 | | AgdaError(s) => ("Agda Error", s) 17 | | ResponseParseError(e) => ("Internal Parse Error", Parser.Error.toString(e)) 18 | } 19 | -------------------------------------------------------------------------------- /src/Connection/Target/Connection__Target__IPC.res: -------------------------------------------------------------------------------- 1 | // Means of Inter-process communication 2 | type t = 3 | | ViaPipe( 4 | string, 5 | array, 6 | option, 7 | ) // command, args, options 8 | | ViaTCP(NodeJs.Url.t) 9 | -------------------------------------------------------------------------------- /src/Highlighting/Highlighting__Decoration.res: -------------------------------------------------------------------------------- 1 | // https://www.gnu.org/software/emacs/manual/html_node/emacs/Faces.html 2 | type face = 3 | | Background(string) 4 | | Foreground(string) 5 | 6 | type t = { 7 | light: face, 8 | dark: face, 9 | } 10 | 11 | let toVSCodeDecorations = (input: array<(t, VSCode.Range.t)>, editor: VSCode.TextEditor.t): array<( 12 | Editor.Decoration.t, 13 | array, 14 | )> => { 15 | // dictionaries of color-ranges mapping 16 | // speed things up by aggregating decorations of the same kind 17 | let backgroundColorDict: Dict.t> = Dict.make() 18 | let foregroundColorDict: Dict.t> = Dict.make() 19 | 20 | let addFaceToDict = (face: face, range) => 21 | switch face { 22 | | Background(color) => 23 | switch Dict.get(backgroundColorDict, color) { 24 | | None => Dict.set(backgroundColorDict, color, [range]) 25 | | Some(ranges) => ranges->Array.push(range) 26 | } 27 | | Foreground(color) => 28 | switch Dict.get(foregroundColorDict, color) { 29 | | None => Dict.set(foregroundColorDict, color, [range]) 30 | | Some(ranges) => ranges->Array.push(range) 31 | } 32 | } 33 | 34 | // convert Aspects to colors and collect them in the dict 35 | input->Array.forEach((({light, dark}, range)) => { 36 | let theme = VSCode.Window.activeColorTheme->VSCode.ColorTheme.kind 37 | if theme == VSCode.ColorThemeKind.Dark { 38 | addFaceToDict(dark, range) 39 | } else { 40 | addFaceToDict(light, range) 41 | } 42 | }) 43 | 44 | // decorate with colors stored in the dicts 45 | let backgroundDecorations = 46 | Dict.toArray(backgroundColorDict)->Array.map(((color, ranges)) => ( 47 | Editor.Decoration.highlightBackgroundWithColor(editor, color, ranges), 48 | ranges, 49 | )) 50 | let foregroundDecorations = 51 | Dict.toArray(foregroundColorDict)->Array.map(((color, ranges)) => ( 52 | Editor.Decoration.decorateTextWithColor(editor, color, ranges), 53 | ranges, 54 | )) 55 | // return decorations 56 | Array.concat(foregroundDecorations, backgroundDecorations) 57 | } 58 | -------------------------------------------------------------------------------- /src/Node/N.res: -------------------------------------------------------------------------------- 1 | /* Node.js bindings */ 2 | 3 | exception Exception(Js.Exn.t) 4 | 5 | module Net = Node__Net 6 | module Util = Node__Util 7 | module Fs = Node__Fs 8 | -------------------------------------------------------------------------------- /src/Node/Node__Fs.res: -------------------------------------------------------------------------------- 1 | @module("fs") 2 | external readdir: (string, (Js.nullable, array) => unit) => unit = "readdir" 3 | 4 | @module("fs") 5 | external access: (string, Js.null => unit) => unit = "access" 6 | 7 | @module("fs") 8 | external unlink: (string, Js.nullable => unit) => unit = "unlink" 9 | 10 | let readFile = async filepath => { 11 | let fileHandle = await NodeJs.Fs.open_(filepath, NodeJs.Fs.Flag.read) 12 | let buffer = await NodeJs.Fs.FileHandle.readFile(fileHandle) 13 | await NodeJs.Fs.FileHandle.close(fileHandle) 14 | NodeJs.Buffer.toString(buffer) 15 | } 16 | -------------------------------------------------------------------------------- /src/Node/Node__Net.res: -------------------------------------------------------------------------------- 1 | module Socket = { 2 | type t 3 | // methods 4 | @send external destroy: t => t = "destroy" 5 | // events 6 | @send 7 | external on: (t, @string [#error(Js.Exn.t => unit) | #timeout(unit => unit)]) => t = "on" 8 | } 9 | 10 | @module("net") 11 | external connect: (int, unit => unit) => Socket.t = "connect" 12 | -------------------------------------------------------------------------------- /src/Node/Node__Util.res: -------------------------------------------------------------------------------- 1 | @module("util") 2 | external promisify: (('a, (Js.nullable, 'b) => unit) => unit, 'a) => promise<'b> = 3 | "promisify" 4 | -------------------------------------------------------------------------------- /src/Registry.res: -------------------------------------------------------------------------------- 1 | module Module: { 2 | module Entry: { 3 | type t = { 4 | mutable state: option, 5 | semanticTokens: Resource.t>, 6 | } 7 | } 8 | 9 | let getState: string => option 10 | let getEntry: string => option 11 | let getAllStates: unit => array 12 | let add: (string, State.t) => unit 13 | let remove: string => unit 14 | let removeAndDestroy: string => promise 15 | let removeAndDestroyAll: unit => promise 16 | let isEmpty: unit => bool 17 | 18 | let requestSemanticTokens: string => promise> 19 | } = { 20 | module Entry = { 21 | type tokens = array 22 | 23 | type t = { 24 | mutable state: option, 25 | semanticTokens: Resource.t, 26 | } 27 | 28 | // create a new Entry and also return with a pending promise for SemanticTokens 29 | let make = state => 30 | switch state { 31 | | None => {state: None, semanticTokens: Resource.make()} 32 | | Some(state: State.t) => 33 | let semanticTokens = state.highlighting->Highlighting.getSemanticTokens 34 | { 35 | state: Some(state), 36 | semanticTokens, 37 | } 38 | } 39 | } 40 | 41 | // FileName-Entry Registry 42 | let dict: Dict.t = Dict.make() 43 | 44 | let getEntry = fileName => dict->Dict.get(fileName) 45 | let getState = fileName => getEntry(fileName)->Option.flatMap(x => x.state) 46 | 47 | // Get all existing States 48 | let getAllStates = () => dict->Dict.valuesToArray->Array.filterMap(getEntry => getEntry.state) 49 | 50 | // Adds an instantiated State to the Registry 51 | let add = (fileName, state: State.t) => 52 | switch getEntry(fileName) { 53 | | None => 54 | // entry not found, create a new one 55 | dict->Dict.set(fileName, Entry.make(Some(state))) 56 | | Some(entry) => 57 | switch entry.state { 58 | | Some(state) => entry.state = Some(state) // update the state 59 | | None => 60 | dict->Dict.set(fileName, Entry.make(Some(state))) 61 | } 62 | } 63 | 64 | // Removes the entry (but without triggering State.destroy() ) 65 | let remove = fileName => Dict.delete(dict, fileName) 66 | 67 | let removeAndDestroy = async fileName => 68 | switch getEntry(fileName) { 69 | | None => () 70 | | Some(entry) => 71 | remove(fileName) 72 | entry.state->Option.forEach(state => State.destroy(state, false)->ignore) 73 | } 74 | 75 | let removeAndDestroyAll = async () => { 76 | let _ = 77 | await dict 78 | ->Dict.keysToArray 79 | ->Array.map(pair => () => removeAndDestroy(pair)) 80 | ->Util.Promise_.oneByOne 81 | } 82 | 83 | let isEmpty = () => Dict.keysToArray(dict)->Array.length == 0 84 | 85 | // Requesting Semantic Tokens 86 | let requestSemanticTokens = async fileName => { 87 | switch getEntry(fileName) { 88 | | Some(entry) => 89 | let tokens = await entry.semanticTokens->Resource.get 90 | tokens 91 | | None => 92 | // entry not found, create a new one 93 | let entry = Entry.make(None) 94 | dict->Dict.set(fileName, entry) 95 | let tokens = await entry.semanticTokens->Resource.get 96 | tokens 97 | } 98 | } 99 | 100 | // let provideSemanticTokens = tokens => 101 | // switch getEntry(tokens.fileName) { 102 | // | Some(entry) => 103 | // entry.semanticTokens->Option.forEach(semanticTokens => semanticTokens(tokens)) 104 | // entry.state->Option.forEach(state => State.provideSemanticTokens(state, tokens)) 105 | // | None => 106 | // // entry not found, create a new one 107 | // let (entry, _) = Entry.make(Some(tokens.state)) 108 | // dict->Dict.set(tokens.fileName, entry) 109 | // entry.semanticTokens->Option.forEach(semanticTokens => semanticTokens(tokens)) 110 | // } 111 | } 112 | 113 | include Module 114 | -------------------------------------------------------------------------------- /src/Resource.res: -------------------------------------------------------------------------------- 1 | // Module for representing a resource that may be acquired immediately or later. 2 | module Module: { 3 | type t<'a> 4 | let make: unit => t<'a> 5 | let get: t<'a> => promise<'a> 6 | let set: (t<'a>, 'a) => unit 7 | } = { 8 | type state<'a> = 9 | | Pending(promise<'a>, 'a => unit) 10 | | Acquired('a) 11 | type t<'a> = {mutable state: state<'a>} 12 | 13 | let make = () => { 14 | let (promise, resolve, _) = Util.Promise_.pending() 15 | {state: Pending(promise, resolve)} 16 | } 17 | 18 | let get = async self => { 19 | switch self.state { 20 | | Pending(promise, _) => await promise 21 | | Acquired(value) => value 22 | } 23 | } 24 | 25 | let set = (self, value) => { 26 | switch self.state { 27 | | Pending(_, resolve) => 28 | resolve(value) 29 | self.state = Acquired(value) 30 | | Acquired(_) => self.state = Acquired(value) // update the value 31 | } 32 | } 33 | } 34 | 35 | include Module 36 | -------------------------------------------------------------------------------- /src/State/State__Connection.res: -------------------------------------------------------------------------------- 1 | let askUserAboutDownloadPolicy = async () => { 2 | let messageOptions = { 3 | VSCode.MessageOptions.modal: true, 4 | detail: "Do you want to download and install the latest Agda Language Server?", 5 | } 6 | let result = await VSCode.Window.showWarningMessageWithOptions( 7 | "Cannot find Agda or Agda Language Server", 8 | messageOptions, 9 | [Config.Connection.DownloadPolicy.toString(Yes), Config.Connection.DownloadPolicy.toString(No)], 10 | ) // 📺 11 | 12 | // parse the result 13 | result->Option.mapOr( 14 | Config.Connection.DownloadPolicy.No, 15 | Config.Connection.DownloadPolicy.fromString, 16 | ) 17 | } 18 | 19 | let sendRequest = async ( 20 | state: State.t, 21 | handleResponse: Response.t => promise, 22 | request: Request.t, 23 | ): unit => { 24 | let sendRequestAndHandleResponses = async ( 25 | connection, 26 | state: State.t, 27 | request, 28 | handler: Response.t => promise, 29 | ) => { 30 | let onResponse = async response => { 31 | await handler(response) 32 | state.channels.log->Chan.emit(ResponseHandled(response)) 33 | } 34 | 35 | state.channels.log->Chan.emit(RequestSent(request)) 36 | // only resolve the promise after: 37 | // 1. the result of connection has been displayed 38 | // 2. all responses have been handled 39 | switch await Connection.sendRequest(connection, state.document, request, onResponse) { 40 | | Error(error) => await State__View.Panel.displayConnectionError(state, error) 41 | | Ok(status) => 42 | // display the connection status 43 | await State__View.Panel.displayConnectionStatus(state, status) 44 | // update the Agda version 45 | switch status { 46 | | Agda(version, _) => state.agdaVersion = Some(version) 47 | | ALS(_alsVersion, agdaVersion, _) => state.agdaVersion = Some(agdaVersion) 48 | } 49 | } 50 | } 51 | 52 | switch state.connection { 53 | | None => 54 | let platform = await Connection__Download__Platform.determine() 55 | switch await Connection.make( 56 | state.memento, 57 | Config.Connection.getAgdaPaths(), 58 | ["als", "agda"], 59 | platform, 60 | askUserAboutDownloadPolicy, 61 | Connection.LatestALS.alreadyDownloaded(state.globalStorageUri), 62 | Connection.LatestALS.download(state.memento, state.globalStorageUri), 63 | ) { 64 | | Error(error) => await State__View.Panel.displayConnectionError(state, error) 65 | | Ok(connection) => 66 | state.connection = Some(connection) 67 | await sendRequestAndHandleResponses(connection, state, request, handleResponse) 68 | } 69 | | Some(connection) => 70 | await sendRequestAndHandleResponses(connection, state, request, handleResponse) 71 | } 72 | } 73 | 74 | // like `sendRequest` but collects all responses, for testing 75 | let sendRequestAndCollectResponses = async (state: State.t, request: Request.t): array< 76 | Response.t, 77 | > => { 78 | let responses = ref([]) 79 | let responseHandler = async response => { 80 | responses.contents->Array.push(response) 81 | } 82 | await state->sendRequest(responseHandler, request) 83 | responses.contents 84 | } 85 | -------------------------------------------------------------------------------- /src/State/State__Memento.res: -------------------------------------------------------------------------------- 1 | module Any: { 2 | type t 3 | } = { 4 | type t 5 | } 6 | 7 | // Binds to VSCode.Memento when VSCode.ExtensionContext is available 8 | // Binds to a mock when testing 9 | module Module: { 10 | type t 11 | // constructor 12 | let make: option => t 13 | // primitive operations 14 | let get: (t, string) => option<'a> 15 | let getWithDefault: (t, string, 'a) => 'a 16 | let keys: t => array 17 | let set: (t, string, 'a) => promise 18 | // for debugging 19 | let toString: t => string 20 | } = { 21 | type t = Memento(VSCode.Memento.t) | Mock(Dict.t) 22 | 23 | let make = memento => 24 | switch memento { 25 | | Some(memento) => Memento(memento) 26 | | None => Mock(Dict.make()) 27 | } 28 | 29 | let get = (context, key) => 30 | switch context { 31 | | Memento(context) => VSCode.Memento.get(context, key) 32 | | Mock(dict) => Obj.magic(dict->Dict.get(key)) 33 | } 34 | let getWithDefault = (context, key, defaultValue) => 35 | switch context { 36 | | Memento(context) => VSCode.Memento.getWithDefault(context, key, defaultValue) 37 | | Mock(dict) => 38 | switch dict->Dict.get(key) { 39 | | Some(value) => Obj.magic(value) 40 | | None => defaultValue 41 | } 42 | } 43 | 44 | let keys = context => 45 | switch context { 46 | | Memento(context) => VSCode.Memento.keys(context) 47 | | Mock(dict) => dict->Dict.keysToArray 48 | } 49 | 50 | let set = (context, key, value) => 51 | switch context { 52 | | Memento(context) => VSCode.Memento.update(context, key, value) 53 | | Mock(dict) => dict->Dict.set(key, Obj.magic(value))->Promise.resolve 54 | } 55 | 56 | let toString = context => 57 | switch context { 58 | | Memento(context) => 59 | let entries = VSCode.Memento.keys(context)->Array.map(key => { 60 | switch VSCode.Memento.get(context, key) { 61 | | None => key ++ ": None" 62 | | Some(value) => key ++ ": " ++ value 63 | } 64 | }) 65 | "Memento: {\n" ++ Array.join(entries, "\n") ++ "}" 66 | | Mock(dict) => 67 | let entries = 68 | dict 69 | ->Dict.toArray 70 | ->Array.map(((key, value)) => { 71 | key ++ ": " ++ value->Obj.magic->Js.String.make 72 | }) 73 | "Mock: {\n" ++ Array.join(entries, "\n") ++ "}" 74 | } 75 | } 76 | 77 | include Module 78 | -------------------------------------------------------------------------------- /src/Util/AVLTree.res: -------------------------------------------------------------------------------- 1 | module Node = { 2 | type t<'a> 3 | @send external getValue: t<'a> => 'a = "getValue" 4 | } 5 | 6 | type t<'a> 7 | 8 | //////////////////////////////////////////////////////////////////////////////// 9 | // Constructor 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | @module("@datastructures-js/binary-search-tree") @new 13 | external make: unit => t<'a> = "BinarySearchTree" 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // Methods 17 | //////////////////////////////////////////////////////////////////////////////// 18 | 19 | @send external count: t<'a> => int = "count" 20 | 21 | @send external insert: (t<'a>, int, 'a) => unit = "insert" 22 | 23 | @send external has: (t<'a>, int) => bool = "has" 24 | 25 | @send external find: (t<'a>, int) => Nullable.t> = "find" 26 | let find = (self: t<'a>, key: int): option<'a> => 27 | self->find(key)->Nullable.toOption->Option.map(Node.getValue) 28 | 29 | @send external max: t<'a> => Nullable.t> = "max" 30 | let max = (self: t<'a>): option<'a> => self->max->Nullable.toOption->Option.map(Node.getValue) 31 | 32 | @send external min: t<'a> => Nullable.t> = "min" 33 | let min = (self: t<'a>): option<'a> => self->min->Nullable.toOption->Option.map(Node.getValue) 34 | 35 | @send external upperBound: (t<'a>, int) => Nullable.t> = "upperBound" 36 | let upperBound = (self: t<'a>, key: int): option<'a> => 37 | self->upperBound(key)->Nullable.toOption->Option.map(Node.getValue) 38 | 39 | @send external lowerBound: (t<'a>, int) => Nullable.t> = "lowerBound" 40 | let lowerBound = (self: t<'a>, key: int): option<'a> => 41 | self->lowerBound(key)->Nullable.toOption->Option.map(Node.getValue) 42 | 43 | @send external floor: (t<'a>, int) => Nullable.t> = "floor" 44 | let floor = (self: t<'a>, key: int): option<'a> => 45 | self->floor(key)->Nullable.toOption->Option.map(Node.getValue) 46 | 47 | @send external ceil: (t<'a>, int) => Nullable.t> = "ceil" 48 | let ceil = (self: t<'a>, key: int): option<'a> => 49 | self->ceil(key)->Nullable.toOption->Option.map(Node.getValue) 50 | 51 | @send external remove: (t<'a>, int) => bool = "remove" 52 | 53 | @send external clear: t<'a> => unit = "clear" 54 | 55 | @send external traverseInOrder: (t<'a>, Node.t<'a> => unit) => unit = "traverseInOrder" 56 | 57 | let toArray = (self: t<'a>): array<'a> => { 58 | let accum = [] 59 | self->traverseInOrder(node => { 60 | let value = node->Node.getValue 61 | accum->Array.push(value) 62 | }) 63 | accum 64 | } 65 | -------------------------------------------------------------------------------- /src/Util/OS.res: -------------------------------------------------------------------------------- 1 | // NOTE: cannot be used in the View module 2 | let onUnix = switch NodeJs.Os.platform() { 3 | | "win32" => false 4 | | _ => true 5 | } 6 | -------------------------------------------------------------------------------- /src/View/Component/Item.res: -------------------------------------------------------------------------------- 1 | open React 2 | 3 | type t = 4 | | Labeled(string, string, RichText.t, option, option) // label // style // body // raw string // range 5 | | Unlabeled(RichText.t, option, option) // body // raw string // range 6 | | Header(string) //

7 | 8 | let plainText = s => Unlabeled(RichText.string(s), None, None) 9 | let error = (s, raw) => Labeled("Error", "error", s, raw, None) 10 | let warning = (s, raw) => Labeled("Warning", "warning", s, raw, None) 11 | 12 | @react.component 13 | let make = (~item: t) => { 14 | let (revealRaw, setRevealRaw) = React.useState(_ => false) 15 | 16 | let onClickRevealRaw = _ => setRevealRaw(state => !state) 17 | 18 | let content = (value, raw) => 19 | switch raw { 20 | | Some(raw) => revealRaw ? : 21 | | None => 22 | } 23 | let revealRawButton = raw => 24 | switch raw { 25 | | Some(_) => 26 | revealRaw 27 | ?
28 |
29 |
30 | :
31 |
32 |
33 | | None => <> 34 | } 35 | let locationButton = location => 36 | switch location { 37 | | Some(location) => 38 | 39 |
40 | 41 | | None => <> 42 | } 43 | switch item { 44 | | Labeled(label, style, text, raw, _range) => 45 |
  • 46 |
    {string(label)}
    47 |
    {content(text, raw)}
    48 | {revealRawButton(raw)} 49 |
  • 50 | | Unlabeled(text, raw, range) => 51 |
  • 52 |
    {content(text, raw)}
    53 | {revealRawButton(raw)} 54 | {locationButton(range)} 55 |
  • 56 | // | HorizontalRule =>
  • 57 | | Header(s) => 58 |
  • 59 |

    {string(s)}

    60 |
  • 61 | } 62 | } 63 | 64 | let decode = { 65 | open! JsonCombinators.Json.Decode 66 | Util.Decode.sum(x => 67 | switch x { 68 | | "Labeled" => 69 | Payload( 70 | Util.Decode.tuple5( 71 | RichText.decode, 72 | option(string), 73 | JsonCombinators.Json.Decode.option(Common.AgdaRange.decode), 74 | string, 75 | string, 76 | )->map(((text, raw, range, label, style)) => Labeled(label, style, text, raw, range)), 77 | ) 78 | | "Unlabeled" => 79 | Payload( 80 | tuple3( 81 | RichText.decode, 82 | option(string), 83 | JsonCombinators.Json.Decode.option(Common.AgdaRange.decode), 84 | )->map(((text, raw, range)) => Unlabeled(text, raw, range)), 85 | ) 86 | | "Header" => Payload(string->map(s => Header(s))) 87 | | tag => raise(DecodeError("[Item] Unknown constructor: " ++ tag)) 88 | } 89 | ) 90 | } 91 | 92 | let encode = { 93 | open! JsonCombinators.Json.Encode 94 | Util.Encode.sum(x => 95 | switch x { 96 | | Labeled(label, style, text, raw, range) => 97 | Payload(( 98 | "Labeled", 99 | Util.Encode.tuple5( 100 | RichText.encode, 101 | option(string), 102 | option(Common.AgdaRange.encode), 103 | string, 104 | string, 105 | (text, raw, range, label, style), 106 | ), 107 | )) 108 | | Unlabeled(text, raw, range) => 109 | Payload(( 110 | "Unlabeled", 111 | tuple3(RichText.encode, option(string), option(Common.AgdaRange.encode))(( 112 | text, 113 | raw, 114 | range, 115 | )), 116 | )) 117 | | Header(s) => Payload(("Header", string(s))) 118 | } 119 | , ...) 120 | } 121 | -------------------------------------------------------------------------------- /src/View/Component/Link.res: -------------------------------------------------------------------------------- 1 | open Common 2 | 3 | type t = 4 | | SrcLoc(AgdaRange.t) 5 | | Hole(int) 6 | 7 | let toString = x => 8 | switch x { 9 | | SrcLoc(range) => AgdaRange.toString(range) 10 | | Hole(int) => "?" ++ string_of_int(int) 11 | } 12 | 13 | let decode = { 14 | open JsonCombinators.Json.Decode 15 | Util.Decode.sum(x => { 16 | switch x { 17 | | "LinkRange" => Payload(AgdaRange.decode->map((. range) => SrcLoc(range))) 18 | | "LinkHole" => Payload(int->map((. index) => Hole(index))) 19 | | tag => raise(DecodeError("[View.Link] Unknown constructor: " ++ tag)) 20 | } 21 | }) 22 | } 23 | 24 | let encode = { 25 | open JsonCombinators.Json.Encode 26 | Util.Encode.sum(x => 27 | switch x { 28 | | SrcLoc(range) => Payload("LinkRange", AgdaRange.encode(range)) 29 | | Hole(index) => Payload("LinkHole", int(index)) 30 | } 31 | , ... 32 | ) 33 | } 34 | 35 | module Event = { 36 | type t = 37 | | JumpToTarget(t) 38 | | MouseOver(t) 39 | | MouseOut(t) 40 | 41 | let chan: Chan.t = Chan.make() 42 | let eventContext = React.createContext(chan) 43 | 44 | module Provider = { 45 | let makeProps = (~value, ~children, ()) => 46 | { 47 | "value": value, 48 | "children": children, 49 | } 50 | 51 | let make = React.Context.provider(eventContext) 52 | } 53 | 54 | let decode = { 55 | Util.Decode.sum(x => { 56 | switch x { 57 | | "JumpToTarget" => 58 | Payload(decode->JsonCombinators.Json.Decode.map((. target) => JumpToTarget(target))) 59 | | "MouseOver" => 60 | Payload(decode->JsonCombinators.Json.Decode.map((. target) => MouseOver(target))) 61 | | "MouseOut" => 62 | Payload(decode->JsonCombinators.Json.Decode.map((. target) => MouseOut(target))) 63 | | tag => 64 | raise(JsonCombinators.Json.Decode.DecodeError("[Link.Event] Unknown constructor: " ++ tag)) 65 | } 66 | }) 67 | } 68 | 69 | let encode = { 70 | Util.Encode.sum(x => 71 | switch x { 72 | | JumpToTarget(link) => Payload("JumpToTarget", encode(link)) 73 | | MouseOver(link) => Payload("MouseOver", encode(link)) 74 | | MouseOut(link) => Payload("MouseOut", encode(link)) 75 | } 76 | , ... 77 | ) 78 | } 79 | } 80 | 81 | @react.component 82 | let make = (~target=SrcLoc(NoRange), ~jump=false, ~hover=false, ~className=[], ~children) => { 83 | let sanitizedTarget = switch target { 84 | | SrcLoc(NoRange) 85 | | SrcLoc(Range(_, [])) => 86 | None 87 | | Hole(index) => Some(Hole(index)) 88 | | SrcLoc(range) => Some(SrcLoc(range)) 89 | } 90 | 91 | let link = React.useContext(Event.eventContext) 92 | switch sanitizedTarget { 93 | | None => children 94 | | Some(t) => 95 | { 98 | if jump { 99 | link->Chan.emit(Event.JumpToTarget(t)) 100 | } 101 | }} 102 | onMouseOver={_ => 103 | if hover { 104 | link->Chan.emit(Event.MouseOver(t)) 105 | }} 106 | onMouseOut={_ => 107 | if hover { 108 | link->Chan.emit(Event.MouseOut(t)) 109 | }}> 110 | children 111 | 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/View/Hook.res: -------------------------------------------------------------------------------- 1 | // React Hook for request-response handling 2 | let recv = (reqChan: Chan.t<'req>, resChan: Chan.t<'res>, handler: 'req => promise<'res>) => 3 | React.useEffect1(() => Some( 4 | reqChan->Chan.on(req => { 5 | handler(req)->Promise.thenResolve(res => resChan->Chan.emit(res))->Promise.done 6 | }), 7 | ), []) 8 | 9 | // React Hook for receiving events 10 | let on = (chan: Chan.t<'a>, handler: 'a => unit) => 11 | React.useEffect1(() => Some(chan->Chan.on(handler)), []) 12 | 13 | let useFocus = () => { 14 | let htmlElRef = React.useRef(Nullable.null) 15 | let setFocus = _ => { 16 | htmlElRef.current 17 | ->Nullable.toOption 18 | ->Option.flatMap(Webapi.Dom.Element.asHtmlElement) 19 | ->Option.forEach(Webapi.Dom.HtmlElement.focus) 20 | } 21 | (htmlElRef, setFocus) 22 | } 23 | -------------------------------------------------------------------------------- /src/View/Panel/Body.res: -------------------------------------------------------------------------------- 1 | @react.component 2 | let make = (~items: View.Body.t) => 3 | switch items { 4 | | [] => <> 5 | | items => 6 |
    7 |
      8 | {items->Array.mapWithIndex((item, i) => )->React.array} 9 |
    10 |
    11 | } 12 | -------------------------------------------------------------------------------- /src/View/Panel/CandidateSymbols.res: -------------------------------------------------------------------------------- 1 | open React 2 | 3 | @react.component 4 | let make = (~candidates: array, ~index: int, ~onChooseSymbol: string => unit) => { 5 | let rowStart = index / 10 * 10 6 | let row = candidates->Array.slice(~start=rowStart, ~end=rowStart + 10) 7 | 8 |
    9 | {switch candidates[index] { 10 | | None => <> 11 | | Some(_) => 12 | row 13 | ->Array.mapWithIndex((key, i) => { 14 | let isSelected = rowStart + i === index 15 | 21 | }) 22 | ->array 23 | }} 24 |
    25 | } 26 | -------------------------------------------------------------------------------- /src/View/Panel/Header.res: -------------------------------------------------------------------------------- 1 | open React 2 | 3 | @react.component 4 | let make = (~header: View.Header.t, ~status: string) => { 5 | let status =
    {string(status)}
    6 | switch header { 7 | | Plain(text) =>
    {string(text)} {status}
    8 | | Success(text) =>
    {string(text)} {status}
    9 | | Warning(text) =>
    {string(text)} {status}
    10 | | Error(text) =>
    {string(text)} {status}
    11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/View/Panel/Keyboard.res: -------------------------------------------------------------------------------- 1 | open React 2 | 3 | type state = { 4 | sequence: string, 5 | translation: Translator.translation, 6 | candidateIndex: int, 7 | } 8 | 9 | let reducer = (state, action) => 10 | switch (state, action) { 11 | | (_, View.EventToView.InputMethod.Activate) => 12 | let translation = Translator.translate("", None) 13 | Some({sequence: "", translation: translation, candidateIndex: 0}) 14 | | (_, Deactivate) => None 15 | | (None, _) => None 16 | | (Some(_), Update(sequence, translation, candidateIndex)) => 17 | Some({sequence: sequence, translation: translation, candidateIndex: candidateIndex}) 18 | | (Some(state), BrowseUp) => Some({...state, candidateIndex: max(0, state.candidateIndex - 10)}) 19 | | (Some(state), BrowseRight) => 20 | Some({ 21 | ...state, 22 | candidateIndex: min( 23 | Array.length(state.translation.candidateSymbols) - 1, 24 | state.candidateIndex + 1, 25 | ), 26 | }) 27 | | (Some(state), BrowseDown) => 28 | Some({ 29 | ...state, 30 | candidateIndex: min( 31 | Array.length(state.translation.candidateSymbols) - 1, 32 | state.candidateIndex + 10, 33 | ), 34 | }) 35 | | (Some(state), BrowseLeft) => Some({...state, candidateIndex: max(0, state.candidateIndex - 1)}) 36 | } 37 | 38 | @react.component 39 | let make = ( 40 | ~state: option, 41 | ~onInsertChar: string => unit, 42 | ~onChooseSymbol: string => unit, 43 | ~prompting: bool, 44 | ) => 45 | switch state { 46 | | None =>
    47 | | Some({sequence, translation, candidateIndex}) => 48 |
    49 |
    50 |
    {string(sequence)}
    51 | 54 |
    55 |
    56 | {translation.keySuggestions 57 | ->Array.map(key => 58 | 61 | ) 62 | ->array} 63 |
    64 |
    65 | } 66 | -------------------------------------------------------------------------------- /src/View/Panel/Prompt.res: -------------------------------------------------------------------------------- 1 | open Common 2 | 3 | @react.component 4 | let make = ( 5 | ~inputMethodActivated: bool, 6 | ~prompt: option<(option, option, option)>, 7 | ~onSubmit: option => unit, 8 | ~onUpdatePromptIM: View.EventFromView.PromptIMUpdate.t => unit, 9 | ) => { 10 | let (placeholder, value) = switch prompt { 11 | | Some((_, placeholder, value)) => (placeholder->Option.getOr(""), value->Option.getOr("")) 12 | | None => ("", "") 13 | } 14 | // preserves mouse selection 15 | let (selectionInterval, setSelectionInterval) = React.useState(_ => None) 16 | 17 | // intercept arrow keys when the input method is activated 18 | // for navigating around symbol candidates 19 | let onKeyUp = event => { 20 | let arrowKey = switch ReactEvent.Keyboard.key(event) { 21 | | "ArrowUp" => Some(View.EventFromView.PromptIMUpdate.BrowseUp) 22 | | "ArrowDown" => Some(BrowseDown) 23 | | "ArrowLeft" => Some(BrowseLeft) 24 | | "ArrowRight" => Some(BrowseRight) 25 | | "Escape" => Some(Escape) 26 | | _ => None 27 | } 28 | 29 | arrowKey->Option.forEach(action => { 30 | if inputMethodActivated { 31 | onUpdatePromptIM(action) 32 | event->ReactEvent.Keyboard.preventDefault 33 | } else if action === Escape { 34 | onSubmit(None) 35 | event->ReactEvent.Keyboard.preventDefault 36 | } 37 | }) 38 | } 39 | 40 | let onMouseUp = event => { 41 | if inputMethodActivated { 42 | event->ReactEvent.Synthetic.persist 43 | let selectionInterval: Interval.t = ( 44 | ReactEvent.Mouse.target(event)["selectionStart"], 45 | ReactEvent.Mouse.target(event)["selectionEnd"], 46 | ) 47 | // preserve mouse selection so that we can restore them later 48 | setSelectionInterval(_ => Some(selectionInterval)) 49 | onUpdatePromptIM(MouseSelect(selectionInterval)) 50 | } 51 | } 52 | 53 | // on update the text in the input box 54 | let onChange = event => { 55 | let value: string = ReactEvent.Form.target(event)["value"] 56 | event->ReactEvent.Synthetic.persist 57 | // preserve mouse selection so that we can restore them later 58 | setSelectionInterval(_ => Some(( 59 | ReactEvent.Form.target(event)["selectionStart"], 60 | ReactEvent.Form.target(event)["selectionEnd"], 61 | ))) 62 | onUpdatePromptIM(KeyUpdate(value)) 63 | } 64 | 65 | // Focus & select text in once the prompt is updated 66 | let inputRef = React.useRef(Nullable.Null) 67 | React.useEffect(() => { 68 | // Focus 69 | inputRef.current 70 | ->Nullable.toOption 71 | ->Option.flatMap(Webapi.Dom.Element.asHtmlElement) 72 | ->Option.forEach(Webapi.Dom.HtmlElement.focus) 73 | // Update mouse selection in 74 | inputRef.current 75 | ->Nullable.toOption 76 | ->Option.forEach(input => { 77 | selectionInterval->Option.forEach( 78 | ((start, end_)) => { 79 | let setSelectionRange = %raw(`(elem, start, end_) => elem.setSelectionRange(start, end_)`) 80 | input->setSelectionRange(start, end_)->ignore 81 | }, 82 | ) 83 | }) 84 | None 85 | }, [prompt]) 86 | 87 | let onSubmit = _event => { 88 | onUpdatePromptIM(Escape) 89 | onSubmit(Some(value)) 90 | } 91 | 92 | switch prompt { 93 | | Some((body, _, _)) => 94 |
    95 |
    96 | {switch body { 97 | | None => <> 98 | | Some(message) =>

    {React.string(message)}

    99 | }} 100 | 109 |
    110 |
    111 | | None => <> 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/View/Root.res: -------------------------------------------------------------------------------- 1 | // As this so called "WebView" is isolated and independent from the Extension 2 | // this is the only way to send messages back to the extension 3 | let vscode = VSCode.Api.acquireVsCodeApi() 4 | 5 | // relay VSCode.Api.onMessage => onRequest or onEvent; 6 | let onRequest = Chan.make() 7 | let onEventToView = Chan.make() 8 | VSCode.Api.onMessage(stringifiedJSON => { 9 | let json = stringifiedJSON->JSON.parseExn 10 | switch JsonCombinators.Json.decode(json, View.RequestOrEventToView.decode) { 11 | | Ok(Event(event)) => onEventToView->Chan.emit(event) 12 | | Ok(Request(req)) => onRequest->Chan.emit(req) 13 | | Error(_) => () // TODO: handle this decode error 14 | } 15 | }) 16 | 17 | // relay onResponse => VSCode.Api.postMessage 18 | let onResponse = Chan.make() 19 | let _ = onResponse->Chan.on(response => { 20 | open View.ResponseOrEventFromView 21 | vscode->VSCode.Api.postMessage(encode(Response(response))) 22 | }) 23 | 24 | // relay onEventFromView => VSCode.Api.postMessage 25 | let onEventFromView = Chan.make() 26 | let _ = onEventFromView->Chan.on(event => { 27 | open View.ResponseOrEventFromView 28 | vscode->VSCode.Api.postMessage(encode(Event(event))) 29 | }) 30 | 31 | // mount the view at the "root" element 32 | Webapi.Dom.Document.getElementById(Webapi.Dom.document, "root")->Option.forEach(rootElement => { 33 | ReactDOM.Client.createRoot(rootElement)->ReactDOM.Client.Root.render( 34 | , 35 | ) 36 | }) 37 | -------------------------------------------------------------------------------- /src/View/Singleton.res: -------------------------------------------------------------------------------- 1 | module Panel: { 2 | // methods 3 | let make: string => WebviewPanel.t 4 | let destroy: unit => unit 5 | let get: unit => option 6 | } = { 7 | let handle: ref> = ref(None) 8 | let make = extensionPath => 9 | switch handle.contents { 10 | | None => 11 | let panel = WebviewPanel.make("Agda", extensionPath) 12 | handle := Some(panel) 13 | // free the handle when the view has been forcibly destructed 14 | WebviewPanel.onceDestroyed(panel) 15 | ->Promise.finally(() => { 16 | handle := None 17 | }) 18 | ->Promise.done 19 | panel 20 | | Some(panel) => panel 21 | } 22 | 23 | let get = () => handle.contents 24 | 25 | let destroy = () => { 26 | handle.contents->Option.forEach(WebviewPanel.destroy) 27 | handle := None 28 | } 29 | } 30 | 31 | module DebugBuffer: { 32 | let get: unit => option 33 | let make: string => WebviewPanel.t 34 | let destroy: unit => unit 35 | } = { 36 | let handle: ref> = ref(None) 37 | let get = () => handle.contents 38 | let make = extensionPath => 39 | switch handle.contents { 40 | | None => 41 | let panel = WebviewPanel.make("Agda Debug Buffer", extensionPath) 42 | handle := Some(panel) 43 | // free the handle when the view has been forcibly destructed 44 | WebviewPanel.onceDestroyed(panel) 45 | ->Promise.finally(() => { 46 | handle := None 47 | }) 48 | ->Promise.done 49 | panel 50 | | Some(panel) => panel 51 | } 52 | 53 | let destroy = () => { 54 | handle.contents->Option.forEach(WebviewPanel.destroy) 55 | handle := None 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /style/variables.less: -------------------------------------------------------------------------------- 1 | :root { 2 | --agdaMode-buffer-font-size: var(--vscode-editor-font-size); 3 | } 4 | 5 | // colors of editor markers 6 | 7 | @error : var(--vscode-editorError-foreground); 8 | @warning : var(--vscode-editorWarning-foreground); 9 | @success : var(--vscode-editorInfo-foreground); 10 | 11 | 12 | // colors for the panel 13 | 14 | @foreground : var(--vscode-foreground); 15 | @foreground-subtle : var(--vscode-input-placeholderForeground); 16 | @foreground-tenuous : var(--vscode-editorIndentGuide-activeBackground); 17 | @foreground-highlight : var(--vscode-activityBar-foreground); 18 | @selection : var(--vscode-editor-selectionBackground); 19 | @header-background : var(--vscode-editor-background); 20 | @body-background : var(--vscode-sideBar-background); 21 | // @deep-background : var(--vscode-scrollbar-shadow); 22 | 23 | @input : var(--vscode-input-foreground); 24 | @inputBorder : var(--vscode-input-border); 25 | @inputPlaceholder : var(--vscode-input-placeholderForeground); 26 | @input-background : var(--vscode-input-background); 27 | 28 | @link : var(--vscode-button-foreground); 29 | @link-hover: var(--vscode-button-foreground); 30 | 31 | @hole: var(--vscode-textLink-foreground); 32 | @hole-hover: var(--vscode-textLink-activeForeground); -------------------------------------------------------------------------------- /syntaxes/forester.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.forester", 3 | "patterns": [ 4 | { 5 | "include": "#agda-block" 6 | }, 7 | { 8 | "include": "source.forester" 9 | } 10 | ], 11 | "repository": { 12 | "agda-block": { 13 | "begin": "\\\\(agda)\\{", 14 | "end": "^\\s*\\}", 15 | "name": "markup.raw.block.forester", 16 | "contentName": "meta.embedded.block.agda", 17 | "beginCaptures": { 18 | "0": { "name": "keyword.control.agda.begin.forester" } 19 | "1": { "name": "fenced_code.block.language.forester" } 20 | }, 21 | "endCaptures": { 22 | "0": { "name": "keyword.control.agda.end.forester" } 23 | }, 24 | "patterns": [ 25 | { 26 | "include": "source.agda" 27 | } 28 | ] 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /syntaxes/markdown.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.markdown", 3 | "patterns": [ 4 | { 5 | "include": "#agda-block" 6 | }, 7 | { 8 | "include": "text.html.markdown" 9 | } 10 | ], 11 | "repository": { 12 | "agda-block": { 13 | "begin": "(^|\\G)(\\s*)(```)(\\s*)(agda)(\\s*$)", 14 | "end": "(^|\\G)(\\2)(```)(\\s*$)", 15 | "name": "markup.fenced_code.block.markdown", 16 | "contentName": "meta.embedded.block.agda", 17 | "beginCaptures": { 18 | "3": { "name": "punctuation.definition.markdown" }, 19 | "5": { "name": "fenced_code.block.language.markdown" }, 20 | "6": { "name": "fenced_code.block.language.attributes.markdown" } 21 | }, 22 | "endCaptures": { 23 | "3": { "name": "punctuation.definition.markdown" } 24 | }, 25 | "patterns": [ 26 | { 27 | "include": "source.agda" 28 | } 29 | ] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /syntaxes/org.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.org", 3 | "patterns": [ 4 | { 5 | "include": "#agda-block" 6 | }, 7 | { 8 | "include": "source.org" 9 | } 10 | ], 11 | "repository": { 12 | "agda-block": { 13 | "begin": "(?i)\\#\\+begin\\_src\\s+(agda2)", 14 | "end": "(?i)\\#\\+end\\_src", 15 | "name": "markup.raw.block.org", 16 | "contentName": "meta.embedded.block.agda", 17 | "beginCaptures": { 18 | "0": { "name": "keyword.control.agda.begin.org" } 19 | "1": { "name": "fenced_code.block.language.org" } 20 | }, 21 | "endCaptures": { 22 | "0": { "name": "keyword.control.agda.end.org" } 23 | }, 24 | "patterns": [ 25 | { 26 | "include": "source.agda" 27 | } 28 | ] 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /syntaxes/restructuredtext.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.rst", 3 | "patterns": [ 4 | { 5 | "include": "#agda-block" 6 | }, 7 | { 8 | "include": "source.rst" 9 | } 10 | ], 11 | "repository": { 12 | "agda-block": { 13 | "begin": "\\:\\:", 14 | "end": "^(?=\\S)", 15 | "name": "markup.raw.block.restructuredtext", 16 | "contentName": "meta.embedded.block.agda", 17 | "beginCaptures": { 18 | "0": { "name": "keyword.control.agda.begin.restructuredtext" } 19 | }, 20 | "endCaptures": { 21 | "0": { "name": "keyword.control.agda.end.restructuredtext" } 22 | }, 23 | "patterns": [ 24 | { 25 | "include": "source.agda" 26 | } 27 | ] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /syntaxes/tex.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.tex", 3 | "patterns": [ 4 | { 5 | "include": "#agda-block" 6 | }, 7 | { 8 | "include": "text.tex" 9 | } 10 | ], 11 | "repository": { 12 | "agda-block": { 13 | "begin": "\\\\begin\\{code\\}.*", 14 | "end": "\\\\end\\{code\\}.*", 15 | "name": "markup.raw.block.latex", 16 | "contentName": "meta.embedded.block.agda", 17 | "beginCaptures": { 18 | "0": { "name": "keyword.control.agda.begin.latex" } 19 | }, 20 | "endCaptures": { 21 | "0": { "name": "keyword.control.agda.end.latex" } 22 | }, 23 | "patterns": [ 24 | { 25 | "include": "source.agda" 26 | } 27 | ] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /syntaxes/typst.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.typst", 3 | "patterns": [ 4 | { 5 | "include": "#agda-block" 6 | }, 7 | { 8 | "include": "text.html.typst" 9 | } 10 | ], 11 | "repository": { 12 | "agda-block": { 13 | "begin": "(^|\\G)(\\s*)(```)(\\s*)(agda)(\\s*$)", 14 | "end": "(^|\\G)(\\2)(```)(\\s*$)", 15 | "name": "markup.fenced_code.block.typst", 16 | "contentName": "meta.embedded.block.agda", 17 | "beginCaptures": { 18 | "3": { "name": "punctuation.definition.typst" }, 19 | "5": { "name": "fenced_code.block.language.typst" }, 20 | "6": { "name": "fenced_code.block.language.attributes.typst" } 21 | }, 22 | "endCaptures": { 23 | "3": { "name": "punctuation.definition.typst" } 24 | }, 25 | "patterns": [ 26 | { 27 | "include": "source.agda" 28 | } 29 | ] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/RunTestFromCLI.res: -------------------------------------------------------------------------------- 1 | // bindings of module '@vscode/test-electron' 2 | type options = { 3 | extensionDevelopmentPath: string, 4 | extensionTestsPath: string, 5 | } 6 | 7 | @module("@vscode/test-electron") 8 | external runTests: options => promise = "runTests" 9 | 10 | let testSuiteAdapterFileName = "TestSuiteAdapter.bs.js" 11 | 12 | // The folder containing the Extension Manifest package.json 13 | // Passed to `--extensionDevelopmentPath` 14 | let extensionDevelopmentPath = NodeJs.Path.resolve([NodeJs.Global.dirname, "../"]) 15 | 16 | // The path to the extension test script 17 | // Passed to --extensionTestsPath 18 | let extensionTestsPath = NodeJs.Path.resolve([NodeJs.Global.dirname, testSuiteAdapterFileName]) 19 | 20 | Js.log( 21 | "Running from the CLI, with\n extensionDevelopmentPath: " ++ 22 | (extensionDevelopmentPath ++ 23 | ("\n extensionTestsPath: " ++ extensionTestsPath)), 24 | ) 25 | 26 | runTests({ 27 | extensionDevelopmentPath, 28 | extensionTestsPath, 29 | })->Promise.done -------------------------------------------------------------------------------- /test/TestSuiteAdapter.res: -------------------------------------------------------------------------------- 1 | // bindings for using mocha programmatically 2 | module Mocha = { 3 | type t 4 | type options = { 5 | ui: string, 6 | color: bool, 7 | } 8 | 9 | @module @new external make: options => t = "mocha" 10 | @send external addFile: (t, string) => unit = "addFile" 11 | @send external run: (t, int => unit) => unit = "run" 12 | } 13 | 14 | // bindings for glob 15 | module Glob = { 16 | type options = {cwd: string} 17 | 18 | @module 19 | external glob: (string, options, (Nullable.t<'error>, array) => unit) => unit = "glob" 20 | } 21 | 22 | exception TestFailure(string) 23 | 24 | let run = () => { 25 | // Create the mocha test 26 | let mocha = Mocha.make({ui: "bdd", color: true}) 27 | 28 | // dirname: ./lib/js/test 29 | // testsRoot: ./lib/js/test/tests 30 | 31 | let testsRoot = NodeJs.Path.resolve([NodeJs.Global.dirname, "tests"]) 32 | 33 | Promise.make((resolve, reject) => 34 | Glob.glob("**/*.js", {cwd: testsRoot}, (err, files) => 35 | switch Nullable.toOption(err) { 36 | | Some(err) => reject(err) 37 | | None => 38 | // Add files to the test suite 39 | files->Array.forEach(file => mocha->Mocha.addFile(NodeJs.Path.resolve([testsRoot, file]))) 40 | 41 | // Run the mocha test 42 | switch mocha->Mocha.run( 43 | failures => 44 | if failures > 0 { 45 | reject(TestFailure(string_of_int(failures) ++ " tests failed.")) 46 | } else { 47 | resolve(true) 48 | }, 49 | ) { 50 | | () => () 51 | | exception exn => 52 | Js.Console.error(exn) 53 | reject(exn) 54 | } 55 | } 56 | ) 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /test/tests/Parser/Response/Issue95-2.6.1-Unix.in: -------------------------------------------------------------------------------- 1 | (agda2-status-action "") 2 | (agda2-info-action "*Type-checking*" "" nil) 3 | (agda2-highlight-clear) 4 | (agda2-info-action "*Type-checking*" "Checking Issue95 (/Users/omega/github/agda-mode/test/ManualTests/Issue95.agda).\n" t) 5 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-0") 6 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-1") 7 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-2") 8 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-3") 9 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-4") 10 | (agda2-info-action "*Error*" "/Users/omega/github/agda-mode/test/ManualTests/Issue95.agda:8,5-9\nString != List Char\nwhen checking that the expression \"\\\\\" has type List Char" nil) 11 | ((last . 3) . (agda2-maybe-goto '("/Users/omega/github/agda-mode/test/ManualTests/Issue95.agda" . 144))) 12 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-5") 13 | (agda2-status-action "") 14 | Agda2> -------------------------------------------------------------------------------- /test/tests/Parser/Response/Issue95-2.6.1-Unix.out: -------------------------------------------------------------------------------- 1 | NonLast Status: implicit arguments not displayed, module not type checked 2 | NonLast ClearRunningInfo 3 | NonLast ClearHighlighting 4 | NonLast RunningInfo 1 Checking Issue95 (/Users/omega/github/agda-mode/test/ManualTests/Issue95.agda). 5 | 6 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-0 7 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-1 8 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-2 9 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-3 10 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-4 11 | NonLast DisplayInfo Error /Users/omega/github/agda-mode/test/ManualTests/Issue95.agda:8,5-9 12 | String != List Char 13 | when checking that the expression "\\" has type List Char 14 | Last(3) JumpToError /Users/omega/github/agda-mode/test/ManualTests/Issue95.agda 144 15 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-5 16 | NonLast Status: implicit arguments not displayed, module not type checked 17 | -------------------------------------------------------------------------------- /test/tests/Parser/Response/Issue95.agda: -------------------------------------------------------------------------------- 1 | -- Load me 2 | module Issue95 where 3 | open import Agda.Builtin.Char 4 | open import Agda.Builtin.List 5 | open import Agda.Builtin.String 6 | 7 | s : List Char 8 | s = "\\" 9 | -------------------------------------------------------------------------------- /test/tests/Parser/Response/QuotationMark-2.6.0-Unix.in: -------------------------------------------------------------------------------- 1 | (agda2-status-action "") 2 | (agda2-info-action "*Type-checking*" "" nil) 3 | (agda2-highlight-clear) 4 | (agda2-info-action "*Type-checking*" "Checking QuotationMark (/Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda).\n" t) 5 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-0") 6 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-1") 7 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-2") 8 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-3") 9 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-4") 10 | (agda2-info-action "*Error*" "/Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda:8,5-8\nString != List Char\nwhen checking that the expression \")\" has type List Char" nil) 11 | ((last . 3) . (agda2-maybe-goto '("/Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda" . 150))) 12 | ((last . 3) . (agda2-maybe-goto '("/Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda" . 150))) 13 | (agda2-highlight-load-and-delete-action "/var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-5") 14 | (agda2-status-action "") 15 | Agda2> -------------------------------------------------------------------------------- /test/tests/Parser/Response/QuotationMark-2.6.0-Unix.out: -------------------------------------------------------------------------------- 1 | NonLast Status: implicit arguments not displayed, module not type checked 2 | NonLast ClearRunningInfo 3 | NonLast ClearHighlighting 4 | NonLast RunningInfo 1 Checking QuotationMark (/Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda). 5 | 6 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-0 7 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-1 8 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-2 9 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-3 10 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-4 11 | NonLast DisplayInfo Error /Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda:8,5-8 12 | String != List Char 13 | when checking that the expression ")" has type List Char 14 | Last(3) JumpToError /Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda 150 15 | Last(3) JumpToError /Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda 150 16 | NonLast HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-5 17 | NonLast Status: implicit arguments not displayed, module not type checked 18 | -------------------------------------------------------------------------------- /test/tests/Parser/Response/QuotationMark.agda: -------------------------------------------------------------------------------- 1 | -- Load me 2 | module QuotationMark where 3 | open import Agda.Builtin.Char 4 | open import Agda.Builtin.List 5 | open import Agda.Builtin.String 6 | 7 | s : List Char 8 | s = ")" 9 | -------------------------------------------------------------------------------- /test/tests/Parser/SExpression/01.in: -------------------------------------------------------------------------------- 1 | Agda2> 2 | (agda2-status-action "") 3 | (agda2-info-action "*Type-checking*" "" nil) 4 | (agda2-highlight-clear) 5 | (agda2-status-action "Checked") 6 | (agda2-info-action "*All Done*" "" nil) 7 | ((last . 1) . (agda2-goals-action '())) 8 | Agda2> 9 | -------------------------------------------------------------------------------- /test/tests/Parser/SExpression/01.out: -------------------------------------------------------------------------------- 1 | "Agda2>" 2 | ["agda2-status-action"] 3 | ["agda2-info-action", "*Type-checking*", "nil"] 4 | ["agda2-highlight-clear"] 5 | ["agda2-status-action", "Checked"] 6 | ["agda2-info-action", "*All Done*", "nil"] 7 | [["last", ".", "1"], ".", ["agda2-goals-action", []]] 8 | -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/01.agda.in: -------------------------------------------------------------------------------- 1 | data ℕ : Set where 2 | Z : ℕ 3 | S : ℕ → ℕ 4 | 5 | -- the following ? should be expanded in into {! !} 6 | -- the comment above should not be affected 7 | a = ? 8 | 9 | _+_ : ℕ → ℕ → ℕ 10 | Z + y = {! 1 !} 11 | S x + y = {! 2 !} -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/01.agda.out: -------------------------------------------------------------------------------- 1 | Hole [0] (143, 144) => (143, 150) "{! !}" 2 | Hole [1] (176, 183) => (176, 183) "{! 1 !}" 3 | Hole [2] (194, 201) => (194, 201) "{! 2 !}" -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/Issue126.agda.in: -------------------------------------------------------------------------------- 1 | a = (?) 2 | -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/Issue126.agda.out: -------------------------------------------------------------------------------- 1 | Hole [0] (5, 6) => (5, 12) "{! !}" 2 | -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/Issue56.agda.in: -------------------------------------------------------------------------------- 1 | module Issue56 where 2 | 3 | +--comm : ? 4 | +--comm = ? 5 | 6 | -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/Issue56.agda.out: -------------------------------------------------------------------------------- 1 | Hole [0] (32, 33) => (32, 39) "{! !}" 2 | Hole [1] (50, 51) => (50, 57) "{! !}" -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/Issue96.agda.in: -------------------------------------------------------------------------------- 1 | data MBool : Set where 2 | TT : MBool 3 | FF : MBool 4 | ?? : MBool 5 | A? : ? 6 | ?A : ? 7 | 8 | ? 9 | ? 10 | ? -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/Issue96.agda.out: -------------------------------------------------------------------------------- 1 | Hole [0] (73, 74) => (73, 80) "{! !}" 2 | Hole [1] (89, 90) => (89, 96) "{! !}" 3 | Hole [2] (98, 99) => (98, 105) "{! !}" 4 | Hole [3] (106, 107) => (106, 113) "{! !}" 5 | Hole [4] (114, 115) => (114, 121) "{! !}" -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/literate.lagda.in: -------------------------------------------------------------------------------- 1 | Ignored by Agda. 2 | 3 | \begin{code}[ignored by Agda] ? {! !} 4 | module Whatever where 5 | -- Agda code goes here 6 | 7 | a = ? 8 | 9 | b = {! !} 10 | 11 | 12 | \end{code} -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/literate.lagda.md.in: -------------------------------------------------------------------------------- 1 | This line is ordinary text, which is ignored by Agda. 2 | 3 | ? {!!} 4 | 5 | ``` 6 | module Whatever where 7 | -- Agda code goes here 8 | ? 9 | ``` 10 | 11 | ? {!!} 12 | Here is another code block: 13 | 14 | ```agda 15 | data ℕ : Set where 16 | zero : {! !} 17 | suc : ℕ → ℕ 18 | ``` -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/literate.lagda.md.out: -------------------------------------------------------------------------------- 1 | Hole [0] (112, 113) => (112, 119) "{! !}" 2 | Hole [1] (196, 202) => (196, 202) "{! !}" -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/literate.lagda.org.in: -------------------------------------------------------------------------------- 1 | This line is ordinary text, which is ignored by Agda. 2 | 3 | {! 0 !} 4 | 5 | #+begin_src agda2 6 | module Whatever where 7 | -- Agda code goes here 8 | 9 | {! 1 !} 10 | 11 | #+end_src 12 | 13 | {! 2 !} 14 | 15 | Another non-code line. -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/literate.lagda.org.out: -------------------------------------------------------------------------------- 1 | Hole [0] (128, 135) => (128, 135) "{! 1 !}" -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/literate.lagda.out: -------------------------------------------------------------------------------- 1 | Hole [0] (106, 107) => (106, 113) "{! !}" 2 | Hole [1] (119, 124) => (119, 124) "{! !}" -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/literate.lagda.rst.in: -------------------------------------------------------------------------------- 1 | This line is ordinary text, which is ignored by Agda. 2 | ? 3 | 4 | :: 5 | 6 | module Whatever where 7 | -- Agda code goes here 8 | 9 | ? 10 | 11 | Another non-code line.? 12 | :: 13 | .. This line is also ignored ? 14 | 15 | .. 16 | :: 17 | -- Agda code 18 | 19 | ? 20 | 21 | 22 | The second one is the language containing a single word; the empty word. The 23 | root node is labelled ``true``, and all the others are labelled ``false``:: 24 | 25 | ε : ∀ {i A} → Lang i A 26 | ν ε = ? 27 | δ ε _ = ∅ -------------------------------------------------------------------------------- /test/tests/Parser/SourceFile/literate.lagda.rst.out: -------------------------------------------------------------------------------- 1 | Hole [0] (113, 114) => (113, 120) "{! !}" 2 | Hole [1] (207, 208) => (207, 214) "{! !}" 3 | Hole [2] (410, 411) => (410, 417) "{! !}" -------------------------------------------------------------------------------- /test/tests/Parser/Test__Parser.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | 3 | describe("when running Parser.escape", () => { 4 | it("should make escaped backslash explicit", () => { 5 | let raw = "\\ x -> x" 6 | let expected = "\\\\ x -> x" 7 | let actual = Parser.escape(raw) 8 | Assert.deepEqual(actual, expected) 9 | }) 10 | 11 | it("should make escaped newline on Unix explicit", () => { 12 | let raw = "x\ny" 13 | let expected = "x\\ny" 14 | let actual = Parser.escape(raw) 15 | Assert.deepEqual(actual, expected) 16 | }) 17 | 18 | it("should make escaped newline on Windows explicit", () => { 19 | let raw = "x\r\ny" 20 | let expected = "x\\r\\ny" 21 | let actual = Parser.escape(raw) 22 | Assert.deepEqual(actual, expected) 23 | }) 24 | 25 | it("should make escaped double quote explicit", () => { 26 | let raw = "\"x\"" 27 | let expected = "\\\"x\\\"" 28 | let actual = Parser.escape(raw) 29 | Assert.deepEqual(actual, expected) 30 | }) 31 | }) 32 | 33 | describe("when running Parser.unescapeEOL", () => { 34 | it("should make explicit newline on Unix implicit", () => { 35 | let raw = "x\\ny" 36 | let expected = "x\ny" 37 | let actual = Parser.unescapeEOL(raw) 38 | Assert.deepEqual(actual, expected) 39 | }) 40 | 41 | it("should make explicit newline on Windows implicit", () => { 42 | let raw = "x\\r\\ny" 43 | let expected = "x\r\ny" 44 | let actual = Parser.unescapeEOL(raw) 45 | Assert.deepEqual(actual, expected) 46 | }) 47 | }) 48 | -------------------------------------------------------------------------------- /test/tests/Parser/Test__Parser__Agda.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | 3 | describe("when running Agda.Expr.parse", () => { 4 | it("should parse a plain string", () => { 5 | let raw = `ℕ` 6 | let expected = Some([Agda.Term.Plain("ℕ")]) 7 | let actual = Agda.Expr.parse(raw) 8 | Assert.deepEqual(actual, expected) 9 | }) 10 | it("should parse a question mark", () => { 11 | let raw = `?3` 12 | let expected = Some([Agda.Term.QuestionMark(3)]) 13 | let actual = Agda.Expr.parse(raw) 14 | Assert.deepEqual(actual, expected) 15 | }) 16 | 17 | it("should parse a underscore", () => { 18 | let raw = ` _4hi ` 19 | let expected = Some([Agda.Term.Underscore("_4hi")]) 20 | let actual = Agda.Expr.parse(raw) 21 | Assert.deepEqual(actual, expected) 22 | }) 23 | }) 24 | 25 | describe("when running Agda.OutputConstraint.parse", () => { 26 | it("should parse OfType", () => { 27 | let raw = `x : ℕ` 28 | let expected = Some(Agda.OutputConstraint.OfType(RichText.string("x"), RichText.string("ℕ"))) 29 | let actual = Agda.OutputConstraint.parse(raw) 30 | Assert.deepEqual(actual, expected) 31 | }) 32 | 33 | it("should parse JustType", () => { 34 | let raw = `Type ℕ` 35 | let expected = Some(Agda.OutputConstraint.JustType(RichText.string("ℕ"))) 36 | let actual = Agda.OutputConstraint.parse(raw) 37 | Assert.deepEqual(actual, expected) 38 | }) 39 | 40 | it("should parse JustSort on Windows", () => { 41 | let raw = "Sort ℕ\r\n ℕ" 42 | let expected = Some( 43 | Agda.OutputConstraint.JustSort( 44 | RichText.string(`ℕ\r\n ℕ`), 45 | ), 46 | ) 47 | let actual = Agda.OutputConstraint.parse(raw) 48 | Assert.deepEqual(actual, expected) 49 | }) 50 | 51 | it("should parse JustSort on Unix", () => { 52 | let raw = "Sort ℕ\n ℕ" 53 | let expected = Some( 54 | Agda.OutputConstraint.JustSort( 55 | RichText.string("ℕ\n ℕ"), 56 | ), 57 | ) 58 | let actual = Agda.OutputConstraint.parse(raw) 59 | Assert.deepEqual(actual, expected) 60 | }) 61 | }) 62 | -------------------------------------------------------------------------------- /test/tests/Parser/Test__Parser__Response.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | open! Test__Parser__SExpression 3 | open Test__Util 4 | 5 | // [SExpression] -> [Response.Prioritized.t] 6 | let toPrioritizedResponses = exprs => 7 | // keeping the successful parsing result 8 | // Assert.fail on the failed ones 9 | exprs 10 | ->Array.map(Response.Prioritized.parse) 11 | ->Array.map(x => 12 | switch x { 13 | | Error(e) => 14 | Assert.fail(Parser.Error.toString(e)) 15 | [] 16 | | Ok(v) => [v] 17 | } 18 | ) 19 | ->Array.flat 20 | 21 | describe("when parsing responses", () => 22 | Golden.getGoldenFilepathsSync("../../../../test/tests/Parser/Response")->Array.forEach(filepath => 23 | Async.it( 24 | "should golden test " ++ filepath, 25 | async () => { 26 | let raw = await Golden.readFile(filepath) 27 | raw 28 | ->Golden.map(parseSExpression([], ...)) 29 | ->Golden.map(toPrioritizedResponses) 30 | ->Golden.map(Strings.unlinesWith(Response.Prioritized.toString, ...)) 31 | ->Golden.compare 32 | }, 33 | ) 34 | ) 35 | ) 36 | -------------------------------------------------------------------------------- /test/tests/Parser/Test__Parser__SExpression.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | open Test__Util 3 | 4 | // [Int] -> String -> [SExpression] 5 | let parseSExpression = (breakpoints, input) => { 6 | open Parser.Incr.Gen 7 | 8 | let output = ref([]) 9 | 10 | let parser = Parser.SExpression.makeIncr(x => 11 | switch x { 12 | | Yield(Error((errNo, raw))) => Assert.fail(Parser.Error.toString(SExpression(errNo, raw))) 13 | | Yield(Ok(a)) => output.contents->Array.push(a) 14 | | Stop => () 15 | } 16 | ) 17 | 18 | input 19 | ->String.trim 20 | ->Strings.breakInput(breakpoints) 21 | ->Array.map(Parser.splitToLines) 22 | ->Array.flat 23 | ->Array.forEach(Parser.Incr.feed(parser, ...)) 24 | 25 | output.contents 26 | } 27 | 28 | describe("when parsing S-expressions as a whole", () => 29 | Golden.getGoldenFilepathsSync( 30 | "../../../../test/tests/Parser/SExpression", 31 | )->Array.forEach(filepath => 32 | Async.it( 33 | "should golden test " ++ filepath, 34 | async () => { 35 | let raw = await Golden.readFile(filepath) 36 | raw 37 | ->Golden.map(parseSExpression([], ...)) 38 | ->Golden.map(Strings.unlinesWith(Parser.SExpression.toString, ...)) 39 | ->Golden.compare 40 | }, 41 | ) 42 | ) 43 | ) 44 | 45 | describe("when parsing S-expressions incrementally", () => 46 | Golden.getGoldenFilepathsSync( 47 | "../../../../test/tests/Parser/SExpression", 48 | )->Array.forEach(filepath => 49 | Async.it( 50 | "should golden test " ++ filepath, 51 | async () => { 52 | let raw = await Golden.readFile(filepath) 53 | raw 54 | ->Golden.map(parseSExpression([3, 23, 171, 217, 1234, 2342, 3453], ...)) 55 | ->Golden.map(Strings.unlinesWith(Parser.SExpression.toString, ...)) 56 | ->Golden.compare 57 | }, 58 | ) 59 | ) 60 | ) 61 | -------------------------------------------------------------------------------- /test/tests/Parser/Test__Parser__SourceFile.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | 3 | describe("when parsing file paths", () => 4 | it("should recognize the file extensions", () => { 5 | open SourceFile.FileType 6 | Assert.equal(parse("a.agda"), Agda) 7 | Assert.equal(parse("a.lagda"), LiterateTeX) 8 | Assert.equal(parse("a.lagda.tex"), LiterateTeX) 9 | Assert.equal(parse("a.lagda.md"), LiterateMarkdown) 10 | Assert.equal(parse("a.lagda.typ"), LiterateTypst) 11 | Assert.equal(parse("a.lagda.rst"), LiterateRST) 12 | Assert.equal(parse("a.lagda.org"), LiterateOrg) 13 | Assert.equal(parse("a.lagda.tree"), LiterateForester) 14 | }) 15 | ) 16 | 17 | if OS.onUnix { 18 | describe("when parsing source files (Unix only)", () => { 19 | describe("Regex.comment", () => { 20 | it( 21 | "should work", 22 | () => { 23 | open SourceFile 24 | let match = String.search(_, Regex.comment) 25 | Assert.equal(match("no comment"), -1) 26 | Assert.equal(match("no comment\n"), -1) 27 | Assert.equal(match("-- comment"), 0) 28 | Assert.equal(match("-- comment with newline\n"), 0) 29 | Assert.equal(match("{- comment -}"), 0) 30 | Assert.equal(match("{- {- -} {! !} -}"), 0) 31 | Assert.equal(match("{- {- -} {! !} -}\n"), 0) 32 | }, 33 | ) 34 | 35 | it( 36 | "should work when \"--\" is placed immediately after some text (issue #56)", 37 | () => { 38 | open SourceFile 39 | let match = String.search(_, Regex.comment) 40 | Assert.equal(match("a -- comment after some text"), 2) 41 | Assert.equal(match("a-- comment placed immediately after some text"), -1) 42 | Assert.equal(match("_-- comment placed immediately after name parts"), 1) 43 | Assert.equal(match(";-- comment placed immediately after name parts"), 1) 44 | Assert.equal(match(".-- comment placed immediately after name parts"), 1) 45 | Assert.equal(match("\"-- comment placed immediately after name parts"), 1) 46 | Assert.equal(match("(-- comment placed immediately after name parts"), 1) 47 | Assert.equal(match(")-- comment placed immediately after name parts"), 1) 48 | Assert.equal(match("{-- comment placed immediately after name parts"), 1) 49 | Assert.equal(match("}-- comment placed immediately after name parts"), 1) 50 | Assert.equal(match("@-- comment placed immediately after name parts"), 1) 51 | }, 52 | ) 53 | }) 54 | 55 | describe("Regex.goalBracket", () => { 56 | it( 57 | "should work", 58 | () => { 59 | open SourceFile 60 | let match = String.search(_, Regex.goalBracket) 61 | Assert.equal(match("{!!}"), 0) 62 | Assert.equal(match("{! !}"), 0) 63 | Assert.equal(match("{! !}\n"), 0) 64 | Assert.equal(match("{! \n !}\n"), 0) 65 | Assert.equal(match("no goal brackets"), -1) 66 | Assert.equal(match("no goal brackets\n"), -1) 67 | }, 68 | ) 69 | }) 70 | 71 | open Test__Util 72 | 73 | Golden.getGoldenFilepathsSync( 74 | "../../../../test/tests/Parser/SourceFile", 75 | )->Array.forEach(filepath => 76 | Async.it( 77 | "should golden test " ++ filepath, 78 | async () => { 79 | let raw = await Golden.readFile(filepath) 80 | raw 81 | ->Golden.map(SourceFile.parse([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], filepath, ...)) 82 | ->Golden.map(Strings.unlinesWith(SourceFile.Diff.toString, ...)) 83 | ->Golden.compare 84 | }, 85 | ) 86 | ) 87 | }) 88 | } 89 | -------------------------------------------------------------------------------- /test/tests/Test.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | 3 | before(() => { 4 | // for mocking the Config 5 | Config.inTestingMode := true 6 | }) 7 | -------------------------------------------------------------------------------- /test/tests/Test__Auto.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | open Test__Util 3 | 4 | let run = normalization => { 5 | describe("request to Agda", () => { 6 | This.timeout(4000) 7 | describe("global", () => { 8 | Async.it( 9 | "should be responded with the correct answer 1", 10 | async () => { 11 | let ctx = await AgdaMode.makeAndLoad("Auto.agda") 12 | 13 | let responses = switch ctx.state.goals[0] { 14 | | Some(goal) => 15 | await ctx.state->State__Connection.sendRequestAndCollectResponses( 16 | Request.Auto(normalization, goal), 17 | ) 18 | | None => [] 19 | } 20 | 21 | let filteredResponses = responses->Array.filter(filteredResponse) 22 | 23 | switch ctx.state.agdaVersion { 24 | | Some(version) => 25 | if Util.Version.gte(version, "2.7.0") { 26 | Assert.deepEqual( 27 | filteredResponses, 28 | [GiveAction(0, GiveString("n")), InteractionPoints([1])], 29 | ) 30 | } else { 31 | Assert.deepEqual( 32 | filteredResponses, 33 | [ 34 | GiveAction(0, GiveString("n")), 35 | DisplayInfo(AllGoalsWarnings("*All Goals*", "?1 : ℕ\n")), 36 | InteractionPoints([1]), 37 | ], 38 | ) 39 | } 40 | | None => Assert.fail("No Agda version found") 41 | } 42 | }, 43 | ) 44 | 45 | Async.it( 46 | "should be responded with the correct answer 2", 47 | async () => { 48 | let ctx = await AgdaMode.makeAndLoad("Auto.agda") 49 | 50 | let responses = switch ctx.state.goals[1] { 51 | | Some(goal) => 52 | await ctx.state->State__Connection.sendRequestAndCollectResponses( 53 | Request.Auto(normalization, goal), 54 | ) 55 | | None => [] 56 | } 57 | 58 | let filteredResponses = responses->Array.filter(filteredResponse) 59 | 60 | switch ctx.state.agdaVersion { 61 | | Some(version) => 62 | if Util.Version.gte(version, "2.7.0") { 63 | Assert.deepEqual( 64 | filteredResponses, 65 | [GiveAction(1, GiveString("n")), InteractionPoints([0])], 66 | ) 67 | } else { 68 | Assert.deepEqual( 69 | filteredResponses, 70 | [ 71 | GiveAction(1, GiveString("m")), 72 | DisplayInfo(AllGoalsWarnings("*All Goals*", "?0 : ℕ\n")), 73 | InteractionPoints([0]), 74 | ], 75 | ) 76 | } 77 | | None => Assert.fail("No Agda version found") 78 | } 79 | }, 80 | ) 81 | }) 82 | }) 83 | } 84 | 85 | describe("agda-mode.auto", () => { 86 | describe("AsIs", () => { 87 | run(AsIs) 88 | }) 89 | 90 | describe("Simplified", () => { 91 | run(Simplified) 92 | }) 93 | 94 | describe("Normalised", () => { 95 | run(Normalised) 96 | }) 97 | 98 | describe("HeadNormal", () => { 99 | run(HeadNormal) 100 | }) 101 | }) 102 | -------------------------------------------------------------------------------- /test/tests/Test__CaseSplit.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | open Test__Util 3 | 4 | describe("State__Goal.caseSplitAux dry run", () => { 5 | Async.it("should calculate the information needed for case splitting correctly", async () => { 6 | let editor = await VSCode.Window.showTextDocumentWithUri( 7 | VSCode.Uri.file(Path.asset("CaseSplit.agda")), 8 | None, 9 | ) 10 | let document = VSCode.TextEditor.document(editor) 11 | let goals = await Goal.makeMany(editor, [0, 1, 2, 3, 4, 5, 6, 7, 8]) 12 | let results = goals->Array.map( 13 | goal => { 14 | // convert `rewriteRange` to text in that range because range offsets are different on different OSs 15 | let (inWhereClause, indentWidth, rewriteRange) = State__Goal.caseSplitAux(document, goal) 16 | let rewriteRange = VSCode.Range.make( 17 | VSCode.TextDocument.positionAt(document, fst(rewriteRange)), 18 | VSCode.TextDocument.positionAt(document, snd(rewriteRange)), 19 | ) 20 | (inWhereClause, indentWidth, Editor.Text.get(document, rewriteRange)) 21 | }, 22 | ) 23 | 24 | Assert.deepEqual( 25 | results, 26 | [ 27 | (false, 9, `x → {! !}`), 28 | (false, 23, `y → {! !}`), 29 | (false, 4, `x → {! !}`), 30 | (false, 4, `y → {! !}`), 31 | (true, 13, `x → {! !}`), 32 | (true, 13, `y → {! !}`), 33 | (true, 2, `x → {! !}`), 34 | (true, 2, `y → {! !}`), 35 | (false, 13, `x → {! !}`), 36 | ], 37 | ) 38 | }) 39 | }) 40 | 41 | describe("agda-mode:case", () => { 42 | This.timeout(10000) 43 | let fileContent = ref("") 44 | 45 | Async.before(async () => fileContent := (await File.read(Path.asset("CaseSplit.agda")))) 46 | Async.after(async () => await File.write(Path.asset("CaseSplit.agda"), fileContent.contents)) 47 | 48 | Async.it("should have more goals after splitting", async () => { 49 | let ctx = await AgdaMode.makeAndLoad("CaseSplit.agda") 50 | await ctx->AgdaMode.case(Some(VSCode.Position.make(7, 16), "x")) 51 | Assert.deepEqual(Array.length(ctx.state.goals), 10) 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /test/tests/Test__ComputeNormalForm.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | open Test__Util 3 | 4 | let run = normalization => 5 | describe("request to Agda", () => { 6 | describe("global", () => { 7 | Async.it( 8 | "should be responded with the correct answer", 9 | async () => { 10 | let ctx = await AgdaMode.makeAndLoad("ComputeNormalForm.agda") 11 | 12 | let responses = 13 | await ctx.state->State__Connection.sendRequestAndCollectResponses( 14 | Request.ComputeNormalFormGlobal(normalization, "Z + S Z"), 15 | ) 16 | let filteredResponses = responses->Array.filter(filteredResponse) 17 | 18 | Assert.deepEqual(filteredResponses, [DisplayInfo(NormalForm("S Z"))]) 19 | }, 20 | ) 21 | 22 | Async.it( 23 | "should be responded with the correct answer", 24 | async () => { 25 | let ctx = await AgdaMode.makeAndLoad("ComputeNormalForm.agda") 26 | 27 | let responses = 28 | await ctx.state->State__Connection.sendRequestAndCollectResponses( 29 | Request.ComputeNormalFormGlobal(normalization, "S Z + S Z"), 30 | ) 31 | let filteredResponses = responses->Array.filter(filteredResponse) 32 | 33 | Assert.deepEqual(filteredResponses, [DisplayInfo(NormalForm("S (S Z)"))]) 34 | }, 35 | ) 36 | }) 37 | }) 38 | 39 | describe("agda-mode.compute-normal-form[DefaultCompute]", () => { 40 | run(DefaultCompute) 41 | }) 42 | 43 | describe("agda-mode.compute-normal-form[IgnoreAbstract]", () => { 44 | run(IgnoreAbstract) 45 | }) 46 | -------------------------------------------------------------------------------- /test/tests/Test__Config.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | 3 | describe("Config", () => { 4 | describe("Connection", () => { 5 | describe( 6 | "Paths", 7 | () => { 8 | Async.it( 9 | "getAgdaPaths . setAgdaPaths = id", 10 | async () => { 11 | let expected = [] 12 | await Config.Connection.setAgdaPaths(expected) 13 | let actual = Config.Connection.getAgdaPaths() 14 | 15 | Assert.deepEqual(actual, expected) 16 | 17 | let expected = ["some/path", "some/other/path"]->Array.map(Connection__URI.parse) 18 | await Config.Connection.setAgdaPaths(expected) 19 | let actual = Config.Connection.getAgdaPaths() 20 | 21 | Assert.deepEqual(actual, expected) 22 | }, 23 | ) 24 | 25 | Async.it( 26 | "`setAgdaPaths` should remove previous paths", 27 | async () => { 28 | await Config.Connection.setAgdaPaths(["some/path"]->Array.map(Connection__URI.parse)) 29 | let expected = ["some/other/path"]->Array.map(Connection__URI.parse) 30 | await Config.Connection.setAgdaPaths(expected) 31 | let actual = Config.Connection.getAgdaPaths() 32 | 33 | Assert.deepEqual(actual, expected) 34 | }, 35 | ) 36 | 37 | Async.it( 38 | "`addAgdaPaths` should be idempotent", 39 | async () => { 40 | let expected = ["some/path"]->Array.map(Connection__URI.parse) 41 | await Config.Connection.setAgdaPaths(expected) 42 | await Config.Connection.setAgdaPaths(expected) 43 | let actual = Config.Connection.getAgdaPaths() 44 | 45 | Assert.deepEqual(actual, expected) 46 | }, 47 | ) 48 | }, 49 | ) 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /test/tests/Test__Highlighting.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | open Test__Util 3 | 4 | describe("Highlighting", () => { 5 | let fileContent = ref("") 6 | Async.beforeEach(async () => fileContent := (await File.read(Path.asset("Issue180.agda")))) 7 | Async.afterEach(async () => await File.write(Path.asset("Issue180.agda"), fileContent.contents)) 8 | 9 | Async.it("should work after inserting a newline", async () => { 10 | let ctx = await AgdaMode.makeAndLoad("Issue180.agda") 11 | let _ = await Editor.Text.insert(ctx.state.document, VSCode.Position.make(6, 0), "\n") 12 | 13 | open Highlighting__SemanticToken 14 | let expected = [ 15 | make(7, (0, 3), Function, Some([])), 16 | make(7, (6, 7), Type, Some([])), 17 | make(7, (10, 11), Type, Some([])), 18 | make(7, (14, 15), Type, Some([])), 19 | make(8, (0, 1), Variable, Some([])), 20 | make(8, (2, 3), Function, Some([])), 21 | make(8, (4, 5), Variable, Some([])), 22 | ] 23 | 24 | let tokens = await ctx.state.highlighting->Highlighting.getSemanticTokens->Resource.get 25 | let actual = tokens->Array.sliceToEnd(~start=12) 26 | 27 | Assert.deepStrictEqual(actual, expected) 28 | }) 29 | 30 | Async.it("should work after deleting an empty line", async () => { 31 | let ctx = await AgdaMode.makeAndLoad("Issue180.agda") 32 | 33 | let _ = await Editor.Text.delete( 34 | ctx.state.document, 35 | VSCode.Range.make(VSCode.Position.make(5, 0), VSCode.Position.make(6, 0)), 36 | ) 37 | 38 | open Highlighting__SemanticToken 39 | let expected = [ 40 | make(5, (0, 3), Function, Some([])), 41 | make(5, (6, 7), Type, Some([])), 42 | make(5, (10, 11), Type, Some([])), 43 | make(5, (14, 15), Type, Some([])), 44 | make(6, (0, 1), Variable, Some([])), 45 | make(6, (2, 3), Function, Some([])), 46 | make(6, (4, 5), Variable, Some([])), 47 | ] 48 | let tokens = await ctx.state.highlighting->Highlighting.getSemanticTokens->Resource.get 49 | let actual = tokens->Array.sliceToEnd(~start=12) 50 | 51 | Assert.deepStrictEqual(actual, expected) 52 | }) 53 | 54 | Async.it("should work after deleting an existing line", async () => { 55 | let ctx = await AgdaMode.makeAndLoad("Issue180.agda") 56 | 57 | let _ = await Editor.Text.delete( 58 | ctx.state.document, 59 | VSCode.Range.make(VSCode.Position.make(5, 0), VSCode.Position.make(7, 0)), 60 | ) 61 | 62 | open Highlighting__SemanticToken 63 | let expected = [ 64 | make(5, (0, 1), Variable, Some([])), 65 | make(5, (2, 3), Function, Some([])), 66 | make(5, (4, 5), Variable, Some([])), 67 | ] 68 | let tokens = await ctx.state.highlighting->Highlighting.getSemanticTokens->Resource.get 69 | let actual = tokens->Array.sliceToEnd(~start=12) 70 | 71 | Assert.deepStrictEqual(actual, expected) 72 | }) 73 | }) 74 | -------------------------------------------------------------------------------- /test/tests/Test__Refine.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | open Test__Util 3 | 4 | describe("agda-mode.refine", () => { 5 | describe("Issue #158", () => { 6 | 7 | let fileContent = ref("") 8 | 9 | Async.before(async () => fileContent := (await File.read(Path.asset("Issue158.agda")))) 10 | Async.after(async () => await File.write(Path.asset("Issue158.agda"), fileContent.contents)) 11 | 12 | Async.it( 13 | "should result in the correct refinement", 14 | async () => { 15 | let ctx = await AgdaMode.makeAndLoad("Issue158.agda") 16 | await ctx->AgdaMode.refine(~cursor=VSCode.Position.make(12, 9)) 17 | let actual = await File.read(Path.asset("Issue158.agda")) 18 | let expected = await File.read(Path.asset("Issue158.agda.out")) 19 | Assert.equal(actual, expected) 20 | }, 21 | ) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /test/tests/Test__SolveConstraints.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | open Test__Util 3 | 4 | let run = normalization => { 5 | let fileContent = ref("") 6 | Async.beforeEach(async () => fileContent := (await File.read(Path.asset("Issue204.agda")))) 7 | Async.afterEach(async () => await File.write(Path.asset("Issue204.agda"), fileContent.contents)) 8 | 9 | Async.it("should be responded with the correct responses", async () => { 10 | let ctx = await AgdaMode.makeAndLoad("Issue204.agda") 11 | 12 | let responses = 13 | await ctx.state->State__Connection.sendRequestAndCollectResponses( 14 | Request.SolveConstraintsGlobal(normalization), 15 | ) 16 | 17 | let filteredResponses = responses->Array.filter(filteredResponse) 18 | Assert.deepEqual(filteredResponses, [InteractionPoints([0, 1]), SolveAll([(0, "4"), (1, "4")])]) 19 | }) 20 | 21 | Async.it("should solve all goals", async () => { 22 | let ctx = await AgdaMode.makeAndLoad("Issue204.agda") 23 | await AgdaMode.solveConstraints(ctx, normalization) 24 | Assert.deepEqual(ctx.state.goals->Array.length, 0) 25 | 26 | let actual = await File.read(Path.asset("Issue204.agda")) 27 | let expected = await File.read(Path.asset("Issue204.agda.out")) 28 | Assert.equal(actual, expected) 29 | }) 30 | } 31 | 32 | describe("agda-mode.solve-constraints", () => { 33 | describe("Simplified", () => { 34 | run(Simplified) 35 | }) 36 | 37 | describe("Normalised", () => { 38 | run(Normalised) 39 | }) 40 | 41 | describe("Instantiated", () => { 42 | run(Instantiated) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /test/tests/Test__Tokens.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | open Test__Util 3 | 4 | describe("Tokens", () => { 5 | This.timeout(10000) 6 | describe("GotoDefinition.agda", () => { 7 | Async.it( 8 | "should produce 28 tokens", 9 | async () => { 10 | let ctx = await AgdaMode.makeAndLoad("GotoDefinition.agda") 11 | let tokens = 12 | ctx.state.tokens 13 | ->Tokens.toArray 14 | ->Array.map( 15 | ((token, range)) => Editor.Range.toString(range) ++ " " ++ Tokens.Token.toString(token), 16 | ) 17 | Assert.deepEqual(Array.length(tokens), 28) 18 | }, 19 | ) 20 | 21 | Async.it( 22 | "should produce correct tokens", 23 | async () => { 24 | let ctx = await AgdaMode.makeAndLoad("GotoDefinition.agda") 25 | let tokens = 26 | ctx.state.tokens 27 | ->Tokens.toArray 28 | ->Array.map( 29 | ((token, range)) => Editor.Range.toString(range) ++ " " ++ Tokens.Token.toString(token), 30 | ) 31 | 32 | let srcOfPrimitive = switch ctx.state.agdaVersion { 33 | | Some(version) => 34 | if Util.Version.gte(version, "2.6.4") { 35 | "[src: 388]" 36 | } else { 37 | "[src: 320]" 38 | } 39 | | None => raise(Failure("No Agda version found")) 40 | } 41 | 42 | Assert.deepEqual( 43 | tokens, 44 | [ 45 | "0:0-6 (0, 6) [Keyword]", 46 | "0:7-21 (7, 21) [Module] [src: 1]", 47 | "0:22-27 (22, 27) [Keyword]", 48 | "1:0-4 (28, 32) [Keyword]", 49 | "1:5-6 (33, 34) [Datatype] [src: 34]", 50 | "1:7-8 (35, 36) [Symbol]", 51 | "1:9-12 (37, 40) [Primitive] " ++ srcOfPrimitive, 52 | "1:13-18 (41, 46) [Keyword]", 53 | "2:2-3 (49, 50) [ConstructorInductive] [src: 50]", 54 | "2:4-5 (51, 52) [Symbol]", 55 | "2:6-7 (53, 54) [Datatype] [src: 34]", 56 | "3:2-3 (57, 58) [ConstructorInductive] [src: 58]", 57 | "3:4-5 (59, 60) [Symbol]", 58 | "3:6-7 (61, 62) [Datatype] [src: 34]", 59 | "3:8-9 (63, 64) [Symbol]", 60 | "3:10-11 (65, 66) [Datatype] [src: 34]", 61 | "5:0-3 (68, 71) [Function, Operator] [src: 69]", 62 | "5:4-5 (72, 73) [Symbol]", 63 | "5:6-7 (74, 75) [Datatype] [src: 34]", 64 | "5:8-9 (76, 77) [Symbol]", 65 | "5:10-11 (78, 79) [Datatype] [src: 34]", 66 | "5:12-13 (80, 81) [Symbol]", 67 | "5:14-15 (82, 83) [Datatype] [src: 34]", 68 | "6:0-1 (84, 85) [Bound] [src: 85]", 69 | "6:2-3 (86, 87) [Function, Operator] [src: 69]", 70 | "6:4-5 (88, 89) [Bound] [src: 89]", 71 | "6:6-7 (90, 91) [Symbol]", 72 | "6:8-15 (92, 99) [Hole]", 73 | ], 74 | ) 75 | }, 76 | ) 77 | }) 78 | }) 79 | -------------------------------------------------------------------------------- /test/tests/TextEditor/Test__LineEnding.res: -------------------------------------------------------------------------------- 1 | open Mocha 2 | 3 | // open! BsMocha.Mocha 4 | // module Assert = BsMocha.Assert 5 | // module P = BsMocha.Promise 6 | 7 | open VSCode 8 | 9 | let openEditorWithContent = async content => { 10 | let textDocument = await Workspace.openTextDocumentWithOptions( 11 | Some({"content": content, "language": "agda"}), 12 | ) 13 | await Window.showTextDocumentWithShowOptions(textDocument, None) 14 | } 15 | 16 | describe("Conversion of offsets between LF and CRLF line endings", () => { 17 | describe("Editor.computeCRLFIndices", () => 18 | it( 19 | "should work", 20 | () => { 21 | Assert.deepEqual(Agda.OffsetConverter.computeCRLFIndices("1234\r\n78"), [4]) // String literal updated to v10.1.4 22 | Assert.deepEqual(Agda.OffsetConverter.computeCRLFIndices("12\r\n56\r\n90"), [2, 6]) // String literal updated to v10.1.4 23 | }, 24 | ) 25 | ) 26 | 27 | describe("Editor.Indices.make", () => 28 | it( 29 | "should work", 30 | () => { 31 | open Agda.Indices 32 | () 33 | Assert.deepEqual( 34 | "12\r\n56\r\n90"->Agda.OffsetConverter.computeCRLFIndices->make->expose->fst, // String literal updated to v10.1.4 35 | [(0, 2), (3, 5)], 36 | ) 37 | }, 38 | ) 39 | ) 40 | 41 | describe("Editor.Indices.convert", () => 42 | it( 43 | "should work", 44 | () => { 45 | open Agda.Indices 46 | let a = make(Agda.OffsetConverter.computeCRLFIndices("12\r\n56\r\n90")) // String literal updated to v10.1.4 47 | Assert.deepEqual(convert(a, 0), 0) 48 | Assert.deepEqual(a->expose->snd, 0) 49 | Assert.deepEqual(convert(a, 1), 1) 50 | Assert.deepEqual(a->expose->snd, 0) 51 | Assert.deepEqual(convert(a, 2), 2) 52 | Assert.deepEqual(a->expose->snd, 0) 53 | Assert.deepEqual(convert(a, 3), 4) 54 | Assert.deepEqual(a->expose->snd, 1) 55 | Assert.deepEqual(convert(a, 4), 5) 56 | Assert.deepEqual(a->expose->snd, 1) 57 | Assert.deepEqual(convert(a, 5), 6) 58 | Assert.deepEqual(a->expose->snd, 1) 59 | Assert.deepEqual(convert(a, 6), 8) 60 | Assert.deepEqual(a->expose->snd, 2) 61 | Assert.deepEqual(convert(a, 7), 9) 62 | Assert.deepEqual(a->expose->snd, 2) 63 | }, 64 | ) 65 | ) 66 | }) 67 | -------------------------------------------------------------------------------- /test/tests/assets/Auto.agda: -------------------------------------------------------------------------------- 1 | module Auto where 2 | 3 | data ℕ : Set where 4 | Z : ℕ 5 | S : ℕ → ℕ 6 | 7 | _+_ : ℕ → ℕ → ℕ 8 | Z + n = {! !} 9 | (S n) + m = {! !} -------------------------------------------------------------------------------- /test/tests/assets/CaseSplit.agda: -------------------------------------------------------------------------------- 1 | module CaseSplit where 2 | 3 | data ℕ : Set where 4 | Z : ℕ 5 | S : ℕ → ℕ 6 | 7 | f0 : ℕ → ℕ 8 | f0 = λ { x → {! !} ; y → {! !} } 9 | 10 | f1 : ℕ → ℕ 11 | f1 = λ 12 | { x → {! !} 13 | ; y → {! !} 14 | } 15 | 16 | g0 : ℕ → ℕ 17 | g0 = λ where x → {! !} 18 | y → {! !} 19 | 20 | g1 : ℕ → ℕ 21 | g1 = λ where 22 | x → {! !} 23 | y → {! !} 24 | 25 | issue16 : ℕ → ℕ 26 | issue16 = λ {x → {! !} } -------------------------------------------------------------------------------- /test/tests/assets/ComputeNormalForm.agda: -------------------------------------------------------------------------------- 1 | module ComputeNormalForm where 2 | 3 | data ℕ : Set where 4 | Z : ℕ 5 | S : ℕ → ℕ 6 | 7 | _+_ : ℕ → ℕ → ℕ 8 | Z + n = n 9 | (S n) + m = S (n + m) -------------------------------------------------------------------------------- /test/tests/assets/GotoDefinition.agda: -------------------------------------------------------------------------------- 1 | module GotoDefinition where 2 | data ℕ : Set where 3 | Z : ℕ 4 | S : ℕ → ℕ 5 | 6 | _+_ : ℕ → ℕ → ℕ 7 | x + y = {! !} -------------------------------------------------------------------------------- /test/tests/assets/InputMethod.agda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banacorn/agda-mode-vscode/620994cf253770ce913c01a77726ccb04d05c860/test/tests/assets/InputMethod.agda -------------------------------------------------------------------------------- /test/tests/assets/Issue158.agda: -------------------------------------------------------------------------------- 1 | module Issue158 where 2 | 3 | postulate 4 | A : Set 5 | 6 | record Foo : Set where 7 | field 8 | very-long-field-name-1 : A 9 | very-long-field-name-2 : A 10 | very-long-field-name-3 : A 11 | 12 | foo : Foo 13 | foo = {! !} -------------------------------------------------------------------------------- /test/tests/assets/Issue158.agda.out: -------------------------------------------------------------------------------- 1 | module Issue158 where 2 | 3 | postulate 4 | A : Set 5 | 6 | record Foo : Set where 7 | field 8 | very-long-field-name-1 : A 9 | very-long-field-name-2 : A 10 | very-long-field-name-3 : A 11 | 12 | foo : Foo 13 | foo = record 14 | { very-long-field-name-1 = {! !} 15 | ; very-long-field-name-2 = {! !} 16 | ; very-long-field-name-3 = {! !} 17 | } -------------------------------------------------------------------------------- /test/tests/assets/Issue173.agda: -------------------------------------------------------------------------------- 1 | module Issue173 where 2 | 3 | _ : {A : Set} → A → A 4 | _ = λ 𝒶 → {! 𝒶 !} -------------------------------------------------------------------------------- /test/tests/assets/Issue180.agda: -------------------------------------------------------------------------------- 1 | module Issue180 where 2 | 3 | data ℕ : Set where 4 | zero : ℕ 5 | suc : ℕ → ℕ 6 | 7 | _+_ : ℕ → ℕ → ℕ 8 | x + y = {! !} -------------------------------------------------------------------------------- /test/tests/assets/Issue204.agda: -------------------------------------------------------------------------------- 1 | module Issue204 where 2 | 3 | data Nat : Set where 4 | zero : Nat 5 | suc : (n : Nat) → Nat 6 | 7 | {-# BUILTIN NATURAL Nat #-} 8 | 9 | data Fin : Nat → Set where 10 | zero : {n : Nat} → Fin (suc n) 11 | suc : {n : Nat} (i : Fin n) → Fin (suc n) 12 | 13 | three1 : Fin 5 14 | three1 = suc {n = {! !}} (suc (suc zero)) 15 | 16 | three2 : Fin 5 17 | three2 = suc {n = {! !}} (suc (suc zero)) -------------------------------------------------------------------------------- /test/tests/assets/Issue204.agda.out: -------------------------------------------------------------------------------- 1 | module Issue204 where 2 | 3 | data Nat : Set where 4 | zero : Nat 5 | suc : (n : Nat) → Nat 6 | 7 | {-# BUILTIN NATURAL Nat #-} 8 | 9 | data Fin : Nat → Set where 10 | zero : {n : Nat} → Fin (suc n) 11 | suc : {n : Nat} (i : Fin n) → Fin (suc n) 12 | 13 | three1 : Fin 5 14 | three1 = suc {n = 4} (suc (suc zero)) 15 | 16 | three2 : Fin 5 17 | three2 = suc {n = 4} (suc (suc zero)) -------------------------------------------------------------------------------- /test/tests/assets/Load.agda: -------------------------------------------------------------------------------- 1 | module Load where 2 | 3 | a : {! !} 4 | a = {! !} -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const CopyPlugin = require('copy-webpack-plugin'); 3 | 4 | module.exports = [ 5 | { 6 | target: "node", 7 | entry: './lib/js/src/View/Root.bs.js', 8 | output: { 9 | path: path.join(__dirname, 'dist'), 10 | filename: 'bundled-view.js', 11 | libraryTarget: 'window', 12 | }, 13 | devtool: 'source-map', 14 | externals: { 15 | vscode: 'vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 16 | }, 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.less$/, 21 | loader: 'less-loader', // compiles Less to CSS 22 | }, 23 | ], 24 | }, 25 | plugins: [ 26 | new CopyPlugin({ 27 | patterns: [ 28 | { from: 'asset/codicon', to: 'codicon' }, 29 | ], 30 | }), 31 | ], 32 | }, 33 | { 34 | target: "node", 35 | entry: './lib/js/src/Main.bs.js', 36 | output: { 37 | path: path.join(__dirname, 'dist'), 38 | filename: 'app.bundle.js', 39 | libraryTarget: 'commonjs2', 40 | }, 41 | devtool: 'source-map', 42 | externals: { 43 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 44 | } 45 | } 46 | ]; --------------------------------------------------------------------------------