├── .github └── workflows │ └── test.yml ├── .gitignore ├── .mocharc.js ├── CHANGELOG.md ├── HACKING.md ├── LICENSE.md ├── README.md ├── asset ├── keymap.js └── query.js ├── bsconfig.json ├── keymap.el ├── keymaps └── agda-mode.cson ├── lib └── js │ ├── bundled.js │ ├── src │ ├── AgdaMode.bs.js │ ├── Command.bs.js │ ├── Connection.bs.js │ ├── Editors.bs.js │ ├── Goal.bs.js │ ├── Highlighting.bs.js │ ├── Instance.bs.js │ ├── Instance │ │ ├── Instance__Connections.bs.js │ │ ├── Instance__Goals.bs.js │ │ ├── Instance__Highlightings.bs.js │ │ ├── Instance__TextEditors.bs.js │ │ └── Instance__Type.bs.js │ ├── Log.bs.js │ ├── Node │ │ ├── N.bs.js │ │ ├── Node__Fs.bs.js │ │ ├── Node__OS.bs.js │ │ └── Node__Util.bs.js │ ├── Parser.bs.js │ ├── Parser │ │ └── Parser__Type.bs.js │ ├── Process.bs.js │ ├── Request.bs.js │ ├── Response.bs.js │ ├── RunningInfo.bs.js │ ├── SourceFile.bs.js │ ├── Task │ │ ├── Task.bs.js │ │ ├── TaskRunner.bs.js │ │ ├── Task__Command.bs.js │ │ ├── Task__DisplayInfo.bs.js │ │ ├── Task__Error.bs.js │ │ └── Task__Response.bs.js │ ├── Type │ │ ├── Type.bs.js │ │ ├── Type__Location.bs.js │ │ └── Type__View.bs.js │ ├── Util │ │ ├── Channel.bs.js │ │ ├── Event.bs.js │ │ ├── Resource.bs.js │ │ └── Util.bs.js │ └── View │ │ ├── Channels.bs.js │ │ ├── Component.bs.js │ │ ├── Component__Link.bs.js │ │ ├── Component__Range.bs.js │ │ ├── Emacs │ │ ├── Emacs.bs.js │ │ ├── Emacs__AllGoalsWarnings.bs.js │ │ ├── Emacs__Body.bs.js │ │ ├── Emacs__Component.bs.js │ │ ├── Emacs__Context.bs.js │ │ ├── Emacs__Error.bs.js │ │ ├── Emacs__GoalTypeContext.bs.js │ │ ├── Emacs__ParseError.bs.js │ │ ├── Emacs__Parser.bs.js │ │ ├── Emacs__SearchAbout.bs.js │ │ └── Emacs__WhyInScope.bs.js │ │ ├── Events.bs.js │ │ ├── Hook.bs.js │ │ ├── MiniEditor.bs.js │ │ ├── Panel │ │ ├── Body.bs.js │ │ ├── Dashboard.bs.js │ │ ├── InputMethod.bs.js │ │ ├── InputMethod │ │ │ ├── Buffer.bs.js │ │ │ ├── CandidateSymbols.bs.js │ │ │ ├── Extension.bs.js │ │ │ └── Translator.bs.js │ │ ├── Panel.bs.js │ │ └── SizingHandle.bs.js │ │ ├── Root.bs.js │ │ ├── Settings │ │ ├── Settings.bs.js │ │ ├── Settings__Breadcrumb.bs.js │ │ ├── Settings__Connection.bs.js │ │ ├── Settings__Connection__Error.bs.js │ │ ├── Settings__Debug.bs.js │ │ ├── Settings__InputMethod.bs.js │ │ └── Settings__Log.bs.js │ │ ├── Tab.bs.js │ │ └── View.bs.js │ └── test │ ├── Parser │ ├── Test__Parser__Response.bs.js │ ├── Test__Parser__SExpression.bs.js │ └── Test__Parser__SourceFile.bs.js │ ├── Test.bs.js │ ├── Test__Connection.bs.js │ ├── Test__Distribution.bs.js │ ├── Test__InputMethod.bs.js │ ├── Test__Main.bs.js │ ├── Test__Misc.bs.js │ ├── Test__Util.bs.js │ └── Test__View.bs.js ├── menus └── agda-mode.cson ├── package-lock.json ├── package.json ├── src ├── AgdaMode.re ├── Command.re ├── Connection.re ├── Editors.re ├── Goal.re ├── Highlighting.re ├── Instance.re ├── Instance │ ├── Instance__Connections.re │ ├── Instance__Goals.re │ ├── Instance__Highlightings.re │ ├── Instance__TextEditors.re │ └── Instance__Type.re ├── Log.re ├── Node │ ├── N.re │ ├── Node__Fs.re │ ├── Node__OS.re │ └── Node__Util.re ├── Parser.re ├── Parser │ └── Parser__Type.re ├── Process.re ├── Request.re ├── Response.re ├── RunningInfo.re ├── SourceFile.re ├── Task │ ├── Task.re │ ├── TaskRunner.re │ ├── Task__Command.re │ ├── Task__DisplayInfo.re │ ├── Task__Error.re │ └── Task__Response.re ├── Type │ ├── Type.re │ ├── Type__Location.re │ └── Type__View.re ├── Util │ ├── Channel.re │ ├── Event.re │ ├── Resource.re │ └── Util.re └── View │ ├── Channels.re │ ├── Component.re │ ├── Component__Link.re │ ├── Component__Range.re │ ├── Emacs │ ├── Emacs.re │ ├── Emacs__AllGoalsWarnings.re │ ├── Emacs__Body.re │ ├── Emacs__Component.re │ ├── Emacs__Context.re │ ├── Emacs__Error.re │ ├── Emacs__GoalTypeContext.re │ ├── Emacs__ParseError.re │ ├── Emacs__Parser.re │ ├── Emacs__SearchAbout.re │ └── Emacs__WhyInScope.re │ ├── Events.re │ ├── Hook.re │ ├── MiniEditor.re │ ├── Panel │ ├── Body.re │ ├── Dashboard.re │ ├── InputMethod.re │ ├── InputMethod │ │ ├── Buffer.re │ │ ├── CandidateSymbols.re │ │ ├── Extension.re │ │ └── Translator.re │ ├── Panel.re │ └── SizingHandle.re │ ├── Root.re │ ├── Settings │ ├── Settings.re │ ├── Settings__Breadcrumb.re │ ├── Settings__Connection.re │ ├── Settings__Connection__Error.re │ ├── Settings__Debug.re │ ├── Settings__InputMethod.re │ └── Settings__Log.re │ ├── Tab.re │ └── View.re ├── styles ├── agda-mode.less ├── base.less ├── layout.less └── module.less ├── test ├── 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 │ │ ├── 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__Response.re │ ├── Test__Parser__SExpression.re │ └── Test__Parser__SourceFile.re ├── Test.re ├── Test__Connection.re ├── Test__Distribution.re ├── Test__InputMethod.re ├── Test__Main.re ├── Test__Misc.re ├── Test__Util.re ├── Test__View.re └── asset │ ├── Algebra.agda │ ├── Blank1.agda │ ├── Blank2.lagda │ ├── Temp.agda │ └── Test.agda ├── webpack.config.js └── yarn.lock /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [10.x] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Setup Node.js 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | 21 | - name: Install atom 22 | run: | 23 | curl -s -L "https://atom.io/download/deb?channel=stable" -H 'Accept: application/octet-stream' -o "atom-amd64.deb" 24 | /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 25 | export DISPLAY=":99" 26 | dpkg-deb -x atom-amd64.deb "${HOME}/atom" 27 | export ATOM_SCRIPT_NAME="atom" 28 | export APM_SCRIPT_NAME="apm" 29 | export ATOM_SCRIPT_PATH="${HOME}/atom/usr/bin/${ATOM_SCRIPT_NAME}" 30 | export APM_SCRIPT_PATH="${HOME}/atom/usr/bin/${APM_SCRIPT_NAME}" 31 | export NPM_SCRIPT_PATH="${HOME}/atom/usr/share/${ATOM_SCRIPT_NAME}/resources/app/apm/node_modules/.bin/npm" 32 | export PATH="${PATH}:${HOME}/atom/usr/bin" 33 | 34 | echo "Using Atom version:" 35 | "${ATOM_SCRIPT_PATH}" -v 36 | echo "Using APM version:" 37 | "${APM_SCRIPT_PATH}" -v 38 | 39 | - name: Install Agda 40 | run: | 41 | echo "Pulling Agda from Docker Hub" 42 | docker pull banacorn/agda:2.6.0.1 43 | 44 | echo "Create a script for aliasing docker run" 45 | mkdir ${HOME}/bin 46 | export PATH="${PATH}:${HOME}/bin" 47 | echo -e '#!/bin/bash\ndocker run -i --rm banacorn/agda:2.6.0.1 agda "$@"' > ${HOME}/bin/agda 48 | chmod +x ${HOME}/bin/agda 49 | 50 | - name: npm install & build 51 | run: | 52 | npm install 53 | npm run build --if-present 54 | 55 | - name: Run tests 56 | run: | 57 | 58 | # so that we can see "atom" and "apm" and "agda" 59 | export PATH="${PATH}:${HOME}/atom/usr/bin:${HOME}/bin" 60 | 61 | echo "Version of Agda: " 62 | agda -V 63 | echo "Path of Agda: " 64 | which agda 65 | 66 | # linking "agda-mode" to "~/.atom/dev/packages" 67 | apm dev agda-mode 68 | 69 | # run the test with "xvfb-run" to simulate X windows 70 | xvfb-run -a atom -t lib/js/test/ 71 | env: 72 | CI: true 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | lib/bs 5 | .bsb.lock 6 | .merlin 7 | 8 | # generated by Agda 9 | *.agdai 10 | 11 | 12 | # Logs 13 | logs 14 | *.log 15 | npm-debug.log* 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (http://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules 42 | jspm_packages 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional REPL history 48 | .node_repl_history 49 | 50 | # Source map 51 | *.map 52 | 53 | # Though we generate both, we only care about the .js keymap/query 54 | asset/keymap.json 55 | asset/query.json 56 | -------------------------------------------------------------------------------- /.mocharc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "specPattern": /.*\.bs\.js$/i, 3 | "timeout": 20000, 4 | "recursive": true 5 | } 6 | -------------------------------------------------------------------------------- /HACKING.md: -------------------------------------------------------------------------------- 1 | # HACKING 2 | 3 | This plugin is written in [Reason](https://reasonml.github.io/) (basically OCaml) 4 | , which compiles to JS via [BuckleScript](https://bucklescript.github.io/en/). 5 | 6 | The user interface is built using [React](https://reactjs.org/), with 7 | [ReasonReact](https://reasonml.github.io/reason-react/en/) as the binding. 8 | 9 | ## Environment setup 10 | 11 | 1. clone the repo and load it as a development package 12 | 2. open the repo in the development mode 13 | 3. install dependencies 14 | 4. checkout to the `dev` branch. The `master` branch is for stable releases. 15 | 16 | ``` 17 | apm develop agda-mode 18 | atom -d ~/github/agda-mode 19 | cd ~/github/agda-mode 20 | npm install 21 | git checkout dev 22 | ``` 23 | 24 | You would also need to have Reason and BuckleScript installed: 25 | 26 | * [Installation](https://reasonml.github.io/docs/en/installation) 27 | * [Editor Plugins](https://reasonml.github.io/docs/en/editor-plugins) 28 | 29 | ## `dev` and `master` branch 30 | 31 | The only difference between `dev` and `master` is the entry point of the package, specified in `./package.json`. 32 | * `master`: `./lib/js/bundled.js`. 33 | * `dev`: `./lib/js/src/AgdaMode.bs`. 34 | 35 | ## Handy commands 36 | 37 | To have the BuckleScript transpiler running while developing: 38 | 39 | ``` 40 | npm run start 41 | ``` 42 | 43 | If the built artefacts are stale, to rebuild them, simple run `start` again: 44 | 45 | ``` 46 | npm run start 47 | ``` 48 | 49 | To re-build the keymaps from Agda's Emacs mode, run: 50 | 51 | ``` 52 | npm run keymap-gen 53 | ``` 54 | 55 | This runs [`./keymap.el`](./keymap.el), which can also be run manually and pointed to a custom Agda path. 56 | 57 | To print the keymap list, run: 58 | 59 | ``` 60 | npm run keymap-print 61 | ``` 62 | 63 | To build and bundle `./lib/js/bundled.js` (the entry file): 64 | 65 | ``` 66 | npm run build 67 | ``` 68 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | /* This is the BuckleScript configuration file. Note that this is a comment; 2 | BuckleScript comes with a JSON parser that supports comments and trailing 3 | comma. If this screws with your editor highlighting, please tell us by filing 4 | an issue! */ 5 | { 6 | "name": "agda-mode", 7 | "reason": { 8 | "react-jsx": 3 9 | }, 10 | "sources": [ 11 | { 12 | "dir": "src", 13 | "subdirs": true 14 | }, 15 | { 16 | "dir": "test", 17 | "subdirs": true, 18 | "type": "dev" 19 | } 20 | ], 21 | "package-specs": [ 22 | { 23 | "module": "commonjs", 24 | "in-source": false 25 | } 26 | ], 27 | "suffix": ".bs.js", 28 | "namespace": true, 29 | "bs-dev-dependencies": [ 30 | "bs-mocha" 31 | ], 32 | "bs-dependencies": [ 33 | "reason-react", 34 | "@glennsl/bs-json", 35 | "@glennsl/rebase", 36 | "bs-webapi", 37 | "reason-react-update", 38 | "bs-atom2", 39 | "bs-nd", 40 | "reason-promise" 41 | ], 42 | "bsc-flags": [ 43 | "-bs-g" 44 | ], 45 | "refmt": 3 46 | } -------------------------------------------------------------------------------- /lib/js/src/Editors.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Belt_Option = require("bs-platform/lib/js/belt_Option.js"); 5 | var Caml_option = require("bs-platform/lib/js/caml_option.js"); 6 | 7 | function make(editor) { 8 | return { 9 | focused: /* Source */0, 10 | source: editor, 11 | query: undefined 12 | }; 13 | } 14 | 15 | function getID(self) { 16 | return String(self.source.id); 17 | } 18 | 19 | function get(editors) { 20 | var match = editors.focused; 21 | if (match) { 22 | var match$1 = editors.query; 23 | if (match$1 !== undefined) { 24 | return Caml_option.valFromOption(match$1); 25 | } else { 26 | return editors.source; 27 | } 28 | } else { 29 | return editors.source; 30 | } 31 | } 32 | 33 | function on(sort, editors) { 34 | if (sort) { 35 | Belt_Option.forEach(Belt_Option.map(editors.query, (function (prim) { 36 | return atom.views.getView(prim); 37 | })), (function (prim) { 38 | prim.focus(); 39 | return /* () */0; 40 | })); 41 | editors.focused = /* Query */1; 42 | return /* () */0; 43 | } else { 44 | atom.views.getView(editors.source).focus(); 45 | editors.focused = /* Source */0; 46 | return /* () */0; 47 | } 48 | } 49 | 50 | var Focus = { 51 | get: get, 52 | on: on 53 | }; 54 | 55 | function getSymbol(editors) { 56 | var arg = get(editors).getSelectedText(); 57 | return (function (param) { 58 | return (function (param$1) { 59 | return arg.substr(param, param$1); 60 | }); 61 | })(0)(1); 62 | } 63 | 64 | function getTextNode(editors) { 65 | var getLargerSyntaxNode = function (param) { 66 | get(editors).selectLargerSyntaxNode(); 67 | return get(editors).getSelectedText(); 68 | }; 69 | var getPointedWord = function (param) { 70 | get(editors).selectWordsContainingCursors(); 71 | return get(editors).getSelectedText(); 72 | }; 73 | var selectedText = get(editors).getSelectedText(); 74 | if (selectedText === "") { 75 | var largerNode = getLargerSyntaxNode(/* () */0); 76 | if (largerNode === "") { 77 | return getPointedWord(/* () */0); 78 | } else { 79 | var pointedText = getPointedWord(/* () */0); 80 | if (pointedText === "_") { 81 | return getLargerSyntaxNode(/* () */0); 82 | } else { 83 | return pointedText; 84 | } 85 | } 86 | } else { 87 | return selectedText; 88 | } 89 | } 90 | 91 | var $$Selection = { 92 | getSymbol: getSymbol, 93 | getTextNode: getTextNode 94 | }; 95 | 96 | exports.make = make; 97 | exports.getID = getID; 98 | exports.Focus = Focus; 99 | exports.$$Selection = $$Selection; 100 | /* No side effect */ 101 | -------------------------------------------------------------------------------- /lib/js/src/Instance.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 6 | var Root$AgdaMode = require("./View/Root.bs.js"); 7 | var Event$AgdaMode = require("./Util/Event.bs.js"); 8 | var Editors$AgdaMode = require("./Editors.bs.js"); 9 | var TaskRunner$AgdaMode = require("./Task/TaskRunner.bs.js"); 10 | var Caml_chrome_debugger = require("bs-platform/lib/js/caml_chrome_debugger.js"); 11 | var RunningInfo$AgdaMode = require("./RunningInfo.bs.js"); 12 | 13 | function activate(instance) { 14 | if (instance.isLoaded) { 15 | return Curry._1(instance.view.activate, /* () */0); 16 | } else { 17 | return $$Promise.resolved(/* () */0); 18 | } 19 | } 20 | 21 | function deactivate(instance) { 22 | if (instance.isLoaded) { 23 | return Curry._1(instance.view.deactivate, /* () */0); 24 | } else { 25 | return $$Promise.resolved(/* () */0); 26 | } 27 | } 28 | 29 | function destroy(instance) { 30 | return Curry._1(instance.view.destroy, /* () */0); 31 | } 32 | 33 | function make(textEditor) { 34 | atom.views.getView(textEditor).classList.add("agda"); 35 | var editors = Editors$AgdaMode.make(textEditor); 36 | var view = Root$AgdaMode.initialize(editors); 37 | var instance = { 38 | editors: editors, 39 | view: view, 40 | history: { 41 | checkpoints: [], 42 | needsReloading: false 43 | }, 44 | isLoaded: false, 45 | highlightings: [], 46 | goals: [], 47 | connection: undefined, 48 | runningInfo: RunningInfo$AgdaMode.make(/* () */0), 49 | onDispatch: Event$AgdaMode.make(/* () */0), 50 | onConnectionError: Event$AgdaMode.make(/* () */0) 51 | }; 52 | var destructor1 = Curry._1(instance.view.onMouseEvent.on, (function (ev) { 53 | switch (ev.tag | 0) { 54 | case /* JumpToTarget */0 : 55 | TaskRunner$AgdaMode.dispatchCommand(/* Jump */Caml_chrome_debugger.variant("Jump", 9, [ev[0]]), instance); 56 | return /* () */0; 57 | case /* MouseOver */1 : 58 | case /* MouseOut */2 : 59 | return /* () */0; 60 | 61 | } 62 | })); 63 | $$Promise.get(Curry._1(instance.view.onDestroy.once, /* () */0), (function (param) { 64 | return Curry._1(destructor1, /* () */0); 65 | })); 66 | return instance; 67 | } 68 | 69 | function dispatchUndo(instance) { 70 | instance.editors.source.undo(); 71 | if (instance.history.needsReloading) { 72 | TaskRunner$AgdaMode.dispatchCommand(/* Load */0, instance); 73 | instance.history.needsReloading = false; 74 | return /* () */0; 75 | } else { 76 | return 0; 77 | } 78 | } 79 | 80 | function getID(instance) { 81 | return Editors$AgdaMode.getID(instance.editors); 82 | } 83 | 84 | var $$Event = /* alias */0; 85 | 86 | var Goals = /* alias */0; 87 | 88 | var Highlightings = /* alias */0; 89 | 90 | var Connections = /* alias */0; 91 | 92 | var TextEditors = /* alias */0; 93 | 94 | exports.$$Event = $$Event; 95 | exports.Goals = Goals; 96 | exports.Highlightings = Highlightings; 97 | exports.Connections = Connections; 98 | exports.TextEditors = TextEditors; 99 | exports.activate = activate; 100 | exports.deactivate = deactivate; 101 | exports.destroy = destroy; 102 | exports.make = make; 103 | exports.dispatchUndo = dispatchUndo; 104 | exports.getID = getID; 105 | /* Promise Not a pure module */ 106 | -------------------------------------------------------------------------------- /lib/js/src/Instance/Instance__Goals.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Atom = require("atom"); 5 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 6 | var Caml_option = require("bs-platform/lib/js/caml_option.js"); 7 | var Goal$AgdaMode = require("../Goal.bs.js"); 8 | var Parser$AgdaMode = require("../Parser.bs.js"); 9 | var SourceFile$AgdaMode = require("../SourceFile.bs.js"); 10 | 11 | function destroyAll(instance) { 12 | Rebase.$$Array.forEach(Goal$AgdaMode.destroy, instance.goals); 13 | instance.goals = []; 14 | return /* () */0; 15 | } 16 | 17 | function find(index, instance) { 18 | var found = Rebase.$$Array.filter((function (goal) { 19 | return goal.index === index; 20 | }), instance.goals); 21 | return Rebase.$$Array.get(found, 0); 22 | } 23 | 24 | function setCursor(goal, instance) { 25 | var position = goal.range.start.translate(new Atom.Point(0, 3)); 26 | instance.editors.source.setCursorBufferPosition(position); 27 | return /* () */0; 28 | } 29 | 30 | function getPositions(instance) { 31 | return Rebase.$$Array.map((function (range) { 32 | return range.start.translate(new Atom.Point(0, 3)); 33 | }), Rebase.$$Array.map((function (goal) { 34 | return goal.range; 35 | }), instance.goals)); 36 | } 37 | 38 | function getPreviousGoalPosition(instance) { 39 | var previousGoal = { 40 | contents: undefined 41 | }; 42 | var cursor = instance.editors.source.getCursorBufferPosition(); 43 | var positions = getPositions(instance); 44 | Rebase.$$Array.forEach((function (position) { 45 | if (position.isLessThan(cursor)) { 46 | previousGoal.contents = Caml_option.some(position); 47 | return /* () */0; 48 | } else { 49 | return 0; 50 | } 51 | }), positions); 52 | if (previousGoal.contents === undefined) { 53 | previousGoal.contents = Rebase.$$Array.get(positions, Rebase.$$Array.length(positions) - 1 | 0); 54 | } 55 | return previousGoal.contents; 56 | } 57 | 58 | function getNextGoalPosition(instance) { 59 | var nextGoal = { 60 | contents: undefined 61 | }; 62 | var cursor = instance.editors.source.getCursorBufferPosition(); 63 | var positions = getPositions(instance); 64 | Rebase.$$Array.forEach((function (position) { 65 | if (position.isGreaterThan(cursor) && nextGoal.contents === undefined) { 66 | nextGoal.contents = Caml_option.some(position); 67 | return /* () */0; 68 | } else { 69 | return 0; 70 | } 71 | }), positions); 72 | if (nextGoal.contents === undefined) { 73 | nextGoal.contents = Rebase.$$Array.get(positions, 0); 74 | } 75 | return nextGoal.contents; 76 | } 77 | 78 | function instantiateAll(indices, instance) { 79 | destroyAll(instance); 80 | var textEditor = instance.editors.source; 81 | var filePath = Parser$AgdaMode.filepath(Rebase.$$Option.getOr("untitled", textEditor.getPath())); 82 | var textBuffer = textEditor.getBuffer(); 83 | var source = textEditor.getText(); 84 | instance.goals = Rebase.$$Array.map((function (result) { 85 | var start = textBuffer.positionForCharacterIndex(result.originalRange[0]); 86 | var end_ = textBuffer.positionForCharacterIndex(result.originalRange[1]); 87 | var range = new Atom.Range(start, end_); 88 | textEditor.setTextInBufferRange(range, result.content); 89 | return Goal$AgdaMode.make(instance.editors.source, result.index, result.modifiedRange); 90 | }), SourceFile$AgdaMode.parse(indices, filePath, source)); 91 | return /* () */0; 92 | } 93 | 94 | exports.destroyAll = destroyAll; 95 | exports.find = find; 96 | exports.setCursor = setCursor; 97 | exports.getPositions = getPositions; 98 | exports.getPreviousGoalPosition = getPreviousGoalPosition; 99 | exports.getNextGoalPosition = getNextGoalPosition; 100 | exports.instantiateAll = instantiateAll; 101 | /* atom Not a pure module */ 102 | -------------------------------------------------------------------------------- /lib/js/src/Instance/Instance__Highlightings.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Fs = require("fs"); 5 | var Atom = require("atom"); 6 | var Util = require("util"); 7 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 8 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 9 | var Parser$AgdaMode = require("../Parser.bs.js"); 10 | var Caml_chrome_debugger = require("bs-platform/lib/js/caml_chrome_debugger.js"); 11 | var Highlighting$AgdaMode = require("../Highlighting.bs.js"); 12 | 13 | function add(annotation, instance) { 14 | var textBuffer = instance.editors.source.getBuffer(); 15 | var startPoint = textBuffer.positionForCharacterIndex(annotation.start - 1 | 0); 16 | var endPoint = textBuffer.positionForCharacterIndex(annotation.end_ - 1 | 0); 17 | var range = new Atom.Range(startPoint, endPoint); 18 | var marker = instance.editors.source.markBufferRange(range); 19 | instance.highlightings.push(marker); 20 | var types = annotation.types.join(" "); 21 | instance.editors.source.decorateMarker(marker, { 22 | type: "highlight", 23 | class: "highlight-decoration " + types 24 | }); 25 | return /* () */0; 26 | } 27 | 28 | function addMany(annotations, instance) { 29 | return Rebase.$$Array.forEach((function (annotation) { 30 | return add(annotation, instance); 31 | }), Rebase.$$Array.filter(Highlighting$AgdaMode.Annotation.shouldHighlight, annotations)); 32 | } 33 | 34 | function addFromFile(filepath, instance) { 35 | var readFile = Util.promisify((function (prim, prim$1) { 36 | Fs.readFile(prim, prim$1); 37 | return /* () */0; 38 | })); 39 | return $$Promise.map($$Promise.Js.toResult($$Promise.Js.fromBsPromise(readFile(filepath))), (function (param) { 40 | if (param.tag) { 41 | console.log(param[0]); 42 | console.log("cannot read the indirect highlighting file: " + filepath); 43 | return /* () */0; 44 | } else { 45 | Rebase.$$Array.forEach((function (annotation) { 46 | return add(annotation, instance); 47 | }), Rebase.$$Array.filter(Highlighting$AgdaMode.Annotation.shouldHighlight, Rebase.$$Array.flatMap((function (x) { 48 | return x; 49 | }), Rebase.$$Array.map((function (tokens) { 50 | if (tokens.tag) { 51 | return Highlighting$AgdaMode.Annotation.parseIndirectHighlightings(tokens[0]); 52 | } else { 53 | return []; 54 | } 55 | }), Rebase.$$Array.filterMap(Rebase.$$Option.fromResult, Parser$AgdaMode.SExpression.parse(param[0].toString())))))); 56 | return /* () */0; 57 | } 58 | })); 59 | } 60 | 61 | function destroyAll(instance) { 62 | Rebase.$$Array.forEach((function (prim) { 63 | prim.destroy(); 64 | return /* () */0; 65 | }), instance.highlightings); 66 | instance.highlightings = []; 67 | return /* () */0; 68 | } 69 | 70 | function execute(instance, param) { 71 | if (param.tag) { 72 | var filepath = param[0]; 73 | return $$Promise.map($$Promise.map(addFromFile(filepath, instance), (function (param) { 74 | return /* Ok */Caml_chrome_debugger.variant("Ok", 0, [(Fs.unlink(filepath, (function (param) { 75 | return /* () */0; 76 | })), /* () */0)]); 77 | })), (function (param) { 78 | return []; 79 | })); 80 | } else { 81 | addMany(param[0], instance); 82 | return $$Promise.resolved([]); 83 | } 84 | } 85 | 86 | exports.add = add; 87 | exports.addMany = addMany; 88 | exports.addFromFile = addFromFile; 89 | exports.destroyAll = destroyAll; 90 | exports.execute = execute; 91 | /* fs Not a pure module */ 92 | -------------------------------------------------------------------------------- /lib/js/src/Instance/Instance__TextEditors.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 6 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 7 | var Caml_option = require("bs-platform/lib/js/caml_option.js"); 8 | var Goal$AgdaMode = require("../Goal.bs.js"); 9 | var Parser$AgdaMode = require("../Parser.bs.js"); 10 | var Caml_chrome_debugger = require("bs-platform/lib/js/caml_chrome_debugger.js"); 11 | var Instance__Goals$AgdaMode = require("./Instance__Goals.bs.js"); 12 | 13 | function getPath(instance) { 14 | return Parser$AgdaMode.filepath(Rebase.$$Option.getOr("untitled", instance.editors.source.getPath())); 15 | } 16 | 17 | function pointingAt(cursor, instance) { 18 | var cursor_ = cursor !== undefined ? Caml_option.valFromOption(cursor) : instance.editors.source.getCursorBufferPosition(); 19 | var pointedGoals = Rebase.$$Array.filter((function (goal) { 20 | return goal.range.containsPoint(cursor_); 21 | }), instance.goals); 22 | return Rebase.$$Array.get(pointedGoals, 0); 23 | } 24 | 25 | function getPointedGoal(instance) { 26 | var pointed = pointingAt(undefined, instance); 27 | if (pointed !== undefined) { 28 | return $$Promise.resolved(/* Ok */Caml_chrome_debugger.variant("Ok", 0, [pointed])); 29 | } else { 30 | return $$Promise.resolved(/* Error */Caml_chrome_debugger.variant("Error", 1, [/* OutOfGoal */1])); 31 | } 32 | } 33 | 34 | function restoreCursorPosition(callback, instance) { 35 | var originalPosition = instance.editors.source.getCursorBufferPosition(); 36 | return $$Promise.map(Curry._1(callback, /* () */0), (function (result) { 37 | var pointed = pointingAt(Caml_option.some(originalPosition), instance); 38 | if (pointed !== undefined) { 39 | var goal = pointed; 40 | if (Goal$AgdaMode.isEmpty(goal)) { 41 | Instance__Goals$AgdaMode.setCursor(goal, instance); 42 | } else { 43 | instance.editors.source.setCursorBufferPosition(originalPosition); 44 | } 45 | } else { 46 | instance.editors.source.setCursorBufferPosition(originalPosition); 47 | } 48 | return result; 49 | })); 50 | } 51 | 52 | function startCheckpoint(command, instance) { 53 | var checkpoint = instance.editors.source.createCheckpoint(); 54 | instance.history.checkpoints.push(checkpoint); 55 | if (Rebase.$$Array.length(instance.history.checkpoints) === 1) { 56 | instance.history.needsReloading = typeof command === "number" ? ( 57 | command >= 13 ? command < 17 : command === 6 58 | ) : false; 59 | return /* () */0; 60 | } else { 61 | return 0; 62 | } 63 | } 64 | 65 | function endCheckpoint(instance) { 66 | var checkpoint = instance.history.checkpoints.pop(); 67 | if (Rebase.$$Array.length(instance.history.checkpoints) === 0) { 68 | Rebase.$$Option.forEach((function (n) { 69 | instance.editors.source.groupChangesSinceCheckpoint(n); 70 | return /* () */0; 71 | }), checkpoint === undefined ? undefined : Caml_option.some(checkpoint)); 72 | } 73 | return /* () */0; 74 | } 75 | 76 | exports.getPath = getPath; 77 | exports.pointingAt = pointingAt; 78 | exports.getPointedGoal = getPointedGoal; 79 | exports.restoreCursorPosition = restoreCursorPosition; 80 | exports.startCheckpoint = startCheckpoint; 81 | exports.endCheckpoint = endCheckpoint; 82 | /* Promise Not a pure module */ 83 | -------------------------------------------------------------------------------- /lib/js/src/Instance/Instance__Type.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, 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/Log.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Belt_Array = require("bs-platform/lib/js/belt_Array.js"); 5 | var Belt_Option = require("bs-platform/lib/js/belt_Option.js"); 6 | var Parser$AgdaMode = require("./Parser.bs.js"); 7 | var Caml_splice_call = require("bs-platform/lib/js/caml_splice_call.js"); 8 | var Request$AgdaMode = require("./Request.bs.js"); 9 | var Response$AgdaMode = require("./Response.bs.js"); 10 | 11 | function make(cmd) { 12 | return { 13 | request: cmd, 14 | response: { 15 | rawText: [], 16 | sexpression: [], 17 | response: [], 18 | error: [] 19 | } 20 | }; 21 | } 22 | 23 | function serialize(i, self) { 24 | var fold = function (text, title) { 25 | return "
" + (String(title) + (" \n

\n\n" + (String(text) + "\n\n

\n
\n"))); 26 | }; 27 | var quote = function (xs, title) { 28 | var xs$1 = fold(Caml_splice_call.spliceObjApply("\n", "concat", [Belt_Array.map(xs, (function (x) { 29 | return "```\n" + (String(x) + "\n```\n"); 30 | }))]), title); 31 | return Caml_splice_call.spliceObjApply("\n", "concat", [Belt_Array.map(xs$1.split(/\n/), (function (__x) { 32 | return Belt_Option.mapWithDefault(__x, "", (function (x) { 33 | return " " + x; 34 | })); 35 | }))]); 36 | }; 37 | var request = Request$AgdaMode.toString(self.request); 38 | var rawText = quote(self.response.rawText, "raw text"); 39 | var sexpression = quote(Belt_Array.map(self.response.sexpression, Parser$AgdaMode.SExpression.toString), "s-expression"); 40 | var response = quote(Belt_Array.map(self.response.response, Response$AgdaMode.toString), "response"); 41 | var error = quote(Belt_Array.map(self.response.error, Parser$AgdaMode.$$Error.toString), "error"); 42 | return "" + (String(i) + (". **" + (String(request) + ("**\n" + (String(rawText) + ("\n" + (String(sexpression) + ("\n" + (String(response) + ("\n" + (String(error) + "\n"))))))))))); 43 | } 44 | 45 | var Entry = { 46 | make: make, 47 | serialize: serialize 48 | }; 49 | 50 | function createEntry(cmd, log) { 51 | var entry = make(cmd); 52 | log.push(entry); 53 | return /* () */0; 54 | } 55 | 56 | function updateLatestEntry(f, log) { 57 | var n = log.length; 58 | var lastEntry = Belt_Array.get(log, n - 1 | 0); 59 | return Belt_Option.forEach(lastEntry, f); 60 | } 61 | 62 | function logRawText(text) { 63 | return (function (param) { 64 | return updateLatestEntry((function (entry) { 65 | entry.response.rawText.push(text); 66 | return /* () */0; 67 | }), param); 68 | }); 69 | } 70 | 71 | function logSExpression(text) { 72 | return (function (param) { 73 | return updateLatestEntry((function (entry) { 74 | entry.response.sexpression.push(text); 75 | return /* () */0; 76 | }), param); 77 | }); 78 | } 79 | 80 | function logResponse(text) { 81 | return (function (param) { 82 | return updateLatestEntry((function (entry) { 83 | entry.response.response.push(text); 84 | return /* () */0; 85 | }), param); 86 | }); 87 | } 88 | 89 | function logError(text) { 90 | return (function (param) { 91 | return updateLatestEntry((function (log) { 92 | log.response.error.push(text); 93 | return /* () */0; 94 | }), param); 95 | }); 96 | } 97 | 98 | function serialize$1(x) { 99 | return Caml_splice_call.spliceObjApply("\n", "concat", [Belt_Array.mapWithIndex(x, serialize)]); 100 | } 101 | 102 | exports.Entry = Entry; 103 | exports.createEntry = createEntry; 104 | exports.updateLatestEntry = updateLatestEntry; 105 | exports.logRawText = logRawText; 106 | exports.logSExpression = logSExpression; 107 | exports.logResponse = logResponse; 108 | exports.logError = logError; 109 | exports.serialize = serialize$1; 110 | /* Parser-AgdaMode Not a pure module */ 111 | -------------------------------------------------------------------------------- /lib/js/src/Node/N.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Caml_exceptions = require("bs-platform/lib/js/caml_exceptions.js"); 5 | 6 | var Exception = Caml_exceptions.create("N-AgdaMode.Exception"); 7 | 8 | var OS = /* alias */0; 9 | 10 | var Util = /* alias */0; 11 | 12 | var Fs = /* alias */0; 13 | 14 | exports.Exception = Exception; 15 | exports.OS = OS; 16 | exports.Util = Util; 17 | exports.Fs = Fs; 18 | /* No side effect */ 19 | -------------------------------------------------------------------------------- /lib/js/src/Node/Node__Fs.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, 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/Node/Node__OS.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, 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/Node/Node__Util.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, 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/Parser/Parser__Type.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var $$Array = require("bs-platform/lib/js/array.js"); 5 | 6 | function toString(param) { 7 | if (param.tag) { 8 | return "[" + ($$Array.map(toString, param[0]).join(", ") + "]"); 9 | } else { 10 | return "\"" + (param[0] + "\""); 11 | } 12 | } 13 | 14 | var SExpression = { 15 | toString: toString 16 | }; 17 | 18 | exports.SExpression = SExpression; 19 | /* No side effect */ 20 | -------------------------------------------------------------------------------- /lib/js/src/RunningInfo.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Atom = require("atom"); 5 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 6 | var Caml_option = require("bs-platform/lib/js/caml_option.js"); 7 | var Caml_splice_call = require("bs-platform/lib/js/caml_splice_call.js"); 8 | 9 | function make(param) { 10 | return { 11 | editor: undefined, 12 | isOpeningEditor: false, 13 | buffer: [], 14 | subscriptions: new Atom.CompositeDisposable() 15 | }; 16 | } 17 | 18 | var itemOptions = { 19 | initialLine: 0, 20 | initialColumn: 0, 21 | split: "right", 22 | activatePane: false, 23 | activateItem: false, 24 | pending: false, 25 | searchAllPanes: true, 26 | location: undefined 27 | }; 28 | 29 | function destroy(self) { 30 | self.editor = undefined; 31 | self.isOpeningEditor = false; 32 | self.buffer = []; 33 | self.subscriptions.dispose(); 34 | return /* () */0; 35 | } 36 | 37 | function add(info, self) { 38 | var match = self.editor; 39 | if (match !== undefined) { 40 | Caml_option.valFromOption(match).insertText(info); 41 | return $$Promise.resolved(/* () */0); 42 | } else if (self.isOpeningEditor) { 43 | self.buffer.unshift(info); 44 | return $$Promise.resolved(/* () */0); 45 | } else { 46 | self.isOpeningEditor = true; 47 | return $$Promise.map($$Promise.mapOk($$Promise.Js.toResult($$Promise.Js.fromBsPromise(atom.workspace.open("agda-mode://running-info", itemOptions))), (function (newItem) { 48 | self.isOpeningEditor = false; 49 | self.editor = Caml_option.some(newItem); 50 | newItem.insertText(Caml_splice_call.spliceObjApply("", "concat", [self.buffer])); 51 | self.buffer = []; 52 | self.subscriptions.add(newItem.onDidDestroy((function (param) { 53 | return destroy(self); 54 | }))); 55 | return /* () */0; 56 | })), (function (param) { 57 | return /* () */0; 58 | })); 59 | } 60 | } 61 | 62 | exports.make = make; 63 | exports.itemOptions = itemOptions; 64 | exports.destroy = destroy; 65 | exports.add = add; 66 | /* atom Not a pure module */ 67 | -------------------------------------------------------------------------------- /lib/js/src/Task/Task.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 5 | var Caml_chrome_debugger = require("bs-platform/lib/js/caml_chrome_debugger.js"); 6 | 7 | var Highlightings = { }; 8 | 9 | function $$return(x) { 10 | return $$Promise.resolved(/* Ok */Caml_chrome_debugger.variant("Ok", 0, [x])); 11 | } 12 | 13 | exports.Highlightings = Highlightings; 14 | exports.$$return = $$return; 15 | /* Promise Not a pure module */ 16 | -------------------------------------------------------------------------------- /lib/js/src/Type/Type.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | 5 | var $$Location = /* alias */0; 6 | 7 | var View = /* alias */0; 8 | 9 | exports.$$Location = $$Location; 10 | exports.View = View; 11 | /* No side effect */ 12 | -------------------------------------------------------------------------------- /lib/js/src/Type/Type__View.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Buffer$AgdaMode = require("../View/Panel/InputMethod/Buffer.bs.js"); 6 | 7 | var Header = { }; 8 | 9 | var emitter = React.createContext((function (_ev) { 10 | return /* () */0; 11 | })); 12 | 13 | var make = emitter.Provider; 14 | 15 | var Provider = { 16 | make: make 17 | }; 18 | 19 | var Mouse = { 20 | emitter: emitter, 21 | Provider: Provider 22 | }; 23 | 24 | function reducer(_state, action) { 25 | return { 26 | inputMethod: action[0] 27 | }; 28 | } 29 | 30 | var initialState = { 31 | inputMethod: { 32 | activated: false, 33 | markers: [], 34 | buffer: Buffer$AgdaMode.initial 35 | } 36 | }; 37 | 38 | var debugDispatch = React.createContext((function (param) { 39 | return /* () */0; 40 | })); 41 | 42 | var make$1 = debugDispatch.Provider; 43 | 44 | var Provider$1 = { 45 | make: make$1 46 | }; 47 | 48 | var Debug = { 49 | reducer: reducer, 50 | initialState: initialState, 51 | debugDispatch: debugDispatch, 52 | Provider: Provider$1 53 | }; 54 | 55 | exports.Header = Header; 56 | exports.Mouse = Mouse; 57 | exports.Debug = Debug; 58 | /* emitter Not a pure module */ 59 | -------------------------------------------------------------------------------- /lib/js/src/Util/Channel.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 6 | var Resource$AgdaMode = require("./Resource.bs.js"); 7 | 8 | function send(input, channel) { 9 | return $$Promise.flatMap(Curry._1(channel.acquire, /* () */0), (function (trigger) { 10 | return Curry._1(trigger, input); 11 | })); 12 | } 13 | 14 | function sendTo(channel, input) { 15 | return $$Promise.flatMap(Curry._1(channel.acquire, /* () */0), (function (trigger) { 16 | return Curry._1(trigger, input); 17 | })); 18 | } 19 | 20 | function recv(callback, channel) { 21 | return Curry._1(channel.supply, callback); 22 | } 23 | 24 | var make = Resource$AgdaMode.make; 25 | 26 | exports.make = make; 27 | exports.send = send; 28 | exports.sendTo = sendTo; 29 | exports.recv = recv; 30 | /* Promise Not a pure module */ 31 | -------------------------------------------------------------------------------- /lib/js/src/Util/Event.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Events = require("events"); 5 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 6 | var Nd__Events = require("bs-nd/lib/js/src/Nd__Events.bs.js"); 7 | 8 | function make(param) { 9 | var emitter = new Events.EventEmitter(); 10 | return { 11 | emitter: emitter, 12 | emit: (function (x) { 13 | emitter.emit("data", x); 14 | return /* () */0; 15 | }), 16 | once: (function (param) { 17 | var match = $$Promise.pending(/* () */0); 18 | emitter.once("data", match[1]); 19 | return match[0]; 20 | }), 21 | on: (function (callback) { 22 | Nd__Events.on("data", callback, emitter); 23 | return (function (param) { 24 | Nd__Events.removeListener("data", callback, emitter); 25 | return /* () */0; 26 | }); 27 | }), 28 | destroy: (function (param) { 29 | emitter.removeAllListeners(); 30 | return /* () */0; 31 | }) 32 | }; 33 | } 34 | 35 | exports.make = make; 36 | /* events Not a pure module */ 37 | -------------------------------------------------------------------------------- /lib/js/src/Util/Resource.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 6 | var Belt_List = require("bs-platform/lib/js/belt_List.js"); 7 | var Caml_option = require("bs-platform/lib/js/caml_option.js"); 8 | var Caml_chrome_debugger = require("bs-platform/lib/js/caml_chrome_debugger.js"); 9 | 10 | function make(param) { 11 | var resource = { 12 | contents: undefined 13 | }; 14 | var queue = { 15 | contents: /* [] */0 16 | }; 17 | var acquire = function (param) { 18 | var match = resource.contents; 19 | if (match !== undefined) { 20 | return $$Promise.resolved(Caml_option.valFromOption(match)); 21 | } else { 22 | var match$1 = $$Promise.pending(/* () */0); 23 | queue.contents = /* :: */Caml_chrome_debugger.simpleVariant("::", [ 24 | match$1[1], 25 | queue.contents 26 | ]); 27 | return match$1[0]; 28 | } 29 | }; 30 | var supply = function (x) { 31 | resource.contents = Caml_option.some(x); 32 | return Belt_List.forEach(queue.contents, (function (resolve) { 33 | return Curry._1(resolve, x); 34 | })); 35 | }; 36 | return { 37 | acquire: acquire, 38 | supply: supply 39 | }; 40 | } 41 | 42 | exports.make = make; 43 | /* Promise Not a pure module */ 44 | -------------------------------------------------------------------------------- /lib/js/src/View/Channels.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Channel$AgdaMode = require("../Util/Channel.bs.js"); 6 | 7 | function make(param) { 8 | return { 9 | destroy: Channel$AgdaMode.make(/* () */0), 10 | activatePanel: Channel$AgdaMode.make(/* () */0), 11 | deactivatePanel: Channel$AgdaMode.make(/* () */0), 12 | toggleDocking: Channel$AgdaMode.make(/* () */0), 13 | display: Channel$AgdaMode.make(/* () */0), 14 | inquire: Channel$AgdaMode.make(/* () */0), 15 | updateIsPending: Channel$AgdaMode.make(/* () */0), 16 | activateInputMethod: Channel$AgdaMode.make(/* () */0), 17 | interceptAndInsertKey: Channel$AgdaMode.make(/* () */0), 18 | navigateSettings: Channel$AgdaMode.make(/* () */0), 19 | updateConnection: Channel$AgdaMode.make(/* () */0), 20 | inquireConnection: Channel$AgdaMode.make(/* () */0) 21 | }; 22 | } 23 | 24 | var context = React.createContext(make(/* () */0)); 25 | 26 | var make$1 = context.Provider; 27 | 28 | var Provider = { 29 | make: make$1 30 | }; 31 | 32 | var $$Event = /* alias */0; 33 | 34 | exports.$$Event = $$Event; 35 | exports.make = make; 36 | exports.context = context; 37 | exports.Provider = Provider; 38 | /* context Not a pure module */ 39 | -------------------------------------------------------------------------------- /lib/js/src/View/Component.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | 5 | var $$Range = /* alias */0; 6 | 7 | var Link = /* alias */0; 8 | 9 | exports.$$Range = $$Range; 10 | exports.Link = Link; 11 | /* No side effect */ 12 | -------------------------------------------------------------------------------- /lib/js/src/View/Component__Link.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var React = require("react"); 6 | var $$String = require("bs-platform/lib/js/string.js"); 7 | var Type__View$AgdaMode = require("../Type/Type__View.bs.js"); 8 | var Caml_chrome_debugger = require("bs-platform/lib/js/caml_chrome_debugger.js"); 9 | 10 | function Component__Link(Props) { 11 | var targetOpt = Props.target; 12 | var jumpOpt = Props.jump; 13 | var hoverOpt = Props.hover; 14 | var classNameOpt = Props.className; 15 | var children = Props.children; 16 | var target = targetOpt !== undefined ? targetOpt : /* RangeLink */Caml_chrome_debugger.variant("RangeLink", 0, [/* NoRange */0]); 17 | var jump = jumpOpt !== undefined ? jumpOpt : false; 18 | var hover = hoverOpt !== undefined ? hoverOpt : false; 19 | var className = classNameOpt !== undefined ? classNameOpt : /* [] */0; 20 | var target_; 21 | if (target.tag) { 22 | target_ = /* HoleLink */Caml_chrome_debugger.variant("HoleLink", 1, [target[0]]); 23 | } else { 24 | var range = target[0]; 25 | target_ = range && range[1].length !== 0 ? /* RangeLink */Caml_chrome_debugger.variant("RangeLink", 0, [range]) : undefined; 26 | } 27 | var emit = React.useContext(Type__View$AgdaMode.Mouse.emitter); 28 | if (target_ !== undefined) { 29 | var t = target_; 30 | return React.createElement("span", { 31 | className: $$String.concat(" ", /* :: */Caml_chrome_debugger.simpleVariant("::", [ 32 | "link", 33 | className 34 | ])), 35 | onClick: (function (param) { 36 | if (jump) { 37 | return Curry._1(emit, /* JumpToTarget */Caml_chrome_debugger.variant("JumpToTarget", 0, [t])); 38 | } else { 39 | return 0; 40 | } 41 | }), 42 | onMouseOut: (function (param) { 43 | if (hover) { 44 | return Curry._1(emit, /* MouseOut */Caml_chrome_debugger.variant("MouseOut", 2, [t])); 45 | } else { 46 | return 0; 47 | } 48 | }), 49 | onMouseOver: (function (param) { 50 | if (hover) { 51 | return Curry._1(emit, /* MouseOver */Caml_chrome_debugger.variant("MouseOver", 1, [t])); 52 | } else { 53 | return 0; 54 | } 55 | }) 56 | }, children); 57 | } else { 58 | return React.createElement("span", { 59 | className: $$String.concat(" ", /* :: */Caml_chrome_debugger.simpleVariant("::", [ 60 | "link", 61 | className 62 | ])) 63 | }, children); 64 | } 65 | } 66 | 67 | var make = Component__Link; 68 | 69 | exports.make = make; 70 | /* react Not a pure module */ 71 | -------------------------------------------------------------------------------- /lib/js/src/View/Component__Range.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Caml_chrome_debugger = require("bs-platform/lib/js/caml_chrome_debugger.js"); 6 | var Type__Location$AgdaMode = require("../Type/Type__Location.bs.js"); 7 | var Component__Link$AgdaMode = require("./Component__Link.bs.js"); 8 | 9 | function Component__Range(Props) { 10 | var range = Props.range; 11 | var abbrOpt = Props.abbr; 12 | var abbr = abbrOpt !== undefined ? abbrOpt : false; 13 | if (abbr) { 14 | return React.createElement(Component__Link$AgdaMode.make, { 15 | target: /* RangeLink */Caml_chrome_debugger.variant("RangeLink", 0, [range]), 16 | jump: true, 17 | children: React.createElement("span", { 18 | className: "text-subtle range icon icon-link" 19 | }) 20 | }); 21 | } else { 22 | return React.createElement(Component__Link$AgdaMode.make, { 23 | target: /* RangeLink */Caml_chrome_debugger.variant("RangeLink", 0, [range]), 24 | jump: true, 25 | children: React.createElement("span", { 26 | className: "text-subtle range icon icon-link" 27 | }, Type__Location$AgdaMode.$$Range.toString(range)) 28 | }); 29 | } 30 | } 31 | 32 | var Link = /* alias */0; 33 | 34 | var make = Component__Range; 35 | 36 | exports.Link = Link; 37 | exports.make = make; 38 | /* react Not a pure module */ 39 | -------------------------------------------------------------------------------- /lib/js/src/View/Emacs/Emacs.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | 5 | var Component = /* alias */0; 6 | 7 | var Parser = /* alias */0; 8 | 9 | var AllGoalsWarnings = /* alias */0; 10 | 11 | exports.Component = Component; 12 | exports.Parser = Parser; 13 | exports.AllGoalsWarnings = AllGoalsWarnings; 14 | /* No side effect */ 15 | -------------------------------------------------------------------------------- /lib/js/src/View/Emacs/Emacs__Body.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Emacs__Error$AgdaMode = require("./Emacs__Error.bs.js"); 6 | var Emacs__Context$AgdaMode = require("./Emacs__Context.bs.js"); 7 | var Emacs__ParseError$AgdaMode = require("./Emacs__ParseError.bs.js"); 8 | var Emacs__WhyInScope$AgdaMode = require("./Emacs__WhyInScope.bs.js"); 9 | var Emacs__SearchAbout$AgdaMode = require("./Emacs__SearchAbout.bs.js"); 10 | var Emacs__GoalTypeContext$AgdaMode = require("./Emacs__GoalTypeContext.bs.js"); 11 | var Emacs__AllGoalsWarnings$AgdaMode = require("./Emacs__AllGoalsWarnings.bs.js"); 12 | 13 | function Emacs__Body(Props) { 14 | var data = Props.data; 15 | switch (data.tag | 0) { 16 | case /* AllGoalsWarnings */0 : 17 | return React.createElement(Emacs__AllGoalsWarnings$AgdaMode.make, { 18 | value: data[0] 19 | }); 20 | case /* GoalTypeContext */1 : 21 | return React.createElement(Emacs__GoalTypeContext$AgdaMode.make, { 22 | body: data[0] 23 | }); 24 | case /* Context */2 : 25 | case /* Constraints */3 : 26 | break; 27 | case /* WhyInScope */4 : 28 | return React.createElement(Emacs__WhyInScope$AgdaMode.make, { 29 | body: data[0] 30 | }); 31 | case /* SearchAbout */5 : 32 | return React.createElement(Emacs__SearchAbout$AgdaMode.make, { 33 | body: data[0] 34 | }); 35 | case /* Error */6 : 36 | return React.createElement(Emacs__Error$AgdaMode.make, { 37 | body: data[0] 38 | }); 39 | case /* ParseError */7 : 40 | return React.createElement(Emacs__ParseError$AgdaMode.make, { 41 | connection: data[0] 42 | }); 43 | case /* PlainText */8 : 44 | var body = data[0]; 45 | if (body === "") { 46 | return null; 47 | } else { 48 | return React.createElement("p", undefined, body); 49 | } 50 | 51 | } 52 | return React.createElement(Emacs__Context$AgdaMode.make, { 53 | body: data[0] 54 | }); 55 | } 56 | 57 | var make = Emacs__Body; 58 | 59 | exports.make = make; 60 | /* react Not a pure module */ 61 | -------------------------------------------------------------------------------- /lib/js/src/View/Emacs/Emacs__Context.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 6 | var Emacs__Parser$AgdaMode = require("./Emacs__Parser.bs.js"); 7 | var Emacs__Component$AgdaMode = require("./Emacs__Component.bs.js"); 8 | 9 | function parse(raw) { 10 | var lines = Emacs__Parser$AgdaMode.unindent(raw.split("\n")); 11 | return Rebase.$$Array.filterMap((function (x) { 12 | return x; 13 | }), Rebase.$$Array.map(Emacs__Component$AgdaMode.Output.parse, lines)); 14 | } 15 | 16 | function Emacs__Context(Props) { 17 | var body = Props.body; 18 | return React.createElement("ul", undefined, Rebase.$$Array.mapi((function (value, i) { 19 | return React.createElement(Emacs__Component$AgdaMode.Output.make, { 20 | value: value, 21 | key: String(i) 22 | }); 23 | }), parse(body))); 24 | } 25 | 26 | var make = Emacs__Context; 27 | 28 | exports.parse = parse; 29 | exports.make = make; 30 | /* react Not a pure module */ 31 | -------------------------------------------------------------------------------- /lib/js/src/View/Emacs/Emacs__Error.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 6 | var Js_dict = require("bs-platform/lib/js/js_dict.js"); 7 | var Util$AgdaMode = require("../../Util/Util.bs.js"); 8 | var Emacs__Parser$AgdaMode = require("./Emacs__Parser.bs.js"); 9 | var Emacs__Component$AgdaMode = require("./Emacs__Component.bs.js"); 10 | 11 | function parse(raw) { 12 | var lines = raw.split("\n"); 13 | var __x = Emacs__Parser$AgdaMode.partiteWarningsOrErrors("errors")(Util$AgdaMode.Dict.partite((function (param) { 14 | if (param[1] === 0) { 15 | return "errors"; 16 | } 17 | 18 | }), lines)); 19 | return Rebase.$$Option.mapOr((function (metas) { 20 | return Rebase.$$Array.filterMap((function (x) { 21 | return x; 22 | }), Rebase.$$Array.map(Emacs__Component$AgdaMode.WarningError.parseError, metas)); 23 | }), [], Js_dict.get(__x, "errors")); 24 | } 25 | 26 | function Emacs__Error(Props) { 27 | var body = Props.body; 28 | return React.createElement("ul", undefined, Rebase.$$Array.mapi((function (value, i) { 29 | return React.createElement(Emacs__Component$AgdaMode.WarningError.make, { 30 | value: value, 31 | key: String(i) 32 | }); 33 | }), parse(body))); 34 | } 35 | 36 | var make = Emacs__Error; 37 | 38 | exports.parse = parse; 39 | exports.make = make; 40 | /* react Not a pure module */ 41 | -------------------------------------------------------------------------------- /lib/js/src/View/Emacs/Emacs__ParseError.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Connection$AgdaMode = require("../../Connection.bs.js"); 6 | 7 | function Emacs__ParseError(Props) { 8 | var connection = Props.connection; 9 | return React.createElement("section", undefined, React.createElement("p", undefined, "Something went terribly wrong when trying to parse some responses from Agda"), React.createElement("p", { 10 | className: "text-warning" 11 | }, "Please press the button down here, copy the generated log and paste it ", React.createElement("a", { 12 | href: "https://github.com/banacorn/agda-mode/issues/new" 13 | }, "here")), React.createElement("p", undefined, React.createElement("button", { 14 | className: "btn btn-primary icon icon-clippy", 15 | onClick: (function (param) { 16 | return Connection$AgdaMode.dump(connection); 17 | }) 18 | }, "Dump log"))); 19 | } 20 | 21 | var make = Emacs__ParseError; 22 | 23 | exports.make = make; 24 | /* react Not a pure module */ 25 | -------------------------------------------------------------------------------- /lib/js/src/View/Emacs/Emacs__SearchAbout.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 6 | var Emacs__Parser$AgdaMode = require("./Emacs__Parser.bs.js"); 7 | var Emacs__Component$AgdaMode = require("./Emacs__Component.bs.js"); 8 | 9 | function parse(raw) { 10 | var lines = raw.split("\n"); 11 | var target = Rebase.$$Option.getOr("???", Rebase.$$Option.map((function (param) { 12 | return param.slice(18); 13 | }), Rebase.$$Array.get(lines, 0))); 14 | var outputs = Rebase.$$Array.filterMap((function (x) { 15 | return x; 16 | }), Rebase.$$Array.map(Emacs__Component$AgdaMode.Output.parse, Emacs__Parser$AgdaMode.unindent(Rebase.$$Array.map((function (s) { 17 | return s.slice(2); 18 | }), lines.slice(1))))); 19 | return /* tuple */[ 20 | target, 21 | outputs 22 | ]; 23 | } 24 | 25 | function Emacs__SearchAbout(Props) { 26 | var body = Props.body; 27 | var match = parse(body); 28 | var outputs = match[1]; 29 | var target = match[0]; 30 | if (Rebase.$$Array.length(outputs) === 0) { 31 | return React.createElement("p", undefined, "There are no definitions about " + target); 32 | } else { 33 | return React.createElement(React.Fragment, undefined, React.createElement("p", undefined, "Definitions about " + (target + ":")), React.createElement("ul", undefined, Rebase.$$Array.mapi((function (value, i) { 34 | return React.createElement(Emacs__Component$AgdaMode.Output.make, { 35 | value: value, 36 | key: String(i) 37 | }); 38 | }), outputs))); 39 | } 40 | } 41 | 42 | var make = Emacs__SearchAbout; 43 | 44 | exports.parse = parse; 45 | exports.make = make; 46 | /* react Not a pure module */ 47 | -------------------------------------------------------------------------------- /lib/js/src/View/Emacs/Emacs__WhyInScope.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 6 | var Emacs__Component$AgdaMode = require("./Emacs__Component.bs.js"); 7 | 8 | function parse(raw) { 9 | return Rebase.$$Option.getOr([], Emacs__Component$AgdaMode.PlainText.parse(raw)); 10 | } 11 | 12 | function Emacs__WhyInScope(Props) { 13 | var body = Props.body; 14 | var value = parse(body); 15 | return React.createElement("p", undefined, React.createElement(Emacs__Component$AgdaMode.PlainText.make, { 16 | value: value 17 | })); 18 | } 19 | 20 | var make = Emacs__WhyInScope; 21 | 22 | exports.parse = parse; 23 | exports.make = make; 24 | /* react Not a pure module */ 25 | -------------------------------------------------------------------------------- /lib/js/src/View/Events.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Event$AgdaMode = require("../Util/Event.bs.js"); 5 | 6 | function make(param) { 7 | var onInquire = Event$AgdaMode.make(/* () */0); 8 | var onInputMethodChange = Event$AgdaMode.make(/* () */0); 9 | var onMouseEvent = Event$AgdaMode.make(/* () */0); 10 | return { 11 | onInquire: onInquire, 12 | onInputMethodChange: onInputMethodChange, 13 | onMouseEvent: onMouseEvent 14 | }; 15 | } 16 | 17 | exports.make = make; 18 | /* Event-AgdaMode Not a pure module */ 19 | -------------------------------------------------------------------------------- /lib/js/src/View/Hook.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var React = require("react"); 6 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 7 | var Channel$AgdaMode = require("../Util/Channel.bs.js"); 8 | 9 | function useDidUpdateEffect(f, inputs) { 10 | var didMountRef = React.useRef(false); 11 | React.useEffect((function () { 12 | if (didMountRef.current) { 13 | return Curry._1(f, /* () */0); 14 | } else { 15 | didMountRef.current = true; 16 | return ; 17 | } 18 | }), inputs); 19 | return /* () */0; 20 | } 21 | 22 | function useDidUpdateEffect2(f, param) { 23 | var didMountRef = React.useRef(false); 24 | React.useEffect((function () { 25 | if (didMountRef.current) { 26 | return Curry._1(f, /* () */0); 27 | } else { 28 | didMountRef.current = true; 29 | return ; 30 | } 31 | }), /* tuple */[ 32 | param[0], 33 | param[1] 34 | ]); 35 | return /* () */0; 36 | } 37 | 38 | function useState(init) { 39 | var match = React.useState((function () { 40 | return init; 41 | })); 42 | var setState = match[1]; 43 | var setState$prime = function (value) { 44 | return Curry._1(setState, (function (param) { 45 | return value; 46 | })); 47 | }; 48 | return /* tuple */[ 49 | match[0], 50 | setState$prime 51 | ]; 52 | } 53 | 54 | function useAtomListener(listener) { 55 | React.useEffect((function () { 56 | var destructor = Curry._1(listener, /* () */0); 57 | return (function (param) { 58 | destructor.dispose(); 59 | return /* () */0; 60 | }); 61 | })); 62 | return /* () */0; 63 | } 64 | 65 | function useAtomListenerWhen(listener, shouldListen) { 66 | var match = React.useState((function () { 67 | return ; 68 | })); 69 | var setDestructor = match[1]; 70 | var destructor = match[0]; 71 | React.useEffect((function () { 72 | if (shouldListen) { 73 | var destructor$1 = Curry._1(listener, /* () */0); 74 | Curry._1(setDestructor, (function (param) { 75 | return (function (param) { 76 | destructor$1.dispose(); 77 | return /* () */0; 78 | }); 79 | })); 80 | } else { 81 | Rebase.$$Option.forEach((function (f) { 82 | return Curry._1(f, /* () */0); 83 | }), destructor); 84 | } 85 | return destructor; 86 | }), [shouldListen]); 87 | return /* () */0; 88 | } 89 | 90 | function useListenWhen(listener, shouldListen) { 91 | var match = React.useState((function () { 92 | return ; 93 | })); 94 | var setDestructor = match[1]; 95 | var destructor = match[0]; 96 | React.useEffect((function () { 97 | if (shouldListen) { 98 | Curry._1(setDestructor, (function (param) { 99 | return Curry._1(listener, /* () */0); 100 | })); 101 | } else { 102 | Rebase.$$Option.forEach((function (f) { 103 | Curry._1(f, /* () */0); 104 | return Curry._1(setDestructor, (function (param) { 105 | return ; 106 | })); 107 | }), destructor); 108 | } 109 | return ; 110 | }), [shouldListen]); 111 | return /* () */0; 112 | } 113 | 114 | function useChannel(callback, channel) { 115 | React.useEffect((function () { 116 | Channel$AgdaMode.recv(callback, channel); 117 | return ; 118 | }), []); 119 | return /* () */0; 120 | } 121 | 122 | exports.useDidUpdateEffect = useDidUpdateEffect; 123 | exports.useDidUpdateEffect2 = useDidUpdateEffect2; 124 | exports.useState = useState; 125 | exports.useAtomListener = useAtomListener; 126 | exports.useAtomListenerWhen = useAtomListenerWhen; 127 | exports.useListenWhen = useListenWhen; 128 | exports.useChannel = useChannel; 129 | /* react Not a pure module */ 130 | -------------------------------------------------------------------------------- /lib/js/src/View/Panel/Body.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 6 | var Caml_chrome_debugger = require("bs-platform/lib/js/caml_chrome_debugger.js"); 7 | var Emacs__Body$AgdaMode = require("../Emacs/Emacs__Body.bs.js"); 8 | 9 | function Body(Props) { 10 | var body = Props.body; 11 | var hidden = Props.hidden; 12 | var comp = body ? React.createElement(Emacs__Body$AgdaMode.make, { 13 | data: body[0] 14 | }) : null; 15 | var className = hidden ? Rebase.$$String.joinWith(" ", /* :: */Caml_chrome_debugger.simpleVariant("::", [ 16 | "agda-body", 17 | /* :: */Caml_chrome_debugger.simpleVariant("::", [ 18 | "native-key-bindings", 19 | /* :: */Caml_chrome_debugger.simpleVariant("::", [ 20 | "hidden", 21 | /* [] */0 22 | ]) 23 | ]) 24 | ])) : Rebase.$$String.joinWith(" ", /* :: */Caml_chrome_debugger.simpleVariant("::", [ 25 | "agda-body", 26 | /* :: */Caml_chrome_debugger.simpleVariant("::", [ 27 | "native-key-bindings", 28 | /* [] */0 29 | ]) 30 | ])); 31 | return React.createElement("section", { 32 | className: className, 33 | tabIndex: -1 34 | }, comp); 35 | } 36 | 37 | var make = Body; 38 | 39 | exports.make = make; 40 | /* react Not a pure module */ 41 | -------------------------------------------------------------------------------- /lib/js/src/View/Panel/InputMethod/Buffer.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 5 | var Translator$AgdaMode = require("./Translator.bs.js"); 6 | var Caml_chrome_debugger = require("bs-platform/lib/js/caml_chrome_debugger.js"); 7 | 8 | function init(string) { 9 | return string.substring(0, Rebase.$$String.length(string) - 1 | 0); 10 | } 11 | 12 | function isEmpty(self) { 13 | if (self.symbol === undefined) { 14 | return Rebase.$$String.isEmpty(self.tail); 15 | } else { 16 | return false; 17 | } 18 | } 19 | 20 | function toSequence(self) { 21 | var match = self.symbol; 22 | if (match !== undefined) { 23 | return match[1] + self.tail; 24 | } else { 25 | return self.tail; 26 | } 27 | } 28 | 29 | function toSurface(self) { 30 | var match = self.symbol; 31 | if (match !== undefined) { 32 | return match[0] + self.tail; 33 | } else { 34 | return self.tail; 35 | } 36 | } 37 | 38 | function toString(self) { 39 | return "\"" + (toSurface(self) + ("\"[" + (toSequence(self) + "]"))); 40 | } 41 | 42 | function next(self, reality) { 43 | var surface = toSurface(self); 44 | var sequence = toSequence(self); 45 | if (reality === surface) { 46 | if (Translator$AgdaMode.translate(sequence).further && reality !== "\\") { 47 | return /* Noop */0; 48 | } else { 49 | return /* Complete */1; 50 | } 51 | } else if (init(reality) === surface) { 52 | var insertedChar = reality.substr(-1); 53 | var sequence$prime = sequence + insertedChar; 54 | var translation = Translator$AgdaMode.translate(sequence$prime); 55 | var match = translation.symbol; 56 | if (match !== undefined) { 57 | var symbol = match; 58 | if (insertedChar === symbol && insertedChar === "\\") { 59 | return /* Stuck */Caml_chrome_debugger.variant("Stuck", 3, [0]); 60 | } else { 61 | return /* Rewrite */Caml_chrome_debugger.variant("Rewrite", 2, [{ 62 | symbol: /* tuple */[ 63 | symbol, 64 | sequence$prime 65 | ], 66 | tail: "" 67 | }]); 68 | } 69 | } else if (translation.further) { 70 | return /* Insert */Caml_chrome_debugger.variant("Insert", 0, [{ 71 | symbol: self.symbol, 72 | tail: self.tail + insertedChar 73 | }]); 74 | } else { 75 | return /* Stuck */Caml_chrome_debugger.variant("Stuck", 3, [1]); 76 | } 77 | } else if (reality === init(surface) || reality === init(sequence)) { 78 | if (Rebase.$$String.isEmpty(reality)) { 79 | if (Rebase.$$Option.isSome(self.symbol)) { 80 | return /* Rewrite */Caml_chrome_debugger.variant("Rewrite", 2, [{ 81 | symbol: undefined, 82 | tail: init(sequence) 83 | }]); 84 | } else { 85 | return /* Stuck */Caml_chrome_debugger.variant("Stuck", 3, [2]); 86 | } 87 | } else { 88 | return /* Backspace */Caml_chrome_debugger.variant("Backspace", 1, [{ 89 | symbol: self.symbol, 90 | tail: init(self.tail) 91 | }]); 92 | } 93 | } else { 94 | return /* Stuck */Caml_chrome_debugger.variant("Stuck", 3, [3]); 95 | } 96 | } 97 | 98 | var initial = { 99 | symbol: undefined, 100 | tail: "" 101 | }; 102 | 103 | exports.init = init; 104 | exports.initial = initial; 105 | exports.isEmpty = isEmpty; 106 | exports.toSequence = toSequence; 107 | exports.toSurface = toSurface; 108 | exports.toString = toString; 109 | exports.next = next; 110 | /* Translator-AgdaMode Not a pure module */ 111 | -------------------------------------------------------------------------------- /lib/js/src/View/Panel/InputMethod/Translator.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 5 | var Js_dict = require("bs-platform/lib/js/js_dict.js"); 6 | var Extension$AgdaMode = require("./Extension.bs.js"); 7 | var QueryJs = require("./../../../../../../asset/query.js"); 8 | var KeymapJs = require("./../../../../../../asset/keymap.js"); 9 | 10 | var rawTable = QueryJs.default; 11 | 12 | var rawKeymapObject = KeymapJs.default; 13 | 14 | function fromObject(obj) { 15 | var symbol = (obj[">>"] || []); 16 | var subTrie = Js_dict.fromArray(Rebase.$$Array.map((function (key) { 17 | return /* tuple */[ 18 | key, 19 | fromObject((obj[key])) 20 | ]; 21 | }), Rebase.$$Array.filter((function (key) { 22 | return key !== ">>"; 23 | }), Object.keys(obj)))); 24 | return { 25 | symbol: symbol, 26 | subTrie: subTrie 27 | }; 28 | } 29 | 30 | var keymap = fromObject(rawKeymapObject); 31 | 32 | function toKeySuggestions(trie) { 33 | return Object.keys(trie.subTrie); 34 | } 35 | 36 | function toCandidateSymbols(trie) { 37 | return trie.symbol; 38 | } 39 | 40 | function isInKeymap(input) { 41 | var _input = input; 42 | var _trie = keymap; 43 | while(true) { 44 | var trie = _trie; 45 | var input$1 = _input; 46 | var n = Rebase.$$String.length(input$1); 47 | if (n !== 0) { 48 | var key = Rebase.$$String.sub(0, 1, input$1); 49 | var rest = Rebase.$$String.sub(1, n - 1 | 0, input$1); 50 | var match = Js_dict.get(trie.subTrie, key); 51 | if (match !== undefined) { 52 | _trie = match; 53 | _input = rest; 54 | continue ; 55 | } else { 56 | return ; 57 | } 58 | } else { 59 | return trie; 60 | } 61 | }; 62 | } 63 | 64 | function translate(input) { 65 | var trie = isInKeymap(input); 66 | var keySuggestions = Extension$AgdaMode.extendKeySuggestions(input, Rebase.$$Option.mapOr(toKeySuggestions, [], trie)); 67 | var candidateSymbols = Extension$AgdaMode.extendCandidateSymbols(input, Rebase.$$Option.mapOr(toCandidateSymbols, [], trie)); 68 | return { 69 | symbol: Rebase.$$Array.get(candidateSymbols, 0), 70 | further: Rebase.$$Array.length(keySuggestions) !== 0, 71 | keySuggestions: keySuggestions, 72 | candidateSymbols: candidateSymbols 73 | }; 74 | } 75 | 76 | var initialTranslation = translate(""); 77 | 78 | function lookup(symbol) { 79 | return Rebase.$$Option.flatMap((function (param) { 80 | return Js_dict.get(rawTable, param); 81 | }), Rebase.$$Option.map((function (prim) { 82 | return String(prim); 83 | }), symbol.codePointAt(0))); 84 | } 85 | 86 | exports.rawTable = rawTable; 87 | exports.rawKeymapObject = rawKeymapObject; 88 | exports.fromObject = fromObject; 89 | exports.keymap = keymap; 90 | exports.toKeySuggestions = toKeySuggestions; 91 | exports.toCandidateSymbols = toCandidateSymbols; 92 | exports.isInKeymap = isInKeymap; 93 | exports.translate = translate; 94 | exports.initialTranslation = initialTranslation; 95 | exports.lookup = lookup; 96 | /* rawTable Not a pure module */ 97 | -------------------------------------------------------------------------------- /lib/js/src/View/Panel/SizingHandle.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 6 | var Caml_option = require("bs-platform/lib/js/caml_option.js"); 7 | 8 | function calculateBodyHeight(handleRef, handleY) { 9 | return Rebase.$$Option.flatMap((function (elem) { 10 | var top = (elem.getBoundingClientRect().top | 0) + 51 | 0; 11 | return Rebase.$$Option.flatMap((function (element) { 12 | var bottom = element.getBoundingClientRect().top | 0; 13 | if (top > 0) { 14 | return (bottom - handleY | 0) - 51 | 0; 15 | } 16 | 17 | }), Caml_option.nullable_to_opt(document.querySelector("atom-panel-container.footer"))); 18 | }), Caml_option.nullable_to_opt(handleRef.current)); 19 | } 20 | 21 | function SizingHandle(Props) { 22 | var onResizeStart = Props.onResizeStart; 23 | var onResizeEnd = Props.onResizeEnd; 24 | var mountAtBottom = Props.mountAtBottom; 25 | var handleRef = React.useRef(null); 26 | if (mountAtBottom) { 27 | return React.createElement("div", { 28 | className: "sizing-handle-anchor" 29 | }, React.createElement("div", { 30 | ref: handleRef, 31 | className: "sizing-handle native-key-bindings", 32 | draggable: true, 33 | tabIndex: -1, 34 | onDragEnd: (function (ev) { 35 | return Rebase.$$Option.forEach(onResizeEnd, calculateBodyHeight(handleRef, ev.clientY)); 36 | }), 37 | onDragStart: (function (ev) { 38 | return Rebase.$$Option.forEach(onResizeStart, calculateBodyHeight(handleRef, ev.clientY)); 39 | }) 40 | })); 41 | } else { 42 | return null; 43 | } 44 | } 45 | 46 | var make = SizingHandle; 47 | 48 | exports.calculateBodyHeight = calculateBodyHeight; 49 | exports.make = make; 50 | /* react Not a pure module */ 51 | -------------------------------------------------------------------------------- /lib/js/src/View/Settings/Settings__Breadcrumb.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var React = require("react"); 6 | 7 | function Settings__Breadcrumb(Props) { 8 | var uri = Props.uri; 9 | var onNavigate = Props.onNavigate; 10 | var tmp; 11 | switch (uri) { 12 | case /* Root */0 : 13 | tmp = null; 14 | break; 15 | case /* Connection */1 : 16 | tmp = React.createElement("li", undefined, React.createElement("a", { 17 | href: "#" 18 | }, React.createElement("span", { 19 | className: "icon icon-plug" 20 | }, "Connection"))); 21 | break; 22 | case /* Log */2 : 23 | tmp = React.createElement("li", undefined, React.createElement("a", { 24 | href: "#" 25 | }, React.createElement("span", { 26 | className: "icon icon-comment-discussion" 27 | }, "Log"))); 28 | break; 29 | case /* InputMethod */3 : 30 | tmp = React.createElement("li", undefined, React.createElement("a", { 31 | href: "#" 32 | }, React.createElement("span", { 33 | className: "icon icon-keyboard" 34 | }, "Input Method"))); 35 | break; 36 | case /* Debug */4 : 37 | tmp = React.createElement("li", undefined, React.createElement("a", { 38 | href: "#" 39 | }, React.createElement("span", { 40 | className: "icon icon-terminal" 41 | }, "Debug"))); 42 | break; 43 | 44 | } 45 | return React.createElement("nav", { 46 | className: "agda-settings-breadcrumb" 47 | }, React.createElement("ol", { 48 | className: "breadcrumb" 49 | }, React.createElement("li", undefined, React.createElement("a", { 50 | href: "#", 51 | onClick: (function (param) { 52 | return Curry._1(onNavigate, /* Root */0); 53 | }) 54 | }, React.createElement("span", { 55 | className: "icon icon-settings" 56 | }, "Settings"))), tmp)); 57 | } 58 | 59 | var make = Settings__Breadcrumb; 60 | 61 | exports.make = make; 62 | /* react Not a pure module */ 63 | -------------------------------------------------------------------------------- /lib/js/src/View/Settings/Settings__Connection__Error.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Connection$AgdaMode = require("../../Connection.bs.js"); 6 | 7 | function Settings__Connection__Error(Props) { 8 | var error = Props.error; 9 | var match = Connection$AgdaMode.$$Error.toString(error); 10 | return React.createElement(React.Fragment, undefined, React.createElement("hr", undefined), React.createElement("h2", undefined, "Error: " + match[0]), React.createElement("p", undefined, "error message:"), React.createElement("pre", { 11 | className: "inset-panel padded text-warning error" 12 | }, match[1])); 13 | } 14 | 15 | var make = Settings__Connection__Error; 16 | 17 | exports.make = make; 18 | /* react Not a pure module */ 19 | -------------------------------------------------------------------------------- /lib/js/src/View/Settings/Settings__Debug.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Rebase = require("@glennsl/rebase/lib/js/src/Rebase.bs.js"); 6 | var Util$AgdaMode = require("../../Util/Util.bs.js"); 7 | var Buffer$AgdaMode = require("../Panel/InputMethod/Buffer.bs.js"); 8 | 9 | function Settings__Debug(Props) { 10 | var debug = Props.debug; 11 | var hidden = Props.hidden; 12 | var inputMethod = debug.inputMethod; 13 | return React.createElement("section", { 14 | className: "agda-settings-debug" + Util$AgdaMode.React.showWhen(!hidden) 15 | }, React.createElement("h1", undefined, React.createElement("span", { 16 | className: "icon icon-terminal" 17 | }), React.createElement("span", undefined, "Debug")), React.createElement("p", undefined, "only available in dev mode"), React.createElement("hr", undefined), React.createElement("h2", undefined, React.createElement("span", undefined, "Input Method"), inputMethod.activated ? React.createElement("span", { 18 | className: "icon icon-primitive-dot text-success", 19 | id: "input-method-activation", 20 | title: "activated" 21 | }) : React.createElement("span", { 22 | className: "icon icon-primitive-dot text-error", 23 | id: "input-method-activation", 24 | title: "deactivated" 25 | })), React.createElement("p", undefined, "input sequence : ", React.createElement("span", { 26 | className: "inline-block highlight" 27 | }, Buffer$AgdaMode.toSequence(inputMethod.buffer))), React.createElement("p", undefined, "output buffer : ", React.createElement("span", { 28 | className: "inline-block highlight" 29 | }, Buffer$AgdaMode.toSurface(inputMethod.buffer))), React.createElement("p", undefined, "# of markers : ", React.createElement("span", { 30 | className: "inline-block highlight" 31 | }, String(Rebase.$$Array.length(inputMethod.markers)))), React.createElement("div", { 32 | className: "block" 33 | }, React.createElement("button", { 34 | className: "btn", 35 | onClick: (function (param) { 36 | console.log(inputMethod.markers); 37 | return /* () */0; 38 | }) 39 | }, "Dump Markers"))); 40 | } 41 | 42 | var make = Settings__Debug; 43 | 44 | exports.make = make; 45 | /* react Not a pure module */ 46 | -------------------------------------------------------------------------------- /lib/js/src/View/View.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 6 | var Event$AgdaMode = require("../Util/Event.bs.js"); 7 | var Channel$AgdaMode = require("../Util/Channel.bs.js"); 8 | 9 | function make(events, channels) { 10 | var activate = function (param) { 11 | return Channel$AgdaMode.send(/* () */0, channels.activatePanel); 12 | }; 13 | var deactivate = function (param) { 14 | return Channel$AgdaMode.send(/* () */0, channels.deactivatePanel); 15 | }; 16 | var toggleDocking = function (param) { 17 | return Channel$AgdaMode.send(/* () */0, channels.toggleDocking); 18 | }; 19 | var display = function (text, style, body) { 20 | return Channel$AgdaMode.send(/* tuple */[ 21 | { 22 | text: text, 23 | style: style 24 | }, 25 | body 26 | ], channels.display); 27 | }; 28 | var inquire = function (text, placeholder, value) { 29 | return $$Promise.flatMap(Channel$AgdaMode.send(/* () */0, channels.activatePanel), (function (param) { 30 | return Channel$AgdaMode.send(/* tuple */[ 31 | { 32 | text: text, 33 | style: /* PlainText */0 34 | }, 35 | placeholder, 36 | value 37 | ], channels.inquire); 38 | })); 39 | }; 40 | var updateIsPending = function (isPending) { 41 | return Channel$AgdaMode.send(isPending, channels.updateIsPending); 42 | }; 43 | var onMouseEvent = events.onMouseEvent; 44 | var activateInputMethod = function (activate) { 45 | return Channel$AgdaMode.send(activate, channels.activateInputMethod); 46 | }; 47 | var interceptAndInsertKey = function (symbol) { 48 | return Channel$AgdaMode.send(symbol, channels.interceptAndInsertKey); 49 | }; 50 | var onInputMethodChange = events.onInputMethodChange; 51 | var navigateSettings = function (where) { 52 | return Channel$AgdaMode.send(where, channels.navigateSettings); 53 | }; 54 | var updateConnection = function (connection, error) { 55 | return Channel$AgdaMode.send(/* tuple */[ 56 | connection, 57 | error 58 | ], channels.updateConnection); 59 | }; 60 | var inquireConnection = function (param) { 61 | return Channel$AgdaMode.send(/* () */0, channels.inquireConnection); 62 | }; 63 | var onDestroy = Event$AgdaMode.make(/* () */0); 64 | var destroy = function (param) { 65 | return $$Promise.tap($$Promise.flatMap($$Promise.flatMap(Channel$AgdaMode.send(/* () */0, channels.deactivatePanel), (function (param) { 66 | return Channel$AgdaMode.send(false, channels.activateInputMethod); 67 | })), (function (param) { 68 | return Channel$AgdaMode.send(/* () */0, channels.destroy); 69 | })), (function (param) { 70 | return Curry._1(onDestroy.emit, /* () */0); 71 | })); 72 | }; 73 | return { 74 | activate: activate, 75 | deactivate: deactivate, 76 | toggleDocking: toggleDocking, 77 | display: display, 78 | inquire: inquire, 79 | updateIsPending: updateIsPending, 80 | destroy: destroy, 81 | onDestroy: onDestroy, 82 | onMouseEvent: onMouseEvent, 83 | activateInputMethod: activateInputMethod, 84 | interceptAndInsertKey: interceptAndInsertKey, 85 | onInputMethodChange: onInputMethodChange, 86 | navigateSettings: navigateSettings, 87 | updateConnection: updateConnection, 88 | inquireConnection: inquireConnection 89 | }; 90 | } 91 | 92 | exports.make = make; 93 | /* Promise Not a pure module */ 94 | -------------------------------------------------------------------------------- /lib/js/test/Parser/Test__Parser__Response.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var Belt_Array = require("bs-platform/lib/js/belt_Array.js"); 6 | var Mocha$BsMocha = require("bs-mocha/lib/js/src/Mocha.bs.js"); 7 | var Promise$BsMocha = require("bs-mocha/lib/js/src/Promise.bs.js"); 8 | var Response$AgdaMode = require("../../src/Response.bs.js"); 9 | var Test__Util$AgdaMode = require("../Test__Util.bs.js"); 10 | var Test__Parser__SExpression$AgdaMode = require("./Test__Parser__SExpression.bs.js"); 11 | 12 | function toResponses(exprs) { 13 | return Belt_Array.concatMany(Belt_Array.map(Belt_Array.map(exprs, Response$AgdaMode.parse), (function (param) { 14 | if (param.tag) { 15 | Curry._1(Test__Util$AgdaMode.Assert.fail, param[0]); 16 | return []; 17 | } else { 18 | return [param[0]]; 19 | } 20 | }))); 21 | } 22 | 23 | Mocha$BsMocha.describe("when parsing responses")(undefined, undefined, undefined, (function (param) { 24 | return Belt_Array.forEach(Test__Util$AgdaMode.Golden.getGoldenFilepathsSync("test/Parser/Response"), (function (filepath) { 25 | return Promise$BsMocha.it("should golden test " + filepath)(undefined, undefined, undefined, (function (param) { 26 | return Test__Util$AgdaMode.Golden.readFile(filepath).then((function (raw) { 27 | var partial_arg = []; 28 | return Test__Util$AgdaMode.Golden.compare(Test__Util$AgdaMode.Golden.map(Test__Util$AgdaMode.Golden.map(Test__Util$AgdaMode.Golden.map(raw, (function (param) { 29 | return Test__Parser__SExpression$AgdaMode.parseSExpression(partial_arg, param); 30 | })), toResponses), (function (param) { 31 | return Test__Util$AgdaMode.serializeWith(Response$AgdaMode.toString, param); 32 | }))); 33 | })); 34 | })); 35 | })); 36 | })); 37 | 38 | exports.toResponses = toResponses; 39 | /* Not a pure module */ 40 | -------------------------------------------------------------------------------- /lib/js/test/Parser/Test__Parser__SourceFile.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Belt_Array = require("bs-platform/lib/js/belt_Array.js"); 5 | var Mocha$BsMocha = require("bs-mocha/lib/js/src/Mocha.bs.js"); 6 | var Promise$BsMocha = require("bs-mocha/lib/js/src/Promise.bs.js"); 7 | var SourceFile$AgdaMode = require("../../src/SourceFile.bs.js"); 8 | var Test__Util$AgdaMode = require("../Test__Util.bs.js"); 9 | 10 | Mocha$BsMocha.describe("when parsing file paths")(undefined, undefined, undefined, (function (param) { 11 | return Mocha$BsMocha.it("should recognize the file extensions")(undefined, undefined, undefined, (function (param) { 12 | Test__Util$AgdaMode.Assert.equal(undefined, SourceFile$AgdaMode.FileType.parse("a.agda"), /* Agda */0); 13 | Test__Util$AgdaMode.Assert.equal(undefined, SourceFile$AgdaMode.FileType.parse("a.lagda"), /* LiterateTeX */1); 14 | Test__Util$AgdaMode.Assert.equal(undefined, SourceFile$AgdaMode.FileType.parse("a.lagda.tex"), /* LiterateTeX */1); 15 | Test__Util$AgdaMode.Assert.equal(undefined, SourceFile$AgdaMode.FileType.parse("a.lagda.md"), /* LiterateMarkdown */3); 16 | Test__Util$AgdaMode.Assert.equal(undefined, SourceFile$AgdaMode.FileType.parse("a.lagda.rst"), /* LiterateRST */2); 17 | return Test__Util$AgdaMode.Assert.equal(undefined, SourceFile$AgdaMode.FileType.parse("a.lagda.org"), /* LiterateOrg */4); 18 | })); 19 | })); 20 | 21 | Mocha$BsMocha.describe("when parsing source files")(undefined, undefined, undefined, (function (param) { 22 | return Belt_Array.forEach(Test__Util$AgdaMode.Golden.getGoldenFilepathsSync("test/Parser/SourceFile"), (function (filepath) { 23 | return Promise$BsMocha.it("should golden test " + filepath)(undefined, undefined, undefined, (function (param) { 24 | return Test__Util$AgdaMode.Golden.readFile(filepath).then((function (raw) { 25 | var partial_arg = [ 26 | 0, 27 | 1, 28 | 2, 29 | 3, 30 | 4, 31 | 5, 32 | 6, 33 | 7, 34 | 8, 35 | 9 36 | ]; 37 | return Test__Util$AgdaMode.Golden.compare(Test__Util$AgdaMode.Golden.map(Test__Util$AgdaMode.Golden.map(raw, (function (param) { 38 | return SourceFile$AgdaMode.parse(partial_arg, filepath, param); 39 | })), (function (param) { 40 | return Test__Util$AgdaMode.serializeWith(SourceFile$AgdaMode.Diff.toString, param); 41 | }))); 42 | })); 43 | })); 44 | })); 45 | })); 46 | 47 | /* Not a pure module */ 48 | -------------------------------------------------------------------------------- /lib/js/test/Test.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | 5 | var Main = /* alias */0; 6 | 7 | var Parser = /* alias */0; 8 | 9 | var Util = /* alias */0; 10 | 11 | exports.Main = Main; 12 | exports.Parser = Parser; 13 | exports.Util = Util; 14 | /* No side effect */ 15 | -------------------------------------------------------------------------------- /lib/js/test/Test__Main.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Mocha$BsMocha = require("bs-mocha/lib/js/src/Mocha.bs.js"); 5 | var Promise$BsMocha = require("bs-mocha/lib/js/src/Promise.bs.js"); 6 | var AgdaMode$AgdaMode = require("../src/AgdaMode.bs.js"); 7 | var Test__Util$AgdaMode = require("./Test__Util.bs.js"); 8 | 9 | Promise$BsMocha.before(undefined)(undefined, undefined, undefined, Test__Util$AgdaMode.Package.activate); 10 | 11 | Promise$BsMocha.after(undefined)(undefined, undefined, undefined, Test__Util$AgdaMode.Package.deactivate); 12 | 13 | Mocha$BsMocha.describe("Instances")(undefined, undefined, undefined, (function (param) { 14 | Promise$BsMocha.it_skip("should have no instances before opening any files")(undefined, undefined, undefined, (function (param) { 15 | return Promise.resolve(Test__Util$AgdaMode.Assert.equal(undefined, 0, AgdaMode$AgdaMode.Instances.size(/* () */0))); 16 | })); 17 | Promise$BsMocha.it("should respect the number of opened .agda file")(undefined, undefined, undefined, (function (param) { 18 | return Test__Util$AgdaMode.$$File.openAsset("Temp.agda").then((function (editor) { 19 | Test__Util$AgdaMode.Assert.equal(undefined, 1, AgdaMode$AgdaMode.Instances.size(/* () */0)); 20 | var pane = atom.workspace.getActivePane(); 21 | return pane.destroyItem(editor, true); 22 | })).then((function (destroyed) { 23 | Test__Util$AgdaMode.Assert.equal(undefined, AgdaMode$AgdaMode.Instances.size(/* () */0), destroyed ? 0 : 1); 24 | return Promise.resolve(/* () */0); 25 | })); 26 | })); 27 | Promise$BsMocha.it("should respect the number of opened .lagda file")(undefined, undefined, undefined, (function (param) { 28 | return Test__Util$AgdaMode.$$File.openAsset("Blank2.lagda").then((function (editor) { 29 | Test__Util$AgdaMode.Assert.equal(undefined, 1, AgdaMode$AgdaMode.Instances.size(/* () */0)); 30 | var pane = atom.workspace.getActivePane(); 31 | return pane.destroyItem(editor, true); 32 | })).then((function (destroyed) { 33 | Test__Util$AgdaMode.Assert.equal(undefined, destroyed ? 0 : 1, AgdaMode$AgdaMode.Instances.size(/* () */0)); 34 | return Promise.resolve(/* () */0); 35 | })); 36 | })); 37 | return Promise$BsMocha.it("should include '.agda' in the classlist")(undefined, undefined, undefined, (function (param) { 38 | return Test__Util$AgdaMode.$$File.openAsset("Temp.agda").then((function (editor) { 39 | Test__Util$AgdaMode.Assert.yes(atom.views.getView(editor).classList.contains("agda")); 40 | return Promise.resolve(/* () */0); 41 | })); 42 | })); 43 | })); 44 | 45 | /* Not a pure module */ 46 | -------------------------------------------------------------------------------- /lib/js/test/Test__Misc.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var $$Promise = require("reason-promise/lib/js/src/js/promise.js"); 5 | var Mocha$BsMocha = require("bs-mocha/lib/js/src/Mocha.bs.js"); 6 | var Assert$BsMocha = require("bs-mocha/lib/js/src/Assert.bs.js"); 7 | var Promise$BsMocha = require("bs-mocha/lib/js/src/Promise.bs.js"); 8 | var Instance$AgdaMode = require("../src/Instance.bs.js"); 9 | var Connection$AgdaMode = require("../src/Connection.bs.js"); 10 | var TaskRunner$AgdaMode = require("../src/Task/TaskRunner.bs.js"); 11 | var Test__Util$AgdaMode = require("./Test__Util.bs.js"); 12 | var Instance__Connections$AgdaMode = require("../src/Instance/Instance__Connections.bs.js"); 13 | 14 | Mocha$BsMocha.describe_skip("when loading files")(undefined, undefined, undefined, (function (param) { 15 | return Mocha$BsMocha.describe("when parsing responses from Agda")(undefined, undefined, undefined, (function (param) { 16 | return Promise$BsMocha.it("should succeed")(undefined, undefined, undefined, (function (param) { 17 | var path = Test__Util$AgdaMode.Path.asset("Algebra.agda"); 18 | return Test__Util$AgdaMode.$$File.open_(path).then((function (editor) { 19 | var instance = Instance$AgdaMode.make(editor); 20 | return $$Promise.Js.toBsPromise($$Promise.flatMap($$Promise.mapError($$Promise.mapOk($$Promise.mapOk($$Promise.mapOk($$Promise.flatMapOk(Connection$AgdaMode.autoSearch("agda"), (function (path) { 21 | return Connection$AgdaMode.validateAndMake(path, [" --no-libraries"]); 22 | })), Connection$AgdaMode.connect), Connection$AgdaMode.wire), (function (param) { 23 | return Instance__Connections$AgdaMode.persistConnection(instance, param); 24 | })), Assert$BsMocha.fail), (function (param) { 25 | return TaskRunner$AgdaMode.dispatchCommand(/* Load */0, instance); 26 | }))); 27 | })); 28 | })); 29 | })); 30 | })); 31 | 32 | /* Not a pure module */ 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agda-mode", 3 | "main": "./lib/js/bundled.js", 4 | "version": "0.9.12", 5 | "description": "agda-mode on Atom", 6 | "scripts": { 7 | "keymap-gen": "./keymap.el generate", 8 | "keymap-print": "./keymap.el print", 9 | "start": "bsb -clean && bsb -make-world -w", 10 | "build": "bsb -make-world && npx webpack --mode=production", 11 | "test": "atom -t lib/js/test" 12 | }, 13 | "activationCommands": { 14 | "atom-text-editor": [ 15 | "agda-mode:load" 16 | ], 17 | "atom-text-editor.agda": [ 18 | "agda-mode:input-symbol", 19 | "agda-mode:query-symbol", 20 | "agda-mode:go-to-definition" 21 | ], 22 | "atom-text-editor[data-grammar~='agda']": [ 23 | "agda-mode:input-symbol", 24 | "agda-mode:query-symbol", 25 | "agda-mode:go-to-definition" 26 | ] 27 | }, 28 | "atomTestRunner": "atom-mocha", 29 | "repository": "https://github.com/banacorn/agda-mode", 30 | "license": "MIT", 31 | "engines": { 32 | "atom": ">=1.19.0 <2.0.0" 33 | }, 34 | "devDependencies": { 35 | "atom-mocha": "^2.2.0", 36 | "bs-mocha": "^0.5.0", 37 | "chai": "^4.2.0", 38 | "diff": "^4.0.1", 39 | "git-branch": "^2.0.1", 40 | "node-dir": "^0.1.17", 41 | "webpack": "^4.39.1", 42 | "webpack-cli": "^3.1.2" 43 | }, 44 | "dependencies": { 45 | "@glennsl/bs-json": "^5.0.1", 46 | "@glennsl/rebase": "github:glennsl/rebase", 47 | "bs-platform": "^7.2", 48 | "bs-webapi": "^0.15.3", 49 | "bs-nd": "^0.1.5", 50 | "bs-atom2": "^1.40.1", 51 | "compare-versions": "^3.5.1", 52 | "reason-promise": "^1.0.1", 53 | "react": "^16.9.0", 54 | "react-dom": "^16.9.0", 55 | "reason-react": ">=0.7.0", 56 | "reason-react-update": "^0.1.1" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Editors.re: -------------------------------------------------------------------------------- 1 | open Belt; 2 | 3 | type sort = 4 | | Source 5 | | Query; 6 | 7 | type t = { 8 | mutable focused: sort, 9 | source: Atom.TextEditor.t, 10 | mutable query: option(Atom.TextEditor.t), 11 | }; 12 | 13 | let make = editor => {focused: Source, source: editor, query: None}; 14 | 15 | let getID = self => string_of_int(Atom.TextEditor.id(self.source)); 16 | 17 | module Focus = { 18 | open Atom; 19 | open Webapi.Dom; 20 | let get = (editors): TextEditor.t => 21 | switch (editors.focused) { 22 | | Source => editors.source 23 | | Query => 24 | switch (editors.query) { 25 | | Some(editor) => editor 26 | | None => editors.source 27 | } 28 | }; 29 | 30 | let on = (sort, editors) => 31 | switch (sort) { 32 | | Source => 33 | editors.source->Views.getView->HtmlElement.focus; 34 | editors.focused = Source; 35 | | Query => 36 | editors.query 37 | ->Option.map(Atom.Views.getView) 38 | ->Option.forEach(HtmlElement.focus); 39 | editors.focused = Query; 40 | }; 41 | }; 42 | 43 | module Selection = { 44 | let getSymbol = editors => { 45 | editors 46 | ->Focus.get 47 | ->Atom.TextEditor.getSelectedText 48 | ->Js.String.substrAtMost(~from=0, ~length=1); 49 | }; 50 | let getTextNode = editors => { 51 | let getText = () => { 52 | editors |> Focus.get |> Atom.TextEditor.getSelectedText; 53 | }; 54 | let getLargerSyntaxNode = () => { 55 | editors |> Focus.get |> Atom.TextEditor.selectLargerSyntaxNode |> ignore; 56 | editors |> Focus.get |> Atom.TextEditor.getSelectedText; 57 | }; 58 | let getPointedWord = () => { 59 | editors 60 | |> Focus.get 61 | |> Atom.TextEditor.selectWordsContainingCursors 62 | |> ignore; 63 | editors |> Focus.get |> Atom.TextEditor.getSelectedText; 64 | }; 65 | 66 | let selectedText = getText(); 67 | 68 | // if the user didn't select anything 69 | if (selectedText == "") { 70 | let largerNode = getLargerSyntaxNode(); 71 | // this happens when language-agda is not installed 72 | if (largerNode == "") { 73 | getPointedWord(); 74 | } else { 75 | let pointedText = getPointedWord(); 76 | // this happens when the user is hovering on a mixfix/infix operator like _+_ 77 | if (pointedText == "_") { 78 | getLargerSyntaxNode(); 79 | } else { 80 | pointedText; 81 | }; 82 | }; 83 | } else { 84 | selectedText; 85 | }; 86 | }; 87 | }; -------------------------------------------------------------------------------- /src/Highlighting.re: -------------------------------------------------------------------------------- 1 | open Belt; 2 | 3 | type removeTokenBasedHighlighting = 4 | | Remove 5 | | Keep; 6 | 7 | type filepath = string; 8 | module Token = Parser.SExpression; 9 | 10 | module Annotation = { 11 | open Token; 12 | type t = { 13 | start: int, 14 | end_: int, 15 | types: array(string), 16 | source: option((filepath, int)), 17 | }; 18 | let toString = self => 19 | "Annotation " 20 | ++ string_of_int(self.start) 21 | ++ " " 22 | ++ string_of_int(self.end_) 23 | ++ " " 24 | ++ Util.Pretty.list(List.fromArray(self.types)) 25 | ++ ( 26 | switch (self.source) { 27 | | None => "" 28 | | Some((s, i)) => s ++ " " ++ string_of_int(i) 29 | } 30 | ); 31 | let parse: Token.t => option(t) = 32 | fun 33 | | A(_) => None 34 | | L(xs) => 35 | switch (xs) { 36 | | [| 37 | A(start'), 38 | A(end_'), 39 | types, 40 | _, 41 | _, 42 | L([|A(filepath), _, A(index')|]), 43 | |] => 44 | Parser.int(start') 45 | ->Option.flatMap(start => 46 | Parser.int(end_') 47 | ->Option.flatMap(end_ => 48 | Parser.int(index') 49 | ->Option.map(index => 50 | { 51 | start, 52 | end_, 53 | types: flatten(types), 54 | source: Some((filepath, index)), 55 | } 56 | ) 57 | ) 58 | ) 59 | 60 | | [|A(start'), A(end_'), types|] => 61 | Parser.int(start') 62 | ->Option.flatMap(start => 63 | Parser.int(end_') 64 | ->Option.map(end_ => 65 | {start, end_, types: flatten(types), source: None} 66 | ) 67 | ) 68 | | [|A(start'), A(end_'), types, _|] => 69 | Parser.int(start') 70 | ->Option.flatMap(start => 71 | Parser.int(end_') 72 | ->Option.map(end_ => 73 | {start, end_, types: flatten(types), source: None} 74 | ) 75 | ) 76 | | _ => None 77 | }; 78 | let parseDirectHighlightings: array(Token.t) => array(t) = 79 | tokens => { 80 | tokens 81 | ->Js.Array.sliceFrom(2, _) 82 | ->Array.map(parse) 83 | ->Array.keepMap(x => x); 84 | }; 85 | let parseIndirectHighlightings: array(Token.t) => array(t) = 86 | tokens => 87 | tokens 88 | ->Js.Array.sliceFrom(1, _) 89 | ->Array.map(parse) 90 | ->Array.keepMap(x => x); 91 | /* the type of annotations that we want to highlight */ 92 | let shouldHighlight: t => bool = 93 | annotation => { 94 | annotation.types 95 | |> Js.Array.includes("unsolvedmeta") 96 | || annotation.types 97 | |> Js.Array.includes("unsolvedconstraint") 98 | || annotation.types 99 | |> Js.Array.includes("terminationproblem") 100 | || annotation.types 101 | |> Js.Array.includes("coverageproblem"); 102 | }; 103 | }; 104 | 105 | type t = Atom.DisplayMarker.t; -------------------------------------------------------------------------------- /src/Instance.re: -------------------------------------------------------------------------------- 1 | module Event = Event; 2 | 3 | open Instance__Type; 4 | module Goals = Instance__Goals; 5 | module Highlightings = Instance__Highlightings; 6 | module Connections = Instance__Connections; 7 | module TextEditors = Instance__TextEditors; 8 | 9 | type t = Instance__Type.t; 10 | 11 | let activate = instance => 12 | // only activate the view when it's loaded 13 | if (instance.isLoaded) { 14 | instance.view.activate(); 15 | } else { 16 | Promise.resolved(); 17 | }; 18 | 19 | let deactivate = instance => 20 | // only deactivate the view when it's loaded 21 | if (instance.isLoaded) { 22 | instance.view.deactivate(); 23 | } else { 24 | Promise.resolved(); 25 | }; 26 | 27 | let destroy = instance => instance.view.destroy(); 28 | 29 | let make = (textEditor: Atom.TextEditor.t) => { 30 | /* adds "agda" to the class-list */ 31 | Atom.Views.getView(textEditor) 32 | |> Webapi.Dom.HtmlElement.classList 33 | |> Webapi.Dom.DomTokenList.add("agda"); 34 | 35 | /* */ 36 | let editors = Editors.make(textEditor); 37 | let view = Root.initialize(editors); 38 | let instance = { 39 | isLoaded: false, 40 | editors, 41 | view, 42 | goals: [||], 43 | history: { 44 | checkpoints: [||], 45 | needsReloading: false, 46 | }, 47 | highlightings: [||], 48 | runningInfo: RunningInfo.make(), 49 | connection: None, 50 | onDispatch: Event.make(), 51 | onConnectionError: Event.make(), 52 | }; 53 | 54 | // subscribe to `onMouseEvent` 55 | let destructor1 = 56 | instance.view.onMouseEvent.on(ev => 57 | switch (ev) { 58 | | Type.View.Mouse.JumpToTarget(target) => 59 | TaskRunner.dispatchCommand(Jump(target), instance) |> ignore 60 | | _ => () 61 | } 62 | ); 63 | // unsubscribe to `onMouseEvent` 64 | instance.view.onDestroy.once()->Promise.get(_ => destructor1()); 65 | 66 | instance; 67 | }; 68 | 69 | let dispatchUndo = (instance: t) => { 70 | // should reset goals after undo 71 | instance.editors.source |> Atom.TextEditor.undo; 72 | // reload 73 | if (instance.history.needsReloading) { 74 | TaskRunner.dispatchCommand(Load, instance) |> ignore; 75 | instance.history.needsReloading = false; 76 | }; 77 | }; 78 | 79 | let getID = (instance: t): string => { 80 | instance.editors |> Editors.getID; 81 | }; 82 | -------------------------------------------------------------------------------- /src/Instance/Instance__Connections.re: -------------------------------------------------------------------------------- 1 | open! Rebase; 2 | 3 | open Instance__Type; 4 | open Atom; 5 | 6 | // inquire Agda path from the user 7 | let inquireAgdaPath = 8 | (error: option(Connection.Error.t), instance) 9 | : Promise.t(result(string, error)) => { 10 | View.( 11 | instance.view.activate() 12 | ->Promise.flatMap(() => 13 | instance.view.navigateSettings(Settings.URI.Connection) 14 | ) 15 | ->Promise.flatMap(() => instance.view.updateConnection(None, error)) 16 | ->Promise.flatMap(() => instance.view.inquireConnection()) 17 | ->Promise.mapError(_ => Instance__Type.Cancelled) 18 | ); 19 | }; 20 | 21 | // get Agda path from config or from the user 22 | let getAgdaPathAndArgs = 23 | (instance): Promise.t(result((string, array(string)), error)) => { 24 | let storedPath = Config.get("agda-mode.agdaPath") |> Parser.filepath; 25 | let storedArgs = Config.get("agda-mode.agdaArgs") |> Parser.commandLineArgs; 26 | if (String.isEmpty(storedPath) || storedPath == ".") { 27 | let searchingFor = Config.get("agda-mode.agdaName") |> String.trim; 28 | Connection.autoSearch(searchingFor) 29 | ->Promise.flatMapError(err => { 30 | // log connection error for testing 31 | instance.onConnectionError.emit(err); 32 | inquireAgdaPath(Some(err), instance); 33 | }) 34 | ->Promise.mapOk(path => (path, [||])); 35 | } else { 36 | Promise.resolved(Ok((storedPath, storedArgs))); 37 | }; 38 | }; 39 | 40 | let persistConnection = 41 | (instance, connection: Connection.t) 42 | : Promise.t(result(Connection.t, error)) => { 43 | instance.connection = Some(connection); 44 | /* store the path in the config */ 45 | let path = 46 | Array.concat(connection.metadata.args, [|connection.metadata.path|]) 47 | |> List.fromArray 48 | |> String.joinWith(" "); 49 | Config.set("agda-mode.agdaPath", path) |> ignore; 50 | // update the view, and then pass the connection out 51 | instance.view.updateConnection(Some(connection), None) 52 | ->Promise.map(() => Ok(connection)); 53 | }; 54 | 55 | let connectWithAgdaPathAndArgs = 56 | (instance, path, args): Promise.t(result(Connection.t, error)) => { 57 | // validate the given path 58 | let rec getMetadata = (instance, path, args) => { 59 | Connection.validateAndMake(path, args) 60 | ->Promise.flatMapError(err => 61 | inquireAgdaPath(Some(err), instance) 62 | ->Promise.flatMapOk(p => getMetadata(instance, p, args)) 63 | ); 64 | }; 65 | 66 | instance 67 | ->getMetadata(path, args) 68 | ->Promise.mapOk(Connection.connect) 69 | ->Promise.flatMapOk(persistConnection(instance)) 70 | ->Promise.mapOk(Connection.wire); 71 | }; 72 | 73 | // would stuck (and wait for the user) if the path is wrong, not suitable for testing 74 | let connect = (instance): Promise.t(result(Connection.t, error)) => { 75 | switch (instance.connection) { 76 | | Some(connection) => Promise.resolved(Ok(connection)) 77 | | None => 78 | instance 79 | ->getAgdaPathAndArgs 80 | ->Promise.flatMapOk(((path, args)) => 81 | connectWithAgdaPathAndArgs(instance, path, args) 82 | ) 83 | }; 84 | }; 85 | 86 | let disconnect = instance => { 87 | switch (instance.connection) { 88 | | Some(connection) => 89 | Connection.disconnect(Process.Error.DisconnectedByUser, connection); 90 | instance.connection = None; 91 | instance.view.updateConnection(None, None); 92 | | None => Promise.resolved() 93 | }; 94 | }; -------------------------------------------------------------------------------- /src/Instance/Instance__Goals.re: -------------------------------------------------------------------------------- 1 | open Rebase; 2 | open Instance__Type; 3 | 4 | // destroy all goals 5 | let destroyAll = instance => { 6 | instance.goals |> Array.forEach(Goal.destroy); 7 | instance.goals = [||]; 8 | }; 9 | let find = (index: int, instance) => { 10 | let found = instance.goals |> Array.filter(goal => goal.Goal.index == index); 11 | found[0]; 12 | }; 13 | 14 | // set the cursor inside the goal 15 | let setCursor = (goal, instance) => { 16 | let position = 17 | Atom.Point.translate( 18 | Atom.Point.make(0, 3), 19 | Atom.Range.start(goal.Goal.range), 20 | ); 21 | Atom.TextEditor.setCursorBufferPosition(position, instance.editors.source); 22 | }; 23 | 24 | let getPositions = (instance): array(Atom.Point.t) => { 25 | instance.goals 26 | |> Array.map(goal => goal.Goal.range) 27 | |> Array.map(range => 28 | Atom.Point.translate(Atom.Point.make(0, 3), Atom.Range.start(range)) 29 | ); 30 | }; 31 | 32 | let getPreviousGoalPosition = (instance): option(Atom.Point.t) => { 33 | let previousGoal = ref(None); 34 | let cursor = 35 | Atom.TextEditor.getCursorBufferPosition(instance.editors.source); 36 | let positions = getPositions(instance); 37 | 38 | /* assign the previous goal position */ 39 | positions 40 | |> Array.forEach(position => 41 | if (Atom.Point.isLessThan(cursor, position)) { 42 | previousGoal := Some(position); 43 | } 44 | ); 45 | 46 | /* loop back if this is already the first goal */ 47 | if (previousGoal^ === None) { 48 | previousGoal := positions[Array.length(positions) - 1]; 49 | }; 50 | 51 | previousGoal^; 52 | }; 53 | 54 | let getNextGoalPosition = (instance): option(Atom.Point.t) => { 55 | let nextGoal = ref(None); 56 | let cursor = 57 | Atom.TextEditor.getCursorBufferPosition(instance.editors.source); 58 | let positions = getPositions(instance); 59 | /* assign the next goal position */ 60 | positions 61 | |> Array.forEach(position => 62 | if (Atom.Point.isGreaterThan(cursor, position) && nextGoal^ === None) { 63 | nextGoal := Some(position); 64 | } 65 | ); 66 | 67 | /* if no goal ahead of cursor, then loop back */ 68 | if (nextGoal^ === None) { 69 | nextGoal := positions[0]; 70 | }; 71 | 72 | nextGoal^; 73 | }; 74 | 75 | // instantiate all goals 76 | let instantiateAll = (indices, instance) => { 77 | open Atom; 78 | destroyAll(instance); 79 | 80 | let textEditor = instance.editors.source; 81 | let filePath = 82 | textEditor 83 | |> Atom.TextEditor.getPath 84 | |> Option.getOr("untitled") 85 | |> Parser.filepath; 86 | let textBuffer = TextEditor.getBuffer(textEditor); 87 | 88 | let source = TextEditor.getText(textEditor); 89 | instance.goals = 90 | SourceFile.parse(indices, filePath, source) 91 | |> Array.map((result: SourceFile.Diff.t) => { 92 | let start = 93 | TextBuffer.positionForCharacterIndex( 94 | fst(result.originalRange), 95 | textBuffer, 96 | ); 97 | let end_ = 98 | TextBuffer.positionForCharacterIndex( 99 | snd(result.originalRange), 100 | textBuffer, 101 | ); 102 | let range = Range.make(start, end_); 103 | /* modified the hole */ 104 | textEditor 105 | |> TextEditor.setTextInBufferRange(range, result.content) 106 | |> ignore; 107 | /* make it a goal */ 108 | Goal.make( 109 | instance.editors.source, 110 | result.index, 111 | result.modifiedRange, 112 | ); 113 | }); 114 | (); 115 | }; -------------------------------------------------------------------------------- /src/Instance/Instance__Highlightings.re: -------------------------------------------------------------------------------- 1 | open! Rebase; 2 | 3 | open Instance__Type; 4 | 5 | open Task.Highlightings; 6 | open! Atom; 7 | 8 | /* lots of side effects! */ 9 | let add = (annotation: Highlighting.Annotation.t, instance) => { 10 | let textBuffer = TextEditor.getBuffer(instance.editors.source); 11 | let startPoint = 12 | textBuffer |> TextBuffer.positionForCharacterIndex(annotation.start - 1); 13 | let endPoint = 14 | textBuffer |> TextBuffer.positionForCharacterIndex(annotation.end_ - 1); 15 | let range = Range.make(startPoint, endPoint); 16 | let marker = TextEditor.markBufferRange(range, instance.editors.source); 17 | /* update the state */ 18 | instance.highlightings |> Js.Array.push(marker) |> ignore; 19 | /* decorate */ 20 | let types = annotation.types |> Js.Array.joinWith(" "); 21 | 22 | TextEditor.decorateMarker( 23 | marker, 24 | TextEditor.decorateMarkerOptions( 25 | ~type_="highlight", 26 | ~class_="highlight-decoration " ++ types, 27 | (), 28 | ), 29 | instance.editors.source, 30 | ) 31 | |> ignore; 32 | }; 33 | 34 | let addMany = (annotations, instance) => 35 | annotations 36 | |> Array.filter(Highlighting.Annotation.shouldHighlight) 37 | |> Array.forEach(annotation => instance |> add(annotation)); 38 | 39 | let addFromFile = (filepath, instance): Promise.t(unit) => { 40 | let readFile = N.Fs.readFile |> N.Util.promisify; 41 | /* read and parse and add */ 42 | readFile(. filepath) 43 | ->Promise.Js.fromBsPromise 44 | ->Promise.Js.toResult 45 | ->Promise.map( 46 | fun 47 | | Ok(content) => { 48 | open! Parser__Type.SExpression; 49 | content 50 | |> Node.Buffer.toString 51 | |> Parser.SExpression.parse 52 | |> Array.filterMap(Option.fromResult) // throwing away errors 53 | |> Array.map(tokens => 54 | switch (tokens) { 55 | | L(xs) => 56 | xs |> Highlighting.Annotation.parseIndirectHighlightings 57 | | _ => [||] 58 | } 59 | ) 60 | |> Array.flatMap(x => x) 61 | |> Array.filter(Highlighting.Annotation.shouldHighlight) 62 | |> Array.forEach(annotation => instance |> add(annotation)); 63 | (); 64 | } 65 | | Error(err) => { 66 | Js.log(err); 67 | Js.log("cannot read the indirect highlighting file: " ++ filepath); 68 | }, 69 | ); 70 | }; 71 | 72 | let destroyAll = instance => { 73 | instance.highlightings |> Array.forEach(DisplayMarker.destroy); 74 | instance.highlightings = [||]; 75 | }; 76 | 77 | let execute = instance => 78 | fun 79 | | AddDirectly(annotations) => { 80 | addMany(annotations, instance); 81 | Promise.resolved([||]); 82 | } 83 | | AddIndirectly(filepath) => { 84 | // read the file 85 | addFromFile(filepath, instance) 86 | // delete the file 87 | ->Promise.map(() => Ok(N.Fs.unlink(filepath, _ => ()))) 88 | ->Promise.map(_ => [||]); 89 | }; 90 | -------------------------------------------------------------------------------- /src/Instance/Instance__TextEditors.re: -------------------------------------------------------------------------------- 1 | open! Rebase; 2 | 3 | open Instance__Type; 4 | 5 | let getPath = instance => { 6 | instance.editors.source 7 | |> Atom.TextEditor.getPath 8 | |> Option.getOr("untitled") 9 | |> Parser.filepath; 10 | }; 11 | 12 | let pointingAt = (~cursor=?, instance): option(Goal.t) => { 13 | let cursor_ = 14 | switch (cursor) { 15 | | None => Atom.TextEditor.getCursorBufferPosition(instance.editors.source) 16 | | Some(x) => x 17 | }; 18 | 19 | let pointedGoals = 20 | instance.goals 21 | |> Array.filter(goal => 22 | Atom.Range.containsPoint(cursor_, goal.Goal.range) 23 | ); 24 | // return the first pointed goal 25 | pointedGoals[0]; 26 | }; 27 | 28 | let getPointedGoal = (instance): Promise.t(result(Goal.t, error)) => { 29 | let pointed = pointingAt(instance); 30 | switch (pointed) { 31 | | Some(goal) => Promise.resolved(Ok(goal)) 32 | | None => Promise.resolved(Error(OutOfGoal)) 33 | }; 34 | }; 35 | 36 | // execute the callback 37 | // if it's pointing at some empty hole 38 | // then move the cursor inside the empty hole 39 | // else restore the cursor to its original position 40 | let restoreCursorPosition = (callback, instance) => { 41 | let originalPosition = 42 | Atom.TextEditor.getCursorBufferPosition(instance.editors.source); 43 | 44 | callback() 45 | ->Promise.map(result => { 46 | let pointed = pointingAt(~cursor=originalPosition, instance); 47 | switch (pointed) { 48 | | Some(goal) => 49 | if (Goal.isEmpty(goal)) { 50 | Instance__Goals.setCursor(goal, instance); 51 | } else { 52 | Atom.TextEditor.setCursorBufferPosition( 53 | originalPosition, 54 | instance.editors.source, 55 | ); 56 | } 57 | | None => 58 | Atom.TextEditor.setCursorBufferPosition( 59 | originalPosition, 60 | instance.editors.source, 61 | ) 62 | }; 63 | result; 64 | }); 65 | }; 66 | 67 | // 68 | // History Management 69 | // 70 | 71 | // sometimes a child command may be invoked by some parent command, 72 | // in that case, both the parent and the child command should be 73 | // regarded as a single action 74 | 75 | let startCheckpoint = (command, instance) => { 76 | let checkpoint = instance.editors.source |> Atom.TextEditor.createCheckpoint; 77 | instance.history.checkpoints |> Js.Array.push(checkpoint) |> ignore; 78 | 79 | // see if reloading is needed on undo 80 | if (Array.length(instance.history.checkpoints) === 1) { 81 | instance.history.needsReloading = 82 | Command.( 83 | switch (command) { 84 | | SolveConstraints 85 | | Give 86 | | Refine 87 | | Auto 88 | | Case => true 89 | | _ => false 90 | } 91 | ); 92 | }; 93 | }; 94 | 95 | let endCheckpoint = instance => { 96 | let checkpoint = Js.Array.pop(instance.history.checkpoints); 97 | // group changes if it's a parent command 98 | if (Array.length(instance.history.checkpoints) === 0) { 99 | checkpoint 100 | |> Option.forEach(n => 101 | instance.editors.source 102 | |> Atom.TextEditor.groupChangesSinceCheckpoint(n) 103 | |> ignore 104 | ); 105 | }; 106 | (); 107 | }; 108 | -------------------------------------------------------------------------------- /src/Instance/Instance__Type.re: -------------------------------------------------------------------------------- 1 | type error = 2 | | ParseError(array(Parser.Error.t)) 3 | | ConnectionError(Connection.Error.t) 4 | // Cancelled: never makes its way to Agda 5 | | Cancelled 6 | // Other reasons, also never make their way to Agda 7 | | OutOfGoal; 8 | 9 | type history = { 10 | mutable checkpoints: array(int), 11 | mutable needsReloading: bool, 12 | }; 13 | 14 | type t = { 15 | editors: Editors.t, 16 | view: View.t, 17 | // states 18 | history, 19 | mutable isLoaded: bool, 20 | mutable highlightings: array(Highlighting.t), 21 | mutable goals: array(Goal.t), 22 | mutable connection: option(Connection.t), 23 | mutable runningInfo: RunningInfo.t, 24 | // event emitter for testing 25 | onDispatch: Event.t(unit), 26 | onConnectionError: Event.t(Connection.Error.t), 27 | }; 28 | -------------------------------------------------------------------------------- /src/Log.re: -------------------------------------------------------------------------------- 1 | open Belt; 2 | module Entry = { 3 | type request = Request.t; 4 | type response = { 5 | mutable rawText: array(string), 6 | mutable sexpression: array(Parser.SExpression.t), 7 | mutable response: array(Response.t), 8 | mutable error: array(Parser.Error.t), 9 | }; 10 | type t = { 11 | request, 12 | response, 13 | }; 14 | let make = cmd => { 15 | request: cmd, 16 | response: { 17 | rawText: [||], 18 | sexpression: [||], 19 | response: [||], 20 | error: [||], 21 | }, 22 | }; 23 | let serialize = (i, self) => { 24 | // indent some paragraph by 4 spaces 25 | let indent = xs => 26 | xs 27 | ->Js.String.splitByRe([%re "/\\n/"], _) 28 | ->Array.map(Option.mapWithDefault(_, "", x => " " ++ x)) 29 | ->Js.String.concatMany("\n"); 30 | let fold = (text, title) => {j|
$title 31 |

32 | 33 | $text 34 | 35 |

36 |
37 | |j}; 38 | let quote = (xs, title) => 39 | xs 40 | ->Array.map(x => {j|``` 41 | $x 42 | ``` 43 | |j}) 44 | ->Js.String.concatMany("\n") 45 | ->fold(title) 46 | ->indent; 47 | 48 | let request = Request.toString(self.request); 49 | 50 | let rawText = self.response.rawText->quote("raw text"); 51 | let sexpression = 52 | self.response.sexpression 53 | ->Array.map(Parser.SExpression.toString) 54 | ->quote("s-expression"); 55 | let response = 56 | self.response.response 57 | ->Array.map(Response.toString) 58 | ->quote("response"); 59 | let error = 60 | self.response.error->Array.map(Parser.Error.toString)->quote("error"); 61 | 62 | {j|$i. **$request** 63 | $rawText 64 | $sexpression 65 | $response 66 | $error 67 | |j}; 68 | }; 69 | }; 70 | 71 | type t = array(Entry.t); 72 | 73 | let createEntry = (cmd, log) => { 74 | let entry = Entry.make(cmd); 75 | Js.Array.push(entry, log) |> ignore; 76 | }; 77 | 78 | let updateLatestEntry = (f: Entry.t => unit, log) => { 79 | let n = Array.length(log); 80 | let lastEntry = log[n - 1]; 81 | lastEntry->Option.forEach(f); 82 | }; 83 | 84 | let logRawText = text => 85 | updateLatestEntry(entry => 86 | Js.Array.push(text, entry.response.rawText) |> ignore 87 | ); 88 | 89 | let logSExpression = text => 90 | updateLatestEntry(entry => 91 | Js.Array.push(text, entry.response.sexpression) |> ignore 92 | ); 93 | 94 | let logResponse = text => 95 | updateLatestEntry(entry => 96 | Js.Array.push(text, entry.response.response) |> ignore 97 | ); 98 | 99 | let logError = text => 100 | updateLatestEntry(log => Js.Array.push(text, log.response.error) |> ignore); 101 | 102 | let serialize = x => 103 | x->Array.mapWithIndex(Entry.serialize)->Js.String.concatMany("\n"); -------------------------------------------------------------------------------- /src/Node/N.re: -------------------------------------------------------------------------------- 1 | /* Node.js bindings */ 2 | 3 | exception Exception(Js.Exn.t); 4 | 5 | module OS = Node__OS; 6 | module Util = Node__Util; 7 | module Fs = Node__Fs; 8 | -------------------------------------------------------------------------------- /src/Node/Node__Fs.re: -------------------------------------------------------------------------------- 1 | [@bs.module "fs"] 2 | external readdir: (string, (option(Js.Exn.t), array(string)) => unit) => unit = 3 | "readdir"; 4 | 5 | [@bs.module "fs"] 6 | external access: (string, Js.null(Js.Exn.t) => unit) => unit = "access"; 7 | [@bs.module "fs"] 8 | external readFile: (string, (option(Js.Exn.t), Node.Buffer.t) => unit) => unit = 9 | "readFile"; 10 | [@bs.module "fs"] 11 | external unlink: (string, option(Js.Exn.t) => unit) => unit = "unlink"; 12 | -------------------------------------------------------------------------------- /src/Node/Node__OS.re: -------------------------------------------------------------------------------- 1 | /* Node OS API */ 2 | 3 | [@bs.module "os"] external type_: unit => string = "type"; 4 | -------------------------------------------------------------------------------- /src/Node/Node__Util.re: -------------------------------------------------------------------------------- 1 | [@bs.module "util"] 2 | external promisify: 3 | (('a, (option(Js.Exn.t), 'b) => unit) => unit) => 4 | (. 'a) => Js.Promise.t('b) = 5 | "promisify"; 6 | -------------------------------------------------------------------------------- /src/Parser/Parser__Type.re: -------------------------------------------------------------------------------- 1 | /* Parsing S-Expressions */ 2 | /* Courtesy of @NightRa */ 3 | module SExpression = { 4 | type t = 5 | | A(string) 6 | | L(array(t)); 7 | 8 | let rec toString = 9 | fun 10 | | A(s) => "\"" ++ s ++ "\"" 11 | | L(xs) => 12 | "[" ++ (Array.map(toString, xs) |> Js.Array.joinWith(", ")) ++ "]"; 13 | }; 14 | -------------------------------------------------------------------------------- /src/RunningInfo.re: -------------------------------------------------------------------------------- 1 | open Atom; 2 | 3 | type t = { 4 | mutable editor: option(TextEditor.t), 5 | mutable isOpeningEditor: bool, 6 | mutable buffer: array(string), 7 | mutable subscriptions: CompositeDisposable.t, 8 | }; 9 | let make = () => { 10 | editor: None, 11 | isOpeningEditor: false, 12 | buffer: [||], 13 | subscriptions: CompositeDisposable.make(), 14 | }; 15 | 16 | let itemOptions = { 17 | "initialLine": 0, 18 | "initialColumn": 0, 19 | "split": "right", 20 | "activatePane": false, 21 | "activateItem": false, 22 | "pending": false, 23 | "searchAllPanes": true, 24 | "location": (None: option(string)), 25 | }; 26 | 27 | let destroy = self => { 28 | self.editor = None; 29 | self.isOpeningEditor = false; 30 | self.buffer = [||]; 31 | self.subscriptions |> CompositeDisposable.dispose; 32 | }; 33 | 34 | let add = (info, self) => 35 | switch (self.editor) { 36 | | Some(editor) => 37 | editor |> TextEditor.insertText(info) |> ignore; 38 | Promise.resolved(); 39 | | None => 40 | if (self.isOpeningEditor) { 41 | Js.Array.unshift(info, self.buffer) |> ignore; 42 | Promise.resolved(); 43 | } else { 44 | self.isOpeningEditor = true; 45 | let itemURI = "agda-mode://running-info"; 46 | 47 | Workspace.open_(itemURI, itemOptions) 48 | ->Promise.Js.fromBsPromise 49 | ->Promise.Js.toResult 50 | ->Promise.mapOk(newItem => { 51 | self.isOpeningEditor = false; 52 | // register the newly opened editor 53 | self.editor = Some(newItem); 54 | // insert logs in buffer to the editor and clean the buffer 55 | TextEditor.insertText( 56 | Js.String.concatMany(self.buffer, ""), 57 | newItem, 58 | ) 59 | |> ignore; 60 | // empty the buffer 61 | self.buffer = [||]; 62 | // destroy everything on close 63 | 64 | TextEditor.onDidDestroy(() => self |> destroy, newItem) 65 | |> CompositeDisposable.add(self.subscriptions); 66 | }) 67 | ->Promise.map(_ => ()); 68 | } 69 | }; -------------------------------------------------------------------------------- /src/Task/Task.re: -------------------------------------------------------------------------------- 1 | type header = string; 2 | type placeholder = string; 3 | 4 | type editorTask = 5 | | Save; 6 | 7 | module Highlightings = { 8 | type t = 9 | | AddDirectly(array(Highlighting.Annotation.t)) 10 | | AddIndirectly(string); 11 | }; 12 | 13 | type goalTask = 14 | | GetPointed(callback(Goal.t)) 15 | | GetPointedOr(callback(Goal.t), callback(unit)) 16 | | JumpToTheNext 17 | | JumpToThePrevious 18 | 19 | and t = 20 | | WithInstance(callbackP(Instance__Type.t)) 21 | | WithConnection(callbackP(Connection.t)) 22 | | Disconnect 23 | // View 24 | | Activate 25 | | Deactivate 26 | | Display(header, Type.View.Header.style, Body.t) 27 | | Inquire(header, placeholder, string, callback(string)) 28 | // Editor 29 | | Editor(editorTask) 30 | // Goals 31 | | Goals(goalTask) 32 | // Highlightings 33 | | Highlightings(Highlightings.t) 34 | // Request 35 | | DispatchCommand(Command.t) 36 | | SendRequest(Request.t) 37 | and callback('a) = 'a => list(t) 38 | and callbackP('a) = 39 | 'a => Promise.t(Rebase.result(list(t), Instance__Type.error)); 40 | 41 | let return = x => Promise.resolved(Rebase.Ok(x)); 42 | -------------------------------------------------------------------------------- /src/Task/Task__DisplayInfo.re: -------------------------------------------------------------------------------- 1 | open Task; 2 | open! Type.View.Header; 3 | 4 | // Response.Info => Task 5 | let handle = (info: Response.Info.t): list(Task.t) => 6 | switch (info) { 7 | | CompilationOk => [Display("Compilation Done!", Success, Nothing)] 8 | | Constraints(None) => [Display("No Constraints", Success, Nothing)] 9 | | Constraints(Some(payload)) => [ 10 | Display("Constraints", Info, Emacs(Constraints(payload))), 11 | ] 12 | | AllGoalsWarnings(payload) => [ 13 | Display(payload.title, Info, Emacs(AllGoalsWarnings(payload))), 14 | ] 15 | | Time(payload) => [ 16 | Display("Time", PlainText, Emacs(PlainText(payload))), 17 | ] 18 | | Error(payload) => [Display("Error", Error, Emacs(Error(payload)))] 19 | | Intro(payload) => [ 20 | Display("Intro", PlainText, Emacs(PlainText(payload))), 21 | ] 22 | | Auto(payload) => [ 23 | Display("Auto", PlainText, Emacs(PlainText(payload))), 24 | ] 25 | | ModuleContents(payload) => [ 26 | Display("Module Contents", Info, Emacs(PlainText(payload))), 27 | ] 28 | | SearchAbout(payload) => [ 29 | Display( 30 | "Searching about ...", 31 | PlainText, 32 | Emacs(SearchAbout(payload)), 33 | ), 34 | ] 35 | | WhyInScope(payload) => [ 36 | Display("Scope info", Info, Emacs(WhyInScope(payload))), 37 | ] 38 | | NormalForm(payload) => [ 39 | Display("Normal form", Info, Emacs(PlainText(payload))), 40 | ] 41 | | GoalType(payload) => [ 42 | Display("Goal type", Info, Emacs(GoalTypeContext(payload))), 43 | ] 44 | | CurrentGoal(payload) => [ 45 | Display("Current goal", Info, Emacs(PlainText(payload))), 46 | ] 47 | | InferredType(payload) => [ 48 | Display("Inferred type", Info, Emacs(PlainText(payload))), 49 | ] 50 | | Context(payload) => [ 51 | Display("Context", Info, Emacs(Context(payload))), 52 | ] 53 | | HelperFunction(payload) => [ 54 | Display("Helper function", Info, Emacs(PlainText(payload))), 55 | ] 56 | | Version(payload) => [ 57 | Display("Version", Info, Emacs(PlainText(payload))), 58 | ] 59 | }; 60 | -------------------------------------------------------------------------------- /src/Task/Task__Error.re: -------------------------------------------------------------------------------- 1 | open! Rebase; 2 | 3 | open Instance__Type; 4 | open Task; 5 | 6 | let handle = 7 | fun 8 | | ParseError(errors) => [ 9 | WithConnection( 10 | conn => { 11 | // log the errors 12 | errors |> Array.forEach(e => Log.logError(e, conn.Connection.log)); 13 | // and display with the log 14 | return([ 15 | Display( 16 | "Parse Error", 17 | Type.View.Header.Error, 18 | Emacs(ParseError(conn)), 19 | ), 20 | ]); 21 | }, 22 | ), 23 | WithInstance( 24 | instance => { 25 | Editors.Focus.on(Editors.Source, instance.editors); 26 | return([]); 27 | }, 28 | ), 29 | ] 30 | 31 | | ConnectionError(error) => { 32 | let (header, body) = Connection.Error.toString(error); 33 | [ 34 | Display( 35 | "Connection-related Error: " ++ header, 36 | Type.View.Header.Error, 37 | Emacs(PlainText(body)), 38 | ), 39 | WithInstance( 40 | instance => { 41 | Editors.Focus.on(Editors.Source, instance.editors); 42 | return([]); 43 | }, 44 | ), 45 | ]; 46 | } 47 | | Cancelled => [ 48 | Display( 49 | "Query Cancelled", 50 | Type.View.Header.Error, 51 | Emacs(PlainText("")), 52 | ), 53 | WithInstance( 54 | instance => { 55 | Editors.Focus.on(Editors.Source, instance.editors); 56 | return([]); 57 | }, 58 | ), 59 | ] 60 | | OutOfGoal => [ 61 | Display( 62 | "Out of goal", 63 | Type.View.Header.Error, 64 | Emacs(PlainText("Please place the cursor in a goal")), 65 | ), 66 | WithInstance( 67 | instance => { 68 | Editors.Focus.on(Editors.Source, instance.editors); 69 | return([]); 70 | }, 71 | ), 72 | ]; 73 | -------------------------------------------------------------------------------- /src/Type/Type.re: -------------------------------------------------------------------------------- 1 | module Location = Type__Location; 2 | module View = Type__View; -------------------------------------------------------------------------------- /src/Type/Type__View.re: -------------------------------------------------------------------------------- 1 | open Type__Location; 2 | 3 | /* open Type__Type__Syntax.Name; 4 | open Type__Type__Syntax.Position; 5 | open Type__Type__Syntax.Concrete; */ 6 | 7 | module Header = { 8 | type style = 9 | | PlainText 10 | | Error 11 | | Info 12 | | Success 13 | | Warning; 14 | type t = { 15 | text: string, 16 | style, 17 | }; 18 | }; 19 | /* action */ 20 | type mountingTarget = 21 | | AtBottom 22 | | AtPane; 23 | /* state */ 24 | type mountingPoint = 25 | | Bottom(Webapi.Dom.Element.t) 26 | | Pane(Tab.t); 27 | type mode = 28 | | Display 29 | | Inquire; 30 | 31 | module Mouse = { 32 | type event = 33 | | JumpToTarget(Range.linkTarget) 34 | | MouseOver(Range.linkTarget) 35 | | MouseOut(Range.linkTarget); 36 | 37 | let emitter = React.createContext((_ev: event) => ()); 38 | 39 | module Provider = { 40 | [@bs.obj] 41 | external makeProps: 42 | (~value: event => unit, ~children: React.element, unit) => 43 | { 44 | . 45 | "children": React.element, 46 | "value": event => unit, 47 | }; 48 | 49 | let make = React.Context.provider(emitter); 50 | }; 51 | }; 52 | 53 | module Debug = { 54 | type inputMethod = { 55 | activated: bool, 56 | markers: array(Atom.DisplayMarker.t), 57 | buffer: Buffer.t, 58 | }; 59 | 60 | type action = 61 | | UpdateInputMethod(inputMethod); 62 | 63 | type state = {inputMethod}; 64 | 65 | let reducer = (_state, action) => { 66 | switch (action) { 67 | | UpdateInputMethod(inputMethod) => {inputMethod: inputMethod} 68 | }; 69 | }; 70 | 71 | let initialState = { 72 | inputMethod: { 73 | activated: false, 74 | markers: [||], 75 | buffer: Buffer.initial, 76 | }, 77 | }; 78 | 79 | let debugDispatch = React.createContext((_: action) => ()); 80 | 81 | module Provider = { 82 | [@bs.obj] 83 | external makeProps: 84 | (~value: action => unit, ~children: React.element, unit) => 85 | { 86 | . 87 | "children": React.element, 88 | "value": action => unit, 89 | }; 90 | let make = React.Context.provider(debugDispatch); 91 | }; 92 | }; -------------------------------------------------------------------------------- /src/Util/Channel.re: -------------------------------------------------------------------------------- 1 | type t('input, 'output) = Resource.t('input => Promise.t('output)); 2 | 3 | let make = Resource.make; 4 | 5 | let send = (input, channel) => 6 | channel.Resource.acquire()->Promise.flatMap(trigger => trigger(input)); 7 | 8 | let sendTo = (channel, input) => 9 | channel.Resource.acquire()->Promise.flatMap(trigger => trigger(input)); 10 | 11 | let recv = (callback, channel) => channel.Resource.supply(callback); 12 | -------------------------------------------------------------------------------- /src/Util/Resource.re: -------------------------------------------------------------------------------- 1 | open Belt; 2 | 3 | type t('a) = { 4 | acquire: unit => Promise.t('a), 5 | supply: 'a => unit, 6 | }; 7 | let make = (): t('a) => { 8 | // resource that is temporarily unavailable 9 | let resource = ref(None: option('a)); 10 | // queue of callbacks waiting to be resolved 11 | let queue = ref([]); 12 | // return the resource if it's immediately available, else waits in the queue 13 | let acquire = () => 14 | switch (resource^) { 15 | | None => 16 | let (promise, resolve) = Promise.pending(); 17 | queue := [resolve, ...queue^]; 18 | promise; 19 | | Some(x) => Promise.resolved(x) 20 | }; 21 | // iterate through the list of waiting callbacks and resolve them 22 | let supply = x => { 23 | resource := Some(x); 24 | (queue^)->List.forEach(resolve => resolve(x)); 25 | }; 26 | {acquire, supply}; 27 | }; -------------------------------------------------------------------------------- /src/View/Channels.re: -------------------------------------------------------------------------------- 1 | open Type.View; 2 | 3 | module Event = Event; 4 | // open Event; 5 | 6 | type t = { 7 | // lifecycle 8 | destroy: Channel.t(unit, unit), 9 | // 10 | activatePanel: Channel.t(unit, unit), 11 | deactivatePanel: Channel.t(unit, unit), 12 | toggleDocking: Channel.t(unit, unit), 13 | display: Channel.t((Header.t, Body.t), unit), 14 | inquire: 15 | Channel.t( 16 | (Header.t, string, string), 17 | Rebase.result(string, MiniEditor.error), 18 | ), 19 | updateIsPending: Channel.t(bool, unit), 20 | // updateShouldDisplay: Channel.t(bool, unit, unit), 21 | // Input Method 22 | /* 23 | Issue #34: https://github.com/banacorn/agda-mode/issues/34 24 | Intercept some keys that Bracket Matcher autocompletes 25 | to name them all: "{", "[", "{", "\"", "'", and ` 26 | Because the Bracket Matcher package is too lacking, it does not responds 27 | to the disabling of the package itself, making it impossible to disable 28 | the package during the process of input. 29 | Instead, we hardwire the keys we wanna intercept directly from the Keymaps. 30 | */ 31 | activateInputMethod: Channel.t(bool, unit), 32 | interceptAndInsertKey: Channel.t(string, unit), 33 | // 34 | navigateSettings: Channel.t(option(Settings__Breadcrumb.uri), unit), 35 | updateConnection: 36 | Channel.t((option(Connection.t), option(Connection.Error.t)), unit), 37 | inquireConnection: 38 | Channel.t(unit, Rebase.result(string, MiniEditor.error)), 39 | }; 40 | 41 | /* creates all refs and return them */ 42 | let make = () => { 43 | // lifecycle 44 | destroy: Channel.make(), 45 | // 46 | activatePanel: Channel.make(), 47 | deactivatePanel: Channel.make(), 48 | toggleDocking: Channel.make(), 49 | 50 | display: Channel.make(), 51 | inquire: Channel.make(), 52 | 53 | updateIsPending: Channel.make(), 54 | 55 | // 56 | activateInputMethod: Channel.make(), 57 | interceptAndInsertKey: Channel.make(), 58 | 59 | // 60 | navigateSettings: Channel.make(), 61 | updateConnection: Channel.make(), 62 | inquireConnection: Channel.make(), 63 | }; 64 | 65 | let context = React.createContext(make()); 66 | 67 | module Provider = { 68 | [@bs.obj] 69 | external makeProps: 70 | (~value: t, ~children: React.element, unit) => 71 | { 72 | . 73 | "children": React.element, 74 | "value": t, 75 | } = 76 | ""; 77 | let make = React.Context.provider(context); 78 | }; 79 | -------------------------------------------------------------------------------- /src/View/Component.re: -------------------------------------------------------------------------------- 1 | module Range = Component__Range; 2 | module Link = Component__Link; 3 | -------------------------------------------------------------------------------- /src/View/Component__Link.re: -------------------------------------------------------------------------------- 1 | open Type.Location.Range; 2 | 3 | [@react.component] 4 | let make = 5 | ( 6 | ~target=RangeLink(NoRange), 7 | ~jump=false, 8 | ~hover=false, 9 | ~className=[], 10 | ~children, 11 | ) => { 12 | let target_ = 13 | switch (target) { 14 | | RangeLink(NoRange) 15 | | RangeLink(Range(_, [||])) => None 16 | | HoleLink(index) => Some(HoleLink(index)) 17 | | RangeLink(range) => Some(RangeLink(range)) 18 | }; 19 | 20 | let emit = React.useContext(Type.View.Mouse.emitter); 21 | 22 | switch (target_) { 23 | | None => 24 | 25 | children 26 | 27 | | Some(t) => 28 | 31 | if (jump) { 32 | emit(JumpToTarget(t)); 33 | } 34 | } 35 | onMouseOver={_ => 36 | if (hover) { 37 | emit(MouseOver(t)); 38 | } 39 | } 40 | onMouseOut={_ => 41 | if (hover) { 42 | emit(MouseOut(t)); 43 | } 44 | }> 45 | children 46 | 47 | }; 48 | }; 49 | -------------------------------------------------------------------------------- /src/View/Component__Range.re: -------------------------------------------------------------------------------- 1 | 2 | 3 | open Type.Location; 4 | 5 | module Link = Component__Link; 6 | 7 | [@react.component] 8 | let make = (~range, ~abbr=false) => 9 | if (abbr) { 10 | 11 | 12 | ; 13 | } else { 14 | 15 | 16 | {ReasonReact.string(Range.toString(range))} 17 | 18 | ; 19 | }; 20 | -------------------------------------------------------------------------------- /src/View/Emacs/Emacs.re: -------------------------------------------------------------------------------- 1 | module Component = Emacs__Component; 2 | 3 | // module Body = Emacs__Body; 4 | module Parser = Emacs__Parser; 5 | module AllGoalsWarnings = Emacs__AllGoalsWarnings; 6 | -------------------------------------------------------------------------------- /src/View/Emacs/Emacs__Body.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | 3 | type t = 4 | | AllGoalsWarnings(Emacs__AllGoalsWarnings.t) 5 | | GoalTypeContext(string) 6 | | Context(string) 7 | | Constraints(string) 8 | | WhyInScope(string) 9 | | SearchAbout(string) 10 | | Error(string) 11 | | ParseError(Connection.t) 12 | | PlainText(string); 13 | 14 | [@react.component] 15 | let make = (~data: t) => { 16 | switch (data) { 17 | | AllGoalsWarnings(value) => 18 | | GoalTypeContext(body) => 19 | | Context(body) => 20 | | Constraints(body) => 21 | | WhyInScope(body) => 22 | | SearchAbout(body) => 23 | | Error(body) => 24 | | ParseError(connection) => 25 | | PlainText(body) => body == "" ? null :

{string(body)}

26 | }; 27 | }; -------------------------------------------------------------------------------- /src/View/Emacs/Emacs__Context.re: -------------------------------------------------------------------------------- 1 | open Rebase; 2 | 3 | open Emacs__Component; 4 | 5 | let parse: string => array(Output.t) = 6 | raw => { 7 | let lines = raw |> Js.String.split("\n") |> Emacs__Parser.unindent; 8 | lines |> Array.map(Output.parse) |> Array.filterMap(x => x); 9 | }; 10 | 11 | [@react.component] 12 | let make = (~body: string) => 13 |
    14 | {parse(body) 15 | |> Array.mapi((value, i) => ) 16 | |> React.array} 17 |
; -------------------------------------------------------------------------------- /src/View/Emacs/Emacs__Error.re: -------------------------------------------------------------------------------- 1 | open Emacs__Component; 2 | open Rebase.Option; 3 | open Rebase; 4 | 5 | let parse: string => array(WarningError.t) = 6 | raw => { 7 | let lines = raw |> Js.String.split("\n"); 8 | lines 9 | |> Util.Dict.partite(((_, i)) => i === 0 ? Some("errors") : None) 10 | |> Emacs__Parser.partiteWarningsOrErrors("errors") 11 | |> Js.Dict.get(_, "errors") 12 | |> mapOr( 13 | metas => 14 | metas 15 | |> Array.map(WarningError.parseError) 16 | |> Array.filterMap(x => x), 17 | [||], 18 | ); 19 | }; 20 | 21 | [@react.component] 22 | let make = (~body: string) => 23 |
    24 | {parse(body) 25 | |> Array.mapi((value, i) => 26 | 27 | ) 28 | |> React.array} 29 |
; -------------------------------------------------------------------------------- /src/View/Emacs/Emacs__GoalTypeContext.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | 3 | open Rebase; 4 | open Rebase.Option; 5 | 6 | open Emacs__Component; 7 | 8 | type t = { 9 | goal: option(Expr.t), 10 | have: option(Expr.t), 11 | interactionMetas: array(Output.t), 12 | hiddenMetas: array(Output.t), 13 | }; 14 | let parse = raw => { 15 | let markGoal = ((line, _)) => 16 | line |> Js.String.match([%re "/^Goal:/"]) |> map(_ => "goal"); 17 | let markHave = ((line, _)) => 18 | line |> Js.String.match([%re "/^Have:/"]) |> map(_ => "have"); 19 | let markMetas = ((line, _)) => 20 | line |> Js.String.match([%re "/\\u2014{60}/g"]) |> map(_ => "metas"); 21 | let partiteGoalTypeContext = 22 | Util.Dict.partite(line => 23 | or_(or_(markGoal(line), markHave(line)), markMetas(line)) 24 | ); 25 | let removeDelimeter = Util.Dict.update("metas", Js.Array.sliceFrom(1)); 26 | let lines = raw |> Js.String.split("\n"); 27 | let dictionary = 28 | lines 29 | |> partiteGoalTypeContext 30 | |> removeDelimeter 31 | |> Emacs__Parser.partiteMetas; 32 | /* extract entries from the dictionary */ 33 | let goal = 34 | "goal" 35 | |> Js.Dict.get(dictionary) 36 | |> flatMap(line => 37 | line 38 | |> List.fromArray 39 | |> String.joinWith("\n") 40 | |> Js.String.sliceToEnd(~from=5) 41 | |> Expr.parse 42 | ); 43 | let have = 44 | "have" 45 | |> Js.Dict.get(dictionary) 46 | |> flatMap(line => 47 | line 48 | |> List.fromArray 49 | |> String.joinWith("\n") 50 | |> Js.String.sliceToEnd(~from=5) 51 | |> Expr.parse 52 | ); 53 | let interactionMetas = 54 | "interactionMetas" 55 | |> Js.Dict.get(dictionary) 56 | |> mapOr( 57 | metas => 58 | metas 59 | |> Array.map(Output.parseOutputWithoutRange) 60 | |> Array.filterMap(x => x), 61 | [||], 62 | ); 63 | let hiddenMetas = 64 | "hiddenMetas" 65 | |> Js.Dict.get(dictionary) 66 | |> mapOr( 67 | metas => 68 | metas 69 | |> Array.map(Output.parseOutputWithRange) 70 | |> Array.filterMap(x => x), 71 | [||], 72 | ); 73 | {goal, have, interactionMetas, hiddenMetas}; 74 | }; 75 | 76 | [@react.component] 77 | let make = (~body: string) => { 78 | let parsed = parse(body); 79 | <> 80 |
    81 | {parsed.goal 82 | |> Option.mapOr(expr => , null)} 83 | {parsed.have 84 | |> Option.mapOr(expr => , null)} 85 |
86 | {
    87 | {parsed.interactionMetas 88 | |> Array.mapi((value, i) => ) 89 | |> React.array} 90 |
} 91 | {
    92 | {parsed.hiddenMetas 93 | |> Array.mapi((value, i) => ) 94 | |> React.array} 95 |
} 96 | ; 97 | }; -------------------------------------------------------------------------------- /src/View/Emacs/Emacs__ParseError.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | 3 | [@react.component] 4 | let make = (~connection: Connection.t) => { 5 |
6 |

7 | {string( 8 | "Something went terribly wrong when trying to parse some responses from Agda", 9 | )} 10 |

11 |

12 | {string( 13 | "Please press the button down here, copy the generated log and paste it ", 14 | )} 15 | 16 | {string("here")} 17 | 18 |

19 |

20 | 25 |

26 |
; 27 | }; -------------------------------------------------------------------------------- /src/View/Emacs/Emacs__Parser.re: -------------------------------------------------------------------------------- 1 | open Rebase; 2 | 3 | open Rebase.Option; 4 | 5 | /* open Type.View.Emacs; */ 6 | 7 | let unindent: array(string) => array(string) = 8 | lines => { 9 | let isNewline = (line, nextLine) => { 10 | let sort = [%re "/^Sort \\S*/"]; 11 | let delimeter = [%re "/^\\u2014{4}/g"]; 12 | /* banana : Banana */ 13 | let completeJudgement = [%re 14 | "/^(?:(?:[^\\(\\{\\s]+\\s+\\:=?)|Have\\:|Goal\\:)\\s* \\S*/" 15 | ]; 16 | /* case when the term's name is too long, the rest of the judgement 17 | would go to the next line, e.g: 18 | banananananananananananananananana 19 | : Banana 20 | */ 21 | let reallyLongTermIdentifier = [%re "/^\\S+$/"]; 22 | let restOfTheJudgement = [%re "/^\\s*\\:=?\\s* \\S*/"]; 23 | Js.Re.test_(sort, line) 24 | || Js.Re.test_(delimeter, line) 25 | || Js.Re.test_(reallyLongTermIdentifier, line) 26 | && nextLine 27 | |> exists(line => Js.Re.test_(restOfTheJudgement, line)) 28 | || Js.Re.test_(completeJudgement, line); 29 | }; 30 | let newLineIndices: array(int) = 31 | lines 32 | |> Array.mapi((line, index) => (line, lines[index + 1], index)) 33 | |> Array.filter(((line, nextLine, _)) => isNewline(line, nextLine)) 34 | |> Array.map(((_, _, index)) => index); 35 | newLineIndices 36 | |> Array.mapi((index, i) => 37 | switch (newLineIndices[i + 1]) { 38 | | None => (index, Array.length(lines) + 1) 39 | | Some(n) => (index, n) 40 | } 41 | ) 42 | |> Array.map(((from, to_)) => 43 | lines 44 | |> Array.slice(~from, ~to_) 45 | |> List.fromArray 46 | |> String.joinWith("\n") 47 | ); 48 | }; 49 | 50 | let partiteMetas = 51 | Util.Dict.split("metas", (rawMetas: array(string)) => { 52 | let metas = unindent(rawMetas); 53 | let indexOfHiddenMetas = 54 | metas 55 | |> Array.findIndex(s => 56 | s |> Emacs__Component.Output.parseOutputWithRange |> isSome 57 | ) 58 | |> map(fst); 59 | metas 60 | |> Util.Dict.partite(((_, i)) => 61 | switch (indexOfHiddenMetas) { 62 | | Some(n) => 63 | if (i === n) { 64 | Some("hiddenMetas"); 65 | } else if (i === 0) { 66 | Some("interactionMetas"); 67 | } else { 68 | None; 69 | } 70 | | None => 71 | /* All interaction metas */ 72 | if (i === 0) { 73 | Some("interactionMetas"); 74 | } else { 75 | None; 76 | } 77 | } 78 | ); 79 | }); 80 | 81 | let partiteWarningsOrErrors = key => 82 | Util.Dict.update( 83 | key, 84 | (raw: array(string)) => { 85 | let hasDelimeter = 86 | raw[0] |> flatMap(Js.String.match([%re "/^\\u2014{4}/"])) |> isSome; 87 | let lines = hasDelimeter ? raw |> Js.Array.sliceFrom(1) : raw; 88 | let markWarningStart = line => 89 | line |> Type.Location.Range.parse |> isSome; 90 | /* If the previous warning of error ends with "at", then we have to glue it back */ 91 | let glueBack = xs => 92 | xs[Array.length(xs) - 1] 93 | |> flatMap(Js.String.match([%re "/at$/"])) 94 | |> isSome; 95 | lines 96 | |> Util.Array_.partite(markWarningStart) 97 | |> Util.Array_.mergeWithNext(glueBack) 98 | |> Array.map(xs => xs |> List.fromArray |> String.joinWith("\n")); 99 | }, 100 | ); 101 | -------------------------------------------------------------------------------- /src/View/Emacs/Emacs__SearchAbout.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | 3 | open Rebase; 4 | open Rebase.Option; 5 | 6 | open Emacs__Component; 7 | 8 | let parse: string => (string, array(Output.t)) = 9 | raw => { 10 | let lines = raw |> Js.String.split("\n"); 11 | let target = 12 | lines[0] |> map(Js.String.sliceToEnd(~from=18)) |> getOr("???"); 13 | let outputs = 14 | lines 15 | |> Js.Array.sliceFrom(1) 16 | |> Array.map(s => s |> Js.String.sliceToEnd(~from=2)) 17 | |> Emacs__Parser.unindent 18 | |> Array.map(Output.parse) 19 | |> Array.filterMap(x => x); 20 | (target, outputs); 21 | }; 22 | 23 | [@react.component] 24 | let make = (~body: string) => { 25 | let (target, outputs) = parse(body); 26 | Array.length(outputs) === 0 27 | ?

{string("There are no definitions about " ++ target)}

28 | : <> 29 |

{string("Definitions about " ++ target ++ ":")}

30 |
    31 | {outputs 32 | |> Array.mapi((value, i) => 33 | 34 | ) 35 | |> React.array} 36 |
37 | ; 38 | }; -------------------------------------------------------------------------------- /src/View/Emacs/Emacs__WhyInScope.re: -------------------------------------------------------------------------------- 1 | 2 | 3 | open Emacs__Component; 4 | open Rebase.Option; 5 | 6 | let parse: string => array(PlainText.t) = 7 | raw => { 8 | raw |> PlainText.parse |> getOr([||]); 9 | }; 10 | 11 | [@react.component] 12 | let make = (~body: string) => { 13 | let value = parse(body); 14 |

</p>; 15 | }; 16 | -------------------------------------------------------------------------------- /src/View/Events.re: -------------------------------------------------------------------------------- 1 | open Type.View; 2 | open Event; 3 | 4 | type t = { 5 | // <Panel> 6 | onInquire: Event.t(Rebase.result(string, MiniEditor.error)), 7 | /* Input Method */ 8 | onInputMethodChange: Event.t(InputMethod.state), 9 | /* Mouse Events */ 10 | onMouseEvent: Event.t(Mouse.event), 11 | }; 12 | 13 | /* creates all refs and return them */ 14 | let make = () => { 15 | let onInquire = make(); 16 | 17 | /* <InputMethod> related */ 18 | let onInputMethodChange = Event.make(); 19 | 20 | // Others 21 | let onMouseEvent = make(); 22 | 23 | {onInquire, onInputMethodChange, onMouseEvent}; 24 | }; 25 | -------------------------------------------------------------------------------- /src/View/Hook.re: -------------------------------------------------------------------------------- 1 | open Rebase; 2 | 3 | let useDidUpdateEffect = (f, inputs) => { 4 | let didMountRef = React.useRef(false); 5 | React.useEffect1( 6 | () => 7 | if (React.Ref.current(didMountRef)) { 8 | f(); 9 | } else { 10 | React.Ref.setCurrent(didMountRef, true); 11 | None; 12 | }, 13 | inputs, 14 | ); 15 | }; 16 | 17 | let useDidUpdateEffect2 = (f, (a, b)) => { 18 | let didMountRef = React.useRef(false); 19 | React.useEffect2( 20 | () => 21 | if (React.Ref.current(didMountRef)) { 22 | f(); 23 | } else { 24 | React.Ref.setCurrent(didMountRef, true); 25 | None; 26 | }, 27 | (a, b), 28 | ); 29 | }; 30 | 31 | let useState = init => { 32 | let (state, setState) = React.useState(_ => init); 33 | let setState' = value => setState(_ => value); 34 | (state, setState'); 35 | }; 36 | 37 | let useAtomListener = listener => { 38 | React.useEffect(() => { 39 | let destructor = listener(); 40 | Some(() => Atom.Disposable.dispose(destructor)); 41 | }); 42 | }; 43 | 44 | let useAtomListenerWhen = (listener, shouldListen) => { 45 | let (destructor, setDestructor) = React.useState(_ => None); 46 | 47 | React.useEffect1( 48 | () => { 49 | if (shouldListen) { 50 | let destructor = listener(); 51 | setDestructor(_ => Some(() => Atom.Disposable.dispose(destructor))); 52 | } else { 53 | // execute the destructor 54 | destructor |> Option.forEach(f => f()); 55 | }; 56 | 57 | // return the destructor in case that it got unmounted 58 | destructor; 59 | }, 60 | [|shouldListen|], 61 | ); 62 | }; 63 | 64 | let useListenWhen = (listener, shouldListen) => { 65 | let (destructor, setDestructor) = React.useState(_ => None); 66 | 67 | React.useEffect1( 68 | () => { 69 | if (shouldListen) { 70 | setDestructor(_ => listener()); 71 | } else { 72 | // execute the destructor 73 | destructor 74 | |> Option.forEach(f => { 75 | f(); 76 | setDestructor(_ => None); 77 | }); 78 | }; 79 | None; 80 | }, 81 | // destructor; 82 | [|shouldListen|], 83 | ); 84 | }; 85 | 86 | let useChannel = (callback, channel) => { 87 | React.useEffect1( 88 | () => { 89 | channel |> Channel.recv(callback); 90 | None; 91 | }, 92 | [||], 93 | ); 94 | }; 95 | -------------------------------------------------------------------------------- /src/View/Panel/Body.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | 3 | open Rebase; 4 | 5 | type t = 6 | | Nothing 7 | | Emacs(Emacs__Body.t); 8 | // | JSON(Type.View.JSON.rawBody); 9 | 10 | [@react.component] 11 | let make = (~body: t, ~hidden) => { 12 | let comp = 13 | switch (body) { 14 | | Nothing => null 15 | // | JSON(_) => null 16 | | Emacs(data) => <Emacs__Body data /> 17 | }; 18 | let className = 19 | hidden 20 | ? ["agda-body", "native-key-bindings", "hidden"] 21 | |> String.joinWith(" ") 22 | : ["agda-body", "native-key-bindings"] |> String.joinWith(" "); 23 | <section className tabIndex=(-1)> comp </section>; 24 | }; -------------------------------------------------------------------------------- /src/View/Panel/Dashboard.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | open Util.React; 3 | open Rebase; 4 | 5 | [@react.component] 6 | let make = 7 | ( 8 | ~header: Type.View.Header.t, 9 | ~hidden: bool, 10 | ~isPending: bool, 11 | ~mountingPoint: Type.View.mountingPoint, 12 | ~settingsActivated: bool, 13 | ~onMountingTargetChange: Type.View.mountingTarget => unit, 14 | ~onSettingsViewToggle: bool => unit, 15 | ) => { 16 | let settingsButtonRef = React.useRef(Js.Nullable.null); 17 | let dockingButtonRef = React.useRef(Js.Nullable.null); 18 | 19 | React.useEffect1( 20 | () => 21 | settingsButtonRef 22 | |> React.Ref.current 23 | |> Js.Nullable.toOption 24 | |> Option.flatMap(settingsButton => { 25 | let disposable = 26 | Atom.Tooltips.add( 27 | Atom.Views.getView(settingsButton), 28 | { 29 | "title": "settings", 30 | "delay": { 31 | "show": 100, 32 | "hide": 1000, 33 | }, 34 | }, 35 | ); 36 | Some(() => disposable |> Atom.Disposable.dispose); 37 | }), 38 | [||], 39 | ); 40 | 41 | React.useEffect1( 42 | () => 43 | dockingButtonRef 44 | |> React.Ref.current 45 | |> Js.Nullable.toOption 46 | |> Option.flatMap(dockingButton => { 47 | let disposable = 48 | Atom.Tooltips.add( 49 | Atom.Views.getView(dockingButton), 50 | { 51 | "title": "toggle panel docking position", 52 | "delay": { 53 | "show": 300, 54 | "hide": 1000, 55 | }, 56 | "keyBindingCommand": "agda-mode:toggle-docking", 57 | }, 58 | ); 59 | Some(() => disposable |> Atom.Disposable.dispose); 60 | }), 61 | [||], 62 | ); 63 | 64 | let headerClassList = 65 | switch (header.style) { 66 | | PlainText => "" 67 | | Error => "text-error" 68 | | Info => "text-info" 69 | | Success => "text-success" 70 | | Warning => "text-warning" 71 | }; 72 | let spinnerClassList = 73 | "loading loading-spinner-tiny inline-block" ++ when_(isPending, "pending"); 74 | let settingsViewClassList = 75 | "no-btn" ++ when_(settingsActivated, "activated"); 76 | let toggleMountingPosition = 77 | "no-btn" 78 | ++ when_( 79 | switch (mountingPoint) { 80 | | Pane(_) => true 81 | | _ => false 82 | }, 83 | "activated", 84 | ); 85 | 86 | <div className={"agda-header" ++ showWhen(!hidden)}> 87 | <h1 className=headerClassList> {string(header.text)} </h1> 88 | <ul className="agda-dashboard"> 89 | <li> <span id="spinner" className=spinnerClassList /> </li> 90 | <li> 91 | <button 92 | id="agda-dashboard-settings" 93 | className=settingsViewClassList 94 | onClick={_ => onSettingsViewToggle(!settingsActivated)} 95 | ref={ReactDOMRe.Ref.domRef(settingsButtonRef)}> 96 | <span className="icon icon-settings" /> 97 | </button> 98 | </li> 99 | <li> 100 | <button 101 | className=toggleMountingPosition 102 | onClick={_ => 103 | switch (mountingPoint) { 104 | | Pane(_) => onMountingTargetChange(Type.View.AtBottom) 105 | | _ => onMountingTargetChange(Type.View.AtPane) 106 | } 107 | } 108 | ref={ReactDOMRe.Ref.domRef(dockingButtonRef)}> 109 | <span className="icon icon-versions" /> 110 | </button> 111 | </li> 112 | </ul> 113 | </div>; 114 | }; 115 | -------------------------------------------------------------------------------- /src/View/Panel/InputMethod/Buffer.re: -------------------------------------------------------------------------------- 1 | open Rebase; 2 | 3 | type t = { 4 | // the symbol at the front of the sequence along with the sequence it replaced 5 | symbol: option((string, string)), 6 | // the sequence following the symbol we see on the text editor 7 | tail: string, 8 | }; 9 | 10 | // examples of Buffer.t: 11 | // user typed: l => { symbol: Some("←", "l"), tail: "" } 12 | // user typed: lambd => { symbol: Some("←", "lambd"), tail: "ambd" } 13 | // user typed: lambda => { symbol: Some("λ", "lambda"), tail: "" } 14 | 15 | let init = string => 16 | Js.String.substring(~from=0, ~to_=String.length(string) - 1, string); 17 | 18 | let initial = {symbol: None, tail: ""}; 19 | 20 | let isEmpty = self => { 21 | self.symbol == None && String.isEmpty(self.tail); 22 | }; 23 | 24 | let toSequence = self => 25 | switch (self.symbol) { 26 | | None => self.tail 27 | | Some((_, sequence)) => sequence ++ self.tail 28 | }; 29 | 30 | let toSurface = self => 31 | switch (self.symbol) { 32 | | None => self.tail 33 | | Some((symbol, _)) => symbol ++ self.tail 34 | }; 35 | 36 | let toString = self => 37 | "\"" ++ toSurface(self) ++ "\"[" ++ toSequence(self) ++ "]"; 38 | 39 | type action = 40 | | Noop 41 | | Insert(t) // update the buffer accordingly 42 | | Backspace(t) // update the buffer accordingly 43 | | Rewrite(t) // should rewrite the text buffer 44 | | Complete // should deactivate 45 | | Stuck(int); // should deactivate, too 46 | 47 | // devise the next state 48 | let next = (self, reality) => { 49 | let surface = toSurface(self); 50 | let sequence = toSequence(self); 51 | if (reality == surface) { 52 | if (Translator.translate(sequence).further && reality != "\\") { 53 | Noop; 54 | } else { 55 | Complete; 56 | }; 57 | } else if (init(reality) == surface) { 58 | // insertion 59 | let insertedChar = Js.String.substr(~from=-1, reality); 60 | let sequence' = sequence ++ insertedChar; 61 | let translation = Translator.translate(sequence'); 62 | switch (translation.symbol) { 63 | | Some(symbol) => 64 | if (insertedChar == symbol && insertedChar == "\\") { 65 | Stuck(0); 66 | } else { 67 | Rewrite({symbol: Some((symbol, sequence')), tail: ""}); 68 | } 69 | | None => 70 | if (translation.further) { 71 | Insert({...self, tail: self.tail ++ insertedChar}); 72 | } else { 73 | Stuck(1); 74 | } 75 | }; 76 | } else if (reality == init(surface) || reality == init(sequence)) { 77 | // backspace deletion 78 | if (String.isEmpty(reality)) { 79 | // if the symbol is gone 80 | if (Option.isSome(self.symbol)) { 81 | // A symbol has just been backspaced and gone 82 | // replace it with the underlying sequence (backspaced) 83 | Rewrite({ 84 | symbol: None, 85 | tail: init(sequence), 86 | }); 87 | } else { 88 | Stuck(2); 89 | }; 90 | } else { 91 | // normal backspace 92 | Backspace({...self, tail: init(self.tail)}); 93 | }; 94 | } else { 95 | Stuck(3); 96 | }; 97 | }; 98 | -------------------------------------------------------------------------------- /src/View/Panel/InputMethod/CandidateSymbols.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | open Util.React; 3 | 4 | open Rebase; 5 | 6 | open Webapi; 7 | 8 | type action = 9 | | Up 10 | | Down 11 | | Right 12 | | Left; 13 | 14 | let reducer = (totalSize, index, action) => 15 | switch (action) { 16 | | Up => max(0, index - 10) 17 | | Right => min(totalSize - 1, index + 1) 18 | | Down => min(totalSize - 1, index + 10) 19 | | Left => max(0, index - 1) 20 | }; 21 | 22 | [@react.component] 23 | let make = 24 | ( 25 | ~activated: bool, 26 | ~candidateSymbols: array(string), 27 | ~updateTranslation: option(string) => unit, 28 | ~chooseSymbol: string => unit, 29 | ) => { 30 | let (index, move) = 31 | React.useReducer(reducer(Array.length(candidateSymbols)), 0); 32 | 33 | Hook.useAtomListenerWhen( 34 | () => 35 | Atom.Commands.add( 36 | `CSSSelector("atom-text-editor.agda-mode-input-method-activated"), 37 | "core:move-up", 38 | event => { 39 | move(Up); 40 | event |> Dom.Event.stopImmediatePropagation; 41 | }, 42 | ), 43 | activated, 44 | ); 45 | 46 | Hook.useAtomListenerWhen( 47 | () => 48 | Atom.Commands.add( 49 | `CSSSelector("atom-text-editor.agda-mode-input-method-activated"), 50 | "core:move-right", 51 | event => { 52 | move(Right); 53 | event |> Dom.Event.stopImmediatePropagation; 54 | }, 55 | ), 56 | activated, 57 | ); 58 | 59 | Hook.useAtomListenerWhen( 60 | () => 61 | Atom.Commands.add( 62 | `CSSSelector("atom-text-editor.agda-mode-input-method-activated"), 63 | "core:move-down", 64 | event => { 65 | move(Down); 66 | event |> Dom.Event.stopImmediatePropagation; 67 | }, 68 | ), 69 | activated, 70 | ); 71 | 72 | Hook.useAtomListenerWhen( 73 | () => 74 | Atom.Commands.add( 75 | `CSSSelector("atom-text-editor.agda-mode-input-method-activated"), 76 | "core:move-left", 77 | event => { 78 | move(Left); 79 | event |> Dom.Event.stopImmediatePropagation; 80 | }, 81 | ), 82 | activated, 83 | ); 84 | 85 | React.useEffect1( 86 | () => { 87 | updateTranslation(candidateSymbols[index]); 88 | None; 89 | }, 90 | [|index|], 91 | ); 92 | 93 | let rowStart = index / 10 * 10; 94 | let row = 95 | candidateSymbols |> Array.slice(~from=rowStart, ~to_=rowStart + 10); 96 | switch (candidateSymbols[index]) { 97 | | None => null 98 | | Some(_) => 99 | row 100 | |> Array.mapi((key, i) => { 101 | let isSelected = rowStart + i === index; 102 | <button 103 | className={"btn" ++ when_(isSelected, "selected")} 104 | onClick={_ => chooseSymbol(key)} 105 | key> 106 | {string(key)} 107 | </button>; 108 | }) 109 | |> ReactDOMRe.createDOMElementVariadic( 110 | "div", 111 | ~props= 112 | ReactDOMRe.domProps( 113 | ~className="candidates btn-group btn-group-sm", 114 | (), 115 | ), 116 | ) 117 | }; 118 | }; 119 | -------------------------------------------------------------------------------- /src/View/Panel/InputMethod/Extension.re: -------------------------------------------------------------------------------- 1 | // For adding or prioritizing key mapping 2 | open Rebase; 3 | open Fn; 4 | open Json.Decode; 5 | 6 | type keymap = Js.Dict.t(array(string)); 7 | 8 | let defaultKeymap = () => { 9 | let keymap = Js.Dict.empty(); 10 | Js.Dict.set(keymap, "^r", [|{js|ʳ|js}|]); 11 | Js.Dict.set(keymap, "^l", [|{js|ˡ|js}|]); 12 | keymap; 13 | }; 14 | 15 | let readConfig = () => { 16 | switch ( 17 | Js.undefinedToOption(Atom.Config.get("agda-mode.inputMethodExtension")) 18 | ) { 19 | | None => "{}" 20 | | Some(s) => s 21 | }; 22 | }; 23 | 24 | let setConfig = keymap => { 25 | open! Json.Encode; 26 | 27 | let encoder: keymap => Js.Json.t = dict(array(string)); 28 | 29 | Atom.Config.set( 30 | "agda-mode.inputMethodExtension", 31 | Json.stringify(encoder(keymap)), 32 | ) 33 | |> ignore; 34 | }; 35 | 36 | let parse: string => option(keymap) = 37 | Json.parse >> Option.map(dict(array(string))); 38 | 39 | let readKeymap = readConfig >> parse >> Option.getOr(Js.Dict.empty()); 40 | 41 | let lookup = key => Js.Dict.get(readKeymap(), key) |> Option.getOr([||]); 42 | 43 | let add = (key, symbols) => { 44 | let keymap = readKeymap(); 45 | switch (Js.Dict.get(keymap, key)) { 46 | | None => Js.Dict.set(keymap, key, symbols) 47 | | Some(existing) => 48 | // put the existing symbols in the back 49 | Js.Dict.set(keymap, key, Array.concat(existing, symbols)) 50 | }; 51 | 52 | setConfig(keymap); 53 | }; 54 | 55 | let modify = (key, symbols) => { 56 | let keymap = readKeymap(); 57 | Js.Dict.set(keymap, key, symbols); 58 | setConfig(keymap); 59 | }; 60 | 61 | let delete = key => { 62 | let keymap = readKeymap(); 63 | let delete': string => unit = [%raw 64 | "function (id) { 65 | delete keymap[id] 66 | }" 67 | ]; 68 | delete'(key); 69 | setConfig(keymap); 70 | }; 71 | 72 | let resetToDefault = () => { 73 | setConfig(defaultKeymap()); 74 | }; 75 | 76 | let extendKeySuggestions = (key, origionalSuggestions) => { 77 | let extension = 78 | readKeymap() 79 | |> Js.Dict.keys 80 | |> Array.filter(String.startsWith(key)) 81 | |> Array.map(String.sub(~from=String.length(key), ~length=1)) 82 | |> Array.filter(s => String.length(s) === 1); 83 | 84 | // no repeated elements 85 | let union = (xs, ys) => { 86 | ys |> Array.filter(y => !Js.Array.includes(y, xs)) |> Array.concat(xs); 87 | }; 88 | 89 | union(origionalSuggestions, extension) |> Js.Array.sortInPlace; 90 | }; 91 | 92 | // if the extened symbols are prioritized over the origional ones 93 | let extendCandidateSymbols = (key, originalCandidates) => { 94 | let extension = lookup(key); 95 | 96 | let removedOverlaps = 97 | originalCandidates |> Array.filter(s => !Js.Array.includes(s, extension)); // remove the overlapping symbols 98 | // prefix the extension symbols 99 | Array.concat(removedOverlaps, extension); 100 | }; -------------------------------------------------------------------------------- /src/View/Panel/InputMethod/Translator.re: -------------------------------------------------------------------------------- 1 | open Rebase; 2 | 3 | // key - symbols mapping 4 | 5 | [@bs.module "./../../../../../../asset/query.js"] 6 | external rawTable: Js.Dict.t(array(string)) = "default"; 7 | 8 | // trie 9 | 10 | type trie = { 11 | symbol: array(string), 12 | subTrie: Js.Dict.t(trie), 13 | }; 14 | [@bs.module "./../../../../../../asset/keymap.js"] 15 | external rawKeymapObject: Js.t({.}) = "default"; 16 | 17 | let rec fromObject = (obj: Js.t({.})): trie => { 18 | let symbol = [%raw {| 19 | obj[">>"] || [] 20 | |}]; 21 | let subTrie = 22 | obj 23 | |> Js.Obj.keys 24 | |> Array.filter(key => key != ">>") 25 | |> Array.map(key => (key, fromObject([%raw {| 26 | obj[key] 27 | |}]))) 28 | |> Js.Dict.fromArray; 29 | {symbol, subTrie}; 30 | }; 31 | 32 | let keymap = fromObject(rawKeymapObject); 33 | 34 | let toKeySuggestions = (trie: trie): array(string) => 35 | Js.Dict.keys(trie.subTrie); 36 | 37 | let toCandidateSymbols = (trie: trie): array(string) => trie.symbol; 38 | 39 | // see if the key sequence is in the keymap 40 | // returns (KeySuggestions, CandidateSymbols) 41 | let isInKeymap = (input: string): option(trie) => { 42 | let rec helper = (input: string, trie: trie): option(trie) => 43 | switch (String.length(input)) { 44 | | 0 => Some(trie) 45 | | n => 46 | let key = String.sub(~from=0, ~length=1, input); 47 | let rest = String.sub(~from=1, ~length=n - 1, input); 48 | switch (Js.Dict.get(trie.subTrie, key)) { 49 | | Some(trie') => helper(rest, trie') 50 | | None => None 51 | }; 52 | }; 53 | helper(input, keymap); 54 | }; 55 | 56 | // // see if the key sequence is in the extension */ 57 | // let isInExtension = (input: string): option(trie) => {}; 58 | 59 | type translation = { 60 | symbol: option(string), 61 | further: bool, 62 | keySuggestions: array(string), 63 | candidateSymbols: array(string), 64 | }; 65 | 66 | /* converts characters to symbol, and tells if there's any further possible combinations */ 67 | let translate = (input: string): translation => { 68 | let trie = isInKeymap(input); 69 | let keySuggestions = 70 | trie 71 | |> Option.mapOr(toKeySuggestions, [||]) 72 | |> Extension.extendKeySuggestions(input); 73 | 74 | let candidateSymbols = 75 | trie 76 | |> Option.mapOr(toCandidateSymbols, [||]) 77 | |> Extension.extendCandidateSymbols(input); 78 | 79 | { 80 | symbol: candidateSymbols[0], 81 | further: Array.length(keySuggestions) != 0, 82 | keySuggestions, 83 | candidateSymbols, 84 | }; 85 | }; 86 | let initialTranslation = translate(""); 87 | 88 | let lookup = (symbol): option(array(string)) => { 89 | symbol 90 | |> Js.String.codePointAt(0) 91 | |> Option.map(string_of_int) 92 | |> Option.flatMap(Js.Dict.get(rawTable)); 93 | }; -------------------------------------------------------------------------------- /src/View/Panel/SizingHandle.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | 3 | open Rebase; 4 | 5 | open Webapi; 6 | 7 | let calculateBodyHeight = (handleRef, handleY: int): option(int) => { 8 | handleRef 9 | |> React.Ref.current 10 | |> Js.Nullable.toOption 11 | |> Option.flatMap(elem => { 12 | let top = 13 | ( 14 | Dom.Element.getBoundingClientRect(elem) 15 | |> Dom.DomRect.top 16 | |> int_of_float 17 | ) 18 | + 51; /* border-width: 1px */ 19 | Dom.Document.querySelector("atom-panel-container.footer", Dom.document) 20 | |> Option.flatMap(element => { 21 | let bottom = 22 | element 23 | |> Dom.Element.getBoundingClientRect 24 | |> Dom.DomRect.top 25 | |> int_of_float; 26 | if (top > 0) { 27 | Some(bottom - handleY - 51); 28 | } else { 29 | None; 30 | }; 31 | }); 32 | }); 33 | }; 34 | 35 | [@react.component] 36 | let make = 37 | ( 38 | ~onResizeStart: int => unit, 39 | ~onResizeEnd: int => unit, 40 | ~mountAtBottom: bool, 41 | ) => { 42 | let handleRef = React.useRef(Js.Nullable.null); 43 | mountAtBottom 44 | ? <div className="sizing-handle-anchor"> 45 | <div 46 | className="sizing-handle native-key-bindings" 47 | ref={ReactDOMRe.Ref.domRef(handleRef)} 48 | onDragStart={ev => 49 | ev 50 | |> ReactEvent.Mouse.clientY 51 | |> calculateBodyHeight(handleRef) 52 | |> Option.forEach(onResizeStart) 53 | } 54 | onDragEnd={ev => 55 | ev 56 | |> ReactEvent.Mouse.clientY 57 | |> calculateBodyHeight(handleRef) 58 | |> Option.forEach(onResizeEnd) 59 | } 60 | /* to enable Drag & Drop */ 61 | draggable=true 62 | tabIndex=(-1) 63 | /> 64 | </div> 65 | : null; 66 | }; 67 | -------------------------------------------------------------------------------- /src/View/Root.re: -------------------------------------------------------------------------------- 1 | open Rebase; 2 | 3 | open Type.View; 4 | 5 | module Event = Event; 6 | 7 | [@react.component] 8 | let make = (~editors: Editors.t, ~events: Events.t, ~channels: Channels.t) => { 9 | //////////////////////////////////////////// 10 | // <Settings> 11 | //////////////////////////////////////////// 12 | let (settingsURI, setSettingsURI) = Hook.useState(Settings.URI.Root); 13 | let settingsViewRef = React.useRef(None); 14 | 15 | let (settingsElement, setSettingsElement) = Hook.useState(None); 16 | 17 | let updateSettings = 18 | fun 19 | | None => { 20 | // update settingsViewRef 21 | React.Ref.setCurrent(settingsViewRef, None); 22 | // update settingsElement 23 | setSettingsElement(None); 24 | // update settingsURI 25 | setSettingsURI(Settings.URI.Root); 26 | } 27 | | Some((uri, tab)) => { 28 | // update settingsViewRef 29 | React.Ref.setCurrent(settingsViewRef, Some(tab)); 30 | // update settingsElement 31 | settingsViewRef 32 | |> React.Ref.current 33 | |> Option.map(Tab.getElement) 34 | |> setSettingsElement; 35 | // update settingsURI 36 | setSettingsURI(uri); 37 | }; 38 | 39 | Hook.useChannel( 40 | fun 41 | | None => 42 | switch (settingsViewRef |> React.Ref.current) { 43 | // Close => Close 44 | | None => Promise.resolved() 45 | // Open => Close 46 | | Some(tab) => 47 | Tab.kill(tab); 48 | updateSettings(None); 49 | Promise.resolved(); 50 | } 51 | | Some(address) => 52 | switch (settingsViewRef |> React.Ref.current) { 53 | // Close => Open 54 | | None => 55 | let resource = Resource.make(); 56 | let tab = 57 | Tab.make( 58 | ~editor=editors.source, 59 | ~getTitle= 60 | () => "[Settings] " ++ Atom.TextEditor.getTitle(editors.source), 61 | ~path="settings", 62 | ~onOpen=(_, _, _) => resource.supply(), 63 | ~onClose=_ => updateSettings(None), 64 | (), 65 | ); 66 | updateSettings(Some((address, tab))); 67 | resource.acquire(); 68 | // Open => Open 69 | | Some(_) => Promise.resolved() 70 | }, 71 | channels.navigateSettings, 72 | ); 73 | 74 | let (debug, debugDispatch) = 75 | React.useReducer(Debug.reducer, Debug.initialState); 76 | 77 | let settingsActivated = 78 | switch (settingsViewRef |> React.Ref.current) { 79 | | Some(_) => true 80 | | None => false 81 | }; 82 | 83 | let onSettingsViewToggle = shouldOpen => 84 | channels.navigateSettings 85 | |> Channel.send(shouldOpen ? Some(Settings__Breadcrumb.Root) : None) 86 | |> ignore; 87 | 88 | let {Events.onInputMethodChange} = events; 89 | <> 90 | <Channels.Provider value=channels> 91 | <Mouse.Provider value={event => events.onMouseEvent.emit(event)}> 92 | <Debug.Provider value=debugDispatch> 93 | <Panel 94 | editors 95 | settingsActivated 96 | onInputMethodChange 97 | onSettingsViewToggle 98 | onInquireQuery={events.onInquire} 99 | /> 100 | <Settings debug targetURI=settingsURI element=settingsElement /> 101 | </Debug.Provider> 102 | </Mouse.Provider> 103 | </Channels.Provider> 104 | </>; 105 | }; 106 | 107 | let initialize = editors => { 108 | open Webapi.Dom; 109 | let element = document |> Document.createElement("article"); 110 | let events = Events.make(); 111 | let channels = Channels.make(); 112 | let view = View.make(events, channels); 113 | 114 | let component = 115 | React.createElementVariadic( 116 | make, 117 | makeProps(~editors, ~events, ~channels, ()), 118 | [||], 119 | ); 120 | 121 | ReactDOMRe.render(component, element); 122 | /* return the handles for drilling */ 123 | view; 124 | }; -------------------------------------------------------------------------------- /src/View/Settings/Settings.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | open Util.React; 3 | open Rebase.Fn; 4 | 5 | module URI = Settings__Breadcrumb; 6 | type uri = URI.uri; 7 | 8 | let at = (x, y, classNames) => { 9 | classNames ++ showWhen(x == y); 10 | }; 11 | 12 | [@react.component] 13 | let make = 14 | // ~inquireConnection: Event.t(unit, unit), 15 | // ~onInquireConnection: Event.t(string, MiniEditor.error), 16 | ( 17 | ~targetURI: uri, 18 | ~debug: Type.View.Debug.state, 19 | ~element: option(Webapi.Dom.Element.t), 20 | ) => { 21 | let channels = React.useContext(Channels.context); 22 | let ((connection, connectionError), setConnectionAndError) = 23 | Hook.useState((None, None)); 24 | Hook.useChannel( 25 | setConnectionAndError >> Promise.resolved, 26 | channels.updateConnection, 27 | ); 28 | 29 | let (uri, setURI) = Hook.useState(targetURI); 30 | React.useEffect1( 31 | () => { 32 | setURI(targetURI); 33 | None; 34 | }, 35 | [|targetURI|], 36 | ); 37 | 38 | let inDevMode = Atom.inDevMode(); 39 | switch (element) { 40 | | None => null 41 | | Some(anchor) => 42 | ReactDOMRe.createPortal( 43 | <section className="agda-settings" tabIndex=(-1)> 44 | <Settings__Breadcrumb uri onNavigate=setURI /> 45 | <div className="agda-settings-pages"> 46 | <ul className={at(URI.Root, uri, "agda-settings-menu")}> 47 | <li onClick={_ => setURI(URI.Connection)}> 48 | <span className="icon icon-plug"> {string("Connection")} </span> 49 | </li> 50 | <li onClick={_ => setURI(URI.Log)}> 51 | <span className="icon icon-comment-discussion"> 52 | {string("Log")} 53 | </span> 54 | </li> 55 | <li onClick={_ => setURI(URI.InputMethod)}> 56 | <span className="icon icon-keyboard"> 57 | {string("Input Method")} 58 | </span> 59 | </li> 60 | {inDevMode 61 | ? <li onClick={_ => setURI(URI.Debug)}> 62 | <span className="icon icon-terminal"> 63 | {string("Debug")} 64 | </span> 65 | </li> 66 | : null} 67 | </ul> 68 | <Settings__Connection 69 | connection 70 | // inquireConnection 71 | // onInquireConnection 72 | error=connectionError 73 | hidden={uri != URI.Connection} 74 | /> 75 | <Settings__Log connection hidden={uri != URI.Log} /> 76 | <Settings__InputMethod hidden={uri != URI.InputMethod} /> 77 | <Settings__Debug debug hidden={uri != URI.Debug} /> 78 | </div> 79 | </section>, 80 | anchor, 81 | ) 82 | }; 83 | }; 84 | -------------------------------------------------------------------------------- /src/View/Settings/Settings__Breadcrumb.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | 3 | type uri = 4 | | Root 5 | | Connection 6 | | Log 7 | | InputMethod 8 | | Debug; 9 | 10 | [@react.component] 11 | let make = (~uri: uri, ~onNavigate: uri => unit) => 12 | <nav className="agda-settings-breadcrumb"> 13 | <ol className="breadcrumb"> 14 | <li> 15 | <a href="#" onClick={_ => onNavigate(Root)}> 16 | <span className="icon icon-settings"> {string("Settings")} </span> 17 | </a> 18 | </li> 19 | {switch (uri) { 20 | | Root => null 21 | | Connection => 22 | <li> 23 | <a href="#"> 24 | <span className="icon icon-plug"> {string("Connection")} </span> 25 | </a> 26 | </li> 27 | | Log => 28 | <li> 29 | <a href="#"> 30 | <span className="icon icon-comment-discussion"> 31 | {string("Log")} 32 | </span> 33 | </a> 34 | </li> 35 | | InputMethod => 36 | <li> 37 | <a href="#"> 38 | <span className="icon icon-keyboard"> 39 | {string("Input Method")} 40 | </span> 41 | </a> 42 | </li> 43 | | Debug => 44 | <li> 45 | <a href="#"> 46 | <span className="icon icon-terminal"> {string("Debug")} </span> 47 | </a> 48 | </li> 49 | }} 50 | </ol> 51 | </nav>; 52 | -------------------------------------------------------------------------------- /src/View/Settings/Settings__Connection.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | open! Rebase; 3 | open Util.React; 4 | 5 | [@react.component] 6 | let make = 7 | ( 8 | ~connection: option(Connection.t), 9 | ~error: option(Connection.Error.t), 10 | ~hidden, 11 | ) => { 12 | let channels = React.useContext(Channels.context); 13 | let (autoSearchError, setAutoSearchError) = Hook.useState(None); 14 | let editorRef = Resource.make(); 15 | let onSetPath = Event.make(); 16 | 17 | /* triggering autoSearch */ 18 | let handleAutoSearch = _ => { 19 | let promise = Connection.autoSearch("agda"); 20 | promise->Promise.getOk(path => 21 | editorRef.acquire() 22 | ->Promise.getOk(editor => editor |> Atom.TextEditor.setText(path)) 23 | ); 24 | // report error when autoSearch failed 25 | promise->Promise.getError(err => setAutoSearchError(Some(err))); 26 | }; 27 | 28 | let focusOnPathEditor = editor => { 29 | editor |> Atom.Views.getView |> Webapi.Dom.HtmlElement.focus; 30 | editor |> Atom.TextEditor.selectAll |> ignore; 31 | onSetPath.once(); 32 | }; 33 | 34 | // focus on the path editor on `inquireConnection` 35 | Hook.useChannel( 36 | () => editorRef.acquire()->Promise.flatMapOk(focusOnPathEditor), 37 | channels.inquireConnection, 38 | ); 39 | 40 | let connected = connection |> Option.isSome; 41 | let className = 42 | "agda-settings-connection" 43 | ++ showWhen(!hidden) 44 | ++ when_(!connected, "inquiring"); 45 | let status = 46 | connected 47 | ? <span 48 | title="connected" 49 | id="connection-status" 50 | className="icon icon-primitive-dot text-success" 51 | /> 52 | : <span 53 | title="disconnected" 54 | id="connection-status" 55 | className="icon icon-primitive-dot text-error" 56 | />; 57 | <section className> 58 | <h1> 59 | <span className="icon icon-plug" /> 60 | <span> {string("Connection to Agda")} </span> 61 | status 62 | </h1> 63 | <hr /> 64 | <h2> {string("Status")} </h2> 65 | {switch (connection) { 66 | | None => <> <p> {string("connection not established")} </p> </> 67 | | Some(conn) => 68 | <> 69 | <p> {string("Path: " ++ conn.metadata.path)} </p> 70 | <p> {string("Version: " ++ conn.metadata.version)} </p> 71 | <p> 72 | {string( 73 | "Supported protocol: " 74 | ++ Connection.Metadata.Protocol.toString(conn.metadata.protocol), 75 | )} 76 | </p> 77 | </> 78 | }} 79 | <hr /> 80 | <h2> {string("Path")} </h2> 81 | <p> 82 | <MiniEditor 83 | hidden=false 84 | value={ 85 | switch (connection) { 86 | | None => "" 87 | | Some(conn) => conn.metadata.path 88 | } 89 | } 90 | placeholder="path to Agda" 91 | onEditorRef={x => editorRef.supply(Ok(x))} 92 | onConfirm={path => { 93 | setAutoSearchError(None); 94 | onSetPath.emit(Ok(path)); 95 | }} 96 | /> 97 | </p> 98 | <p> 99 | <button 100 | className="btn icon icon-search inline-block-tight" 101 | onClick=handleAutoSearch> 102 | {string("auto search")} 103 | </button> 104 | </p> 105 | {switch (autoSearchError) { 106 | | None => 107 | switch (error) { 108 | | None => null 109 | | Some(err) => <Settings__Connection__Error error=err /> 110 | } 111 | | Some(err) => <Settings__Connection__Error error=err /> 112 | }} 113 | </section>; 114 | }; -------------------------------------------------------------------------------- /src/View/Settings/Settings__Connection__Error.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | 3 | [@react.component] 4 | let make = (~error: Connection.Error.t) => { 5 | let (header, body) = Connection.Error.toString(error); 6 | <> 7 | <hr /> 8 | <h2> {string("Error: " ++ header)} </h2> 9 | <p> {string("error message:")} </p> 10 | <pre className="inset-panel padded text-warning error"> 11 | {string(body)} 12 | </pre> 13 | </>; 14 | }; -------------------------------------------------------------------------------- /src/View/Settings/Settings__Debug.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | open Rebase; 3 | open Util.React; 4 | open Type.View.Debug; 5 | 6 | [@react.component] 7 | let make = (~debug: state, ~hidden) => { 8 | let {inputMethod} = debug; 9 | <section className={"agda-settings-debug" ++ showWhen(!hidden)}> 10 | <h1> 11 | <span className="icon icon-terminal" /> 12 | <span> {string("Debug")} </span> 13 | </h1> 14 | <p> {string("only available in dev mode")} </p> 15 | <hr /> 16 | <h2> 17 | <span> {string("Input Method")} </span> 18 | {inputMethod.activated 19 | ? <span 20 | title="activated" 21 | id="input-method-activation" 22 | className="icon icon-primitive-dot text-success" 23 | /> 24 | : <span 25 | title="deactivated" 26 | id="input-method-activation" 27 | className="icon icon-primitive-dot text-error" 28 | />} 29 | </h2> 30 | <p> 31 | {string("input sequence : ")} 32 | <span className="inline-block highlight"> 33 | {string(Buffer.toSequence(inputMethod.buffer))} 34 | </span> 35 | </p> 36 | <p> 37 | {string("output buffer : ")} 38 | <span className="inline-block highlight"> 39 | {string(Buffer.toSurface(inputMethod.buffer))} 40 | </span> 41 | </p> 42 | <p> 43 | {string("# of markers : ")} 44 | <span className="inline-block highlight"> 45 | {string(string_of_int(Array.length(inputMethod.markers)))} 46 | </span> 47 | </p> 48 | <div className="block"> 49 | <button className="btn" onClick={_ => Js.log(inputMethod.markers)}> 50 | {string("Dump Markers")} 51 | </button> 52 | </div> 53 | </section>; 54 | }; 55 | -------------------------------------------------------------------------------- /src/View/Settings/Settings__Log.re: -------------------------------------------------------------------------------- 1 | open ReasonReact; 2 | open Util.React; 3 | open Rebase; 4 | 5 | module Entry = { 6 | [@react.component] 7 | let make = (~entry: Log.Entry.t) => { 8 | let (hidden, setHidden) = Hook.useState(true); 9 | let className = hidden ? "hidden" : ""; 10 | let rawTexts = 11 | entry.response.rawText 12 | |> Array.mapi((text, i) => 13 | <li key={string_of_int(i)}> {string(text)} </li> 14 | ) 15 | |> React.array; 16 | let sexpressions = 17 | entry.response.sexpression 18 | |> Array.mapi((text, i) => 19 | <li key={string_of_int(i)}> 20 | {string(Parser.SExpression.toString(text))} 21 | </li> 22 | ) 23 | |> React.array; 24 | let responses = 25 | entry.response.response 26 | |> Array.mapi((text, i) => 27 | <li key={string_of_int(i)}> 28 | {string(Response.toString(text))} 29 | </li> 30 | ) 31 | |> React.array; 32 | let hasError = Array.length(entry.response.error) > 0; 33 | let errors = 34 | entry.response.error 35 | |> Array.mapi((text, i) => 36 | <li key={string_of_int(i)}> 37 | {string(Parser.Error.toString(text))} 38 | </li> 39 | ) 40 | |> React.array; 41 | 42 | <li className="agda-settings-log-entry"> 43 | <h2 onClick={_ => setHidden(!hidden)}> 44 | {string(Request.toString(entry.request))} 45 | </h2> 46 | <section className> 47 | <h3> {string("raw text")} </h3> 48 | <ol> rawTexts </ol> 49 | <hr /> 50 | <h3> {string("s-expression")} </h3> 51 | <ol> sexpressions </ol> 52 | <hr /> 53 | <h3> {string("response")} </h3> 54 | <ol> responses </ol> 55 | {hasError 56 | ? <> <hr /> <h3> {string("error")} </h3> <ol> errors </ol> </> 57 | : null} 58 | </section> 59 | </li>; 60 | }; 61 | }; 62 | 63 | [@react.component] 64 | let make = (~connection: option(Connection.t), ~hidden) => { 65 | let (showInstruction, setShowInstruction) = Hook.useState(false); 66 | let (refreshOnLoad, setRefreshOnLoad) = Hook.useState(true); 67 | connection 68 | |> Option.forEach(conn => conn.Connection.resetLogOnLoad = refreshOnLoad); 69 | 70 | let entries = 71 | connection 72 | |> Option.mapOr(conn => conn.Connection.log, [||]) 73 | |> Array.mapi((entry, i) => <Entry entry key={string_of_int(i)} />) 74 | |> React.array; 75 | 76 | <section className={"agda-settings-log" ++ showWhen(!hidden)}> 77 | <h1> 78 | <span className="icon icon-comment-discussion" /> 79 | <span> {string("Log")} </span> 80 | </h1> 81 | <hr /> 82 | <p> 83 | {string( 84 | "Keeps track of what Agda said what we've parsed. For reporting parse errors. ", 85 | )} 86 | </p> 87 | <p> 88 | <label className="input-label"> 89 | <input 90 | className="input-toggle" 91 | type_="checkbox" 92 | checked=refreshOnLoad 93 | onChange={_ => setRefreshOnLoad(!refreshOnLoad)} 94 | /> 95 | {string("Refresh on Load (C-c C-l)")} 96 | </label> 97 | </p> 98 | <p> 99 | <button 100 | onClick={_ => { 101 | setShowInstruction(true); 102 | connection |> Option.forEach(Connection.dump); 103 | }} 104 | className="btn btn-primary icon icon-clippy"> 105 | {string("Dump log")} 106 | </button> 107 | </p> 108 | {showInstruction 109 | ? <p className="text-warning"> 110 | {string( 111 | "In case of parse error, please copy the log and paste it ", 112 | )} 113 | <a href="https://github.com/banacorn/agda-mode/issues/new"> 114 | {string("here")} 115 | </a> 116 | </p> 117 | : null} 118 | <hr /> 119 | <ol> entries </ol> 120 | </section>; 121 | }; -------------------------------------------------------------------------------- /src/View/View.re: -------------------------------------------------------------------------------- 1 | open Type.View; 2 | 3 | /************************************************************************************************************/ 4 | 5 | type t = { 6 | // <Panel> related 7 | activate: unit => Promise.t(unit), 8 | deactivate: unit => Promise.t(unit), 9 | toggleDocking: unit => Promise.t(unit), 10 | display: (string, Type.View.Header.style, Body.t) => Promise.t(unit), 11 | inquire: 12 | (string, string, string) => 13 | Promise.t(Rebase.result(string, MiniEditor.error)), 14 | updateIsPending: bool => Promise.t(unit), 15 | destroy: unit => Promise.t(unit), 16 | onDestroy: Event.t(unit), 17 | onMouseEvent: Event.t(Mouse.event), 18 | // <InputMethod> related 19 | activateInputMethod: bool => Promise.t(unit), 20 | interceptAndInsertKey: string => Promise.t(unit), 21 | onInputMethodChange: Event.t(InputMethod.state), 22 | // <Settings> related 23 | navigateSettings: Settings__Breadcrumb.uri => Promise.t(unit), 24 | // <Settings/Connection> related 25 | updateConnection: 26 | (option(Connection.t), option(Connection.Error.t)) => Promise.t(unit), 27 | inquireConnection: 28 | unit => Promise.t(Rebase.result(string, MiniEditor.error)), 29 | }; 30 | let make = (events: Events.t, channels: Channels.t) => { 31 | let activate = () => channels.activatePanel |> Channel.send(); 32 | let deactivate = () => channels.deactivatePanel |> Channel.send(); 33 | let toggleDocking = () => channels.toggleDocking |> Channel.send(); 34 | 35 | let display = (text, style, body) => 36 | channels.display |> Channel.send(({Type.View.Header.text, style}, body)); 37 | 38 | let inquire = (text, placeholder, value) => 39 | activate() 40 | ->Promise.flatMap(_ => 41 | channels.inquire 42 | |> Channel.send(( 43 | {Type.View.Header.text, style: PlainText}, 44 | placeholder, 45 | value, 46 | )) 47 | ); 48 | 49 | let updateIsPending = isPending => 50 | channels.updateIsPending |> Channel.send(isPending); 51 | 52 | let onMouseEvent = events.onMouseEvent; 53 | 54 | let activateInputMethod = activate => 55 | channels.activateInputMethod |> Channel.send(activate); 56 | 57 | let interceptAndInsertKey = symbol => 58 | channels.interceptAndInsertKey |> Channel.send(symbol); 59 | 60 | let onInputMethodChange = events.onInputMethodChange; 61 | 62 | let navigateSettings = where => 63 | channels.navigateSettings |> Channel.send(Some(where)); 64 | 65 | let updateConnection = (connection, error) => 66 | channels.updateConnection |> Channel.send((connection, error)); 67 | 68 | let inquireConnection = () => channels.inquireConnection |> Channel.send(); 69 | 70 | let onDestroy = Event.make(); 71 | let destroy = () => 72 | deactivate() 73 | ->Promise.flatMap(_ => activateInputMethod(false)) 74 | ->Promise.flatMap(_ => channels.destroy |> Channel.send()) 75 | ->Promise.tap(_ => onDestroy.emit()); 76 | 77 | { 78 | activate, 79 | deactivate, 80 | display, 81 | inquire, 82 | updateIsPending, 83 | destroy, 84 | onDestroy, 85 | onMouseEvent, 86 | activateInputMethod, 87 | interceptAndInsertKey, 88 | onInputMethodChange, 89 | navigateSettings, 90 | updateConnection, 91 | inquireConnection, 92 | toggleDocking, 93 | }; 94 | }; 95 | -------------------------------------------------------------------------------- /styles/agda-mode.less: -------------------------------------------------------------------------------- 1 | // The ui-variables file is provided by base themes provided by Atom. 2 | // 3 | // See https://github.com/atom/atom-dark-ui/blob/master/stylesheets/ui-variables.less 4 | // for a full listing of what's available. 5 | @import "ui-variables"; 6 | @import "syntax-variables"; 7 | 8 | @import "base.less"; 9 | @import "layout.less"; 10 | @import "module.less"; 11 | -------------------------------------------------------------------------------- /styles/base.less: -------------------------------------------------------------------------------- 1 | // The ui-variables file is provided by base themes provided by Atom. 2 | @import "ui-variables"; 3 | @import "syntax-variables"; 4 | 5 | 6 | 7 | // the main component that houses everything 8 | .agda-mode-panel-container { 9 | 10 | // For hiding React components 11 | .hidden { display: none } 12 | 13 | .icon::before { 14 | width: 1em; 15 | height: 1em; 16 | line-height: 1em; 17 | font-size: inherit; 18 | } 19 | 20 | h2, h3 { 21 | margin: 0 0 1em; 22 | } 23 | 24 | hr { 25 | border-color: @base-border-color; 26 | } 27 | 28 | header { 29 | // flexbox 30 | display: flex; 31 | justify-content: space-between; 32 | 33 | h2, h3 { 34 | margin: 0; 35 | line-height: inherit; 36 | } 37 | 38 | margin-bottom: 2em; 39 | } 40 | 41 | header.compact { 42 | margin-bottom: 0em; 43 | } 44 | 45 | // Makes buttons look like ordinary texts 46 | button.no-btn { 47 | background: inherit; 48 | border: none; 49 | border-radius: @component-border-radius; 50 | padding: 0; 51 | } 52 | button.no-btn:hover { 53 | background: @base-background-color; 54 | } 55 | 56 | ul, 57 | ol { 58 | list-style: none; 59 | margin: 0; 60 | padding: 0; 61 | } 62 | 63 | input[type="text"] { 64 | margin-bottom: 1em; 65 | } 66 | } 67 | 68 | // prevents goal indices from floating above the status bar 69 | // see #14: https://github.com/banacorn/agda-mode/issues/14 70 | status-bar.status-bar { z-index: 4 } 71 | atom-pane > [is="atom-tabs"] { z-index: 5 } 72 | atom-text-editor[data-grammar~="agda"] { 73 | z-index: 0; 74 | } 75 | -------------------------------------------------------------------------------- /test/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/Parser/Response/Issue95-2.6.1-Unix.out: -------------------------------------------------------------------------------- 1 | NoStatus 2 | ClearRunningInfo 3 | ClearHighlighting 4 | RunningInfo 1 Checking Issue95 (/Users/omega/github/agda-mode/test/ManualTests/Issue95.agda).\n 5 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-0 6 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-1 7 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-2 8 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-3 9 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-4 10 | DisplayInfo Error /Users/omega/github/agda-mode/test/ManualTests/Issue95.agda:8,5-9 11 | String != List Char 12 | when checking that the expression "\\" has type List Char 13 | JumpToError /Users/omega/github/agda-mode/test/ManualTests/Issue95.agda 144 14 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode39869-5 15 | NoStatus 16 | -------------------------------------------------------------------------------- /test/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/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/Parser/Response/QuotationMark-2.6.0-Unix.out: -------------------------------------------------------------------------------- 1 | NoStatus 2 | ClearRunningInfo 3 | ClearHighlighting 4 | RunningInfo 1 Checking QuotationMark (/Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda).\n 5 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-0 6 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-1 7 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-2 8 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-3 9 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-4 10 | DisplayInfo Error /Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda:8,5-8 11 | String != List Char 12 | when checking that the expression ")" has type List Char 13 | JumpToError /Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda 150 14 | JumpToError /Users/omega/github/agda-mode/test/ManualTests/QuotationMark.agda 150 15 | HighlightingInfoIndirect /var/folders/r2/lx4mzz2x1kn940m7lhnv0b_h0000gn/T/agda2-mode19020-5 16 | NoStatus 17 | -------------------------------------------------------------------------------- /test/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/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/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/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/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/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/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/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/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/Parser/SourceFile/literate.lagda.md.out: -------------------------------------------------------------------------------- 1 | Hole [0] (112, 113) => (112, 119) "{! !}" 2 | Hole [1] (196, 202) => (196, 202) "{! !}" -------------------------------------------------------------------------------- /test/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/Parser/SourceFile/literate.lagda.org.out: -------------------------------------------------------------------------------- 1 | Hole [0] (128, 135) => (128, 135) "{! 1 !}" -------------------------------------------------------------------------------- /test/Parser/SourceFile/literate.lagda.out: -------------------------------------------------------------------------------- 1 | Hole [0] (106, 107) => (106, 113) "{! !}" 2 | Hole [1] (119, 124) => (119, 124) "{! !}" -------------------------------------------------------------------------------- /test/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 ? -------------------------------------------------------------------------------- /test/Parser/SourceFile/literate.lagda.rst.out: -------------------------------------------------------------------------------- 1 | Hole [0] (113, 114) => (113, 120) "{! !}" -------------------------------------------------------------------------------- /test/Parser/Test__Parser__Response.re: -------------------------------------------------------------------------------- 1 | open Belt; 2 | open BsMocha.Mocha; 3 | open Js.Promise; 4 | open Test__Util; 5 | 6 | open Test__Parser__SExpression; 7 | 8 | // [SExpression] -> [Response] 9 | let toResponses = exprs => { 10 | // keeping the successful parsing result 11 | // Assert.fail on the failed ones 12 | exprs 13 | ->Array.map(Response.parse) 14 | ->Array.map( 15 | fun 16 | | Error(e) => { 17 | Assert.fail(e); 18 | [||]; 19 | } 20 | | Ok(v) => [|v|], 21 | ) 22 | ->Array.concatMany; 23 | }; 24 | 25 | describe("when parsing responses", () => 26 | Golden.getGoldenFilepathsSync("test/Parser/Response") 27 | ->Array.forEach(filepath => 28 | BsMocha.Promise.it("should golden test " ++ filepath, () => 29 | Golden.readFile(filepath) 30 | |> then_(raw => 31 | raw 32 | ->Golden.map(parseSExpression([||])) 33 | ->Golden.map(toResponses) 34 | ->Golden.map(serializeWith(Response.toString)) 35 | ->Golden.compare 36 | ) 37 | ) 38 | ) 39 | ); -------------------------------------------------------------------------------- /test/Parser/Test__Parser__SExpression.re: -------------------------------------------------------------------------------- 1 | open BsMocha.Mocha; 2 | open Js.Promise; 3 | open Test__Util; 4 | 5 | open Belt; 6 | 7 | // [Int] -> String -> [SExpression] 8 | let parseSExpression = (breakpoints, input) => { 9 | open Parser.Incr.Event; 10 | 11 | let output = ref([||]); 12 | 13 | let parser = 14 | Parser.SExpression.makeIncr( 15 | fun 16 | | Yield(Rebase.Error(err)) => 17 | Assert.fail( 18 | "Failed when parsing S-expression: " ++ Parser.Error.toString(err), 19 | ) 20 | | Yield(Rebase.Ok(a)) => Js.Array.push(a, output^) |> ignore 21 | | Stop => (), 22 | ); 23 | 24 | input 25 | ->Js.String.trim 26 | ->breakInput(breakpoints) 27 | ->Array.map(Parser.split) 28 | ->Array.concatMany 29 | ->Array.forEach(Parser.Incr.feed(parser)); 30 | 31 | output^; 32 | }; 33 | 34 | describe("when parsing S-expressions wholly", () => 35 | Golden.getGoldenFilepathsSync("test/Parser/SExpression") 36 | ->Array.forEach(filepath => 37 | BsMocha.Promise.it("should golden test " ++ filepath, () => 38 | Golden.readFile(filepath) 39 | |> then_(raw => 40 | raw 41 | ->Golden.map(parseSExpression([||])) 42 | ->Golden.map(serializeWith(Parser.SExpression.toString)) 43 | ->Golden.compare 44 | ) 45 | ) 46 | ) 47 | ); 48 | 49 | describe("when parsing S-expressions incrementally", () => 50 | Golden.getGoldenFilepathsSync("test/Parser/SExpression") 51 | ->Array.forEach(filepath => 52 | BsMocha.Promise.it("should golden test " ++ filepath, () => 53 | Golden.readFile(filepath) 54 | |> then_(raw => 55 | raw 56 | ->Golden.map( 57 | parseSExpression([|3, 23, 171, 217, 1234, 2342, 3453|]), 58 | ) 59 | ->Golden.map(serializeWith(Parser.SExpression.toString)) 60 | ->Golden.compare 61 | ) 62 | ) 63 | ) 64 | ); -------------------------------------------------------------------------------- /test/Parser/Test__Parser__SourceFile.re: -------------------------------------------------------------------------------- 1 | open Belt; 2 | open BsMocha.Mocha; 3 | open Js.Promise; 4 | open Test__Util; 5 | 6 | describe("when parsing file paths", () => 7 | it("should recognize the file extensions", () => { 8 | open SourceFile.FileType; 9 | Assert.equal(parse("a.agda"), Agda); 10 | Assert.equal(parse("a.lagda"), LiterateTeX); 11 | Assert.equal(parse("a.lagda.tex"), LiterateTeX); 12 | Assert.equal(parse("a.lagda.md"), LiterateMarkdown); 13 | Assert.equal(parse("a.lagda.rst"), LiterateRST); 14 | Assert.equal(parse("a.lagda.org"), LiterateOrg); 15 | }) 16 | ); 17 | 18 | describe("when parsing source files", () => 19 | Golden.getGoldenFilepathsSync("test/Parser/SourceFile") 20 | ->Array.forEach(filepath => 21 | BsMocha.Promise.it("should golden test " ++ filepath, () => 22 | Golden.readFile(filepath) 23 | |> then_(raw => 24 | raw 25 | ->Golden.map( 26 | SourceFile.parse( 27 | [|0, 1, 2, 3, 4, 5, 6, 7, 8, 9|], 28 | filepath, 29 | ), 30 | ) 31 | ->Golden.map(serializeWith(SourceFile.Diff.toString)) 32 | ->Golden.compare 33 | ) 34 | ) 35 | ) 36 | ); -------------------------------------------------------------------------------- /test/Test.re: -------------------------------------------------------------------------------- 1 | module Main = Test__Main; 2 | module Parser = Test__Main; 3 | module Util = Test__Util; 4 | -------------------------------------------------------------------------------- /test/Test__Connection.re: -------------------------------------------------------------------------------- 1 | // open Rebase; 2 | open! BsMocha.Mocha; 3 | open! BsMocha.Promise; 4 | open Js.Promise; 5 | open! Test__Util; 6 | 7 | describe("Connection", () => 8 | describe("Path", () => { 9 | after_each(Package.after_each); 10 | it( 11 | "should success when trying to search for the path of program called 'agda'", 12 | () => { 13 | Atom.Config.set("agda-mode.agdaName", "agda") |> ignore; 14 | openAndLoad("Temp.agda") 15 | |> then_(_ => { 16 | Assert.ok(); 17 | resolve(); 18 | }); 19 | }); 20 | it( 21 | "should fail when trying to search for the path of program called 'non-agda'", 22 | () => { 23 | Atom.Config.set("agda-mode.agdaName", "non-agda") |> ignore; 24 | File.openAsset("Temp.agda") 25 | |> then_(getInstance) 26 | |> then_(instance => { 27 | let onConnectionError = 28 | instance.Instance__Type.onConnectionError.once() 29 | ->Promise.Js.toBsPromise; 30 | 31 | dispatch("agda-mode:load", instance) 32 | |> then_(_ => { 33 | Assert.fail("should fail on connection"); 34 | resolve(); 35 | }) 36 | |> ignore; 37 | 38 | onConnectionError 39 | |> then_(error => { 40 | open Connection.Error; 41 | switch (error) { 42 | | PathSearch(NotFound("non-agda", _)) => Assert.ok() 43 | | _ => Assert.fail("wrong connection error") 44 | }; 45 | resolve(); 46 | }); 47 | }); 48 | }); 49 | }) 50 | ); -------------------------------------------------------------------------------- /test/Test__Distribution.re: -------------------------------------------------------------------------------- 1 | open Rebase; 2 | open Fn; 3 | 4 | open! BsMocha.Mocha; 5 | open! BsMocha.Promise; 6 | open Js.Promise; 7 | open Test__Util; 8 | 9 | exception CannotReadPackageJson; 10 | 11 | // bindings for git-branch 12 | [@bs.module] 13 | external branch: unit => Js.Promise.t(Js.null(string)) = "git-branch"; 14 | 15 | let readFile = N.Fs.readFile |> N.Util.promisify; 16 | let readPackageJSONMain = () => { 17 | readFile(. "./package.json") 18 | |> then_( 19 | Node.Buffer.toString 20 | >> Js.Json.parseExn 21 | >> Js.Json.decodeObject 22 | >> Option.flatMap(obj => Js.Dict.get(obj, "main")) 23 | >> Option.flatMap(Js.Json.decodeString) 24 | >> Option.mapOr(resolve, reject(CannotReadPackageJson)), 25 | ); 26 | }; 27 | 28 | let onProd = callback => 29 | branch() 30 | |> then_(x => 31 | switch (Js.nullToOption(x)) { 32 | | Some("master") => callback() 33 | | _ => resolve(0) 34 | } 35 | ); 36 | 37 | let onDev = callback => 38 | branch() 39 | |> then_(x => 40 | switch (Js.nullToOption(x)) { 41 | | Some("master") => resolve(0) 42 | | _ => callback() 43 | } 44 | ); 45 | 46 | describe("Distribution", () => { 47 | describe("when on the master branch", () => { 48 | it("has the production bundle ready", () => 49 | onProd(() => 50 | make((~resolve, ~reject) => 51 | N.Fs.access(Path.file("lib/js/bundled.js"), err => 52 | switch (Js.nullToOption(err)) { 53 | | None => resolve(. 0) 54 | | Some(e) => reject(. N.Exception(e)) 55 | } 56 | ) 57 | ) 58 | ) 59 | ); 60 | 61 | it("should points to the production bundle", () => 62 | onProd(() => 63 | readPackageJSONMain() 64 | |> then_(path => { 65 | path |> Assert.equal("./lib/js/bundled.js"); 66 | resolve(0); 67 | }) 68 | ) 69 | ); 70 | }); 71 | 72 | describe("when on the development branch", () => 73 | it("should points to AgdaMode.bs", () => 74 | onDev(() => 75 | readPackageJSONMain() 76 | |> then_(path => { 77 | path |> Assert.equal("./lib/js/src/AgdaMode.bs"); 78 | resolve(0); 79 | }) 80 | ) 81 | ) 82 | ); 83 | }); 84 | -------------------------------------------------------------------------------- /test/Test__Main.re: -------------------------------------------------------------------------------- 1 | open! BsMocha.Mocha; 2 | open! BsMocha.Promise; 3 | open Js.Promise; 4 | 5 | open Test__Util; 6 | 7 | before(Package.activate); 8 | after(Package.deactivate); 9 | 10 | // describe("Package", () => { 11 | // it( 12 | // "should be activated after triggering 'agda-mode:load' on .agda files", () => { 13 | // // before 14 | // expect("agda-mode") 15 | // |> Modifiers.not 16 | // |> to_be_one_of(Package.activeNames()) 17 | // |> ignore; 18 | // 19 | // File.openAsset("Temp.agda") 20 | // |> then_(dispatch("agda-mode:load")) 21 | // |> then_(_ 22 | // // after 23 | // => 24 | // expect("agda-mode") 25 | // |> to_be_one_of(Package.activeNames()) 26 | // |> resolve 27 | // ); 28 | // }); 29 | // 30 | // it( 31 | // "should be activated after triggering 'agda-mode:load' on .lagda files", () => { 32 | // // before 33 | // expect("agda-mode") 34 | // |> Modifiers.not 35 | // |> to_be_one_of(Package.activeNames()) 36 | // |> ignore; 37 | // 38 | // File.openAsset("Blank2.lagda") 39 | // |> then_(dispatch("agda-mode:load")) 40 | // |> then_(_ 41 | // // after 42 | // => 43 | // expect("agda-mode") 44 | // |> to_be_one_of(Package.activeNames()) 45 | // |> resolve 46 | // ); 47 | // }); 48 | // }); 49 | 50 | describe("Instances", () => { 51 | it_skip("should have no instances before opening any files", () => 52 | AgdaMode.Instances.size() |> Assert.equal(0) |> resolve 53 | ); 54 | 55 | it("should respect the number of opened .agda file", () => 56 | File.openAsset("Temp.agda") 57 | |> then_(editor => { 58 | AgdaMode.Instances.size() |> Assert.equal(1); 59 | let pane = Atom.Workspace.getActivePane(); 60 | Atom.Pane.destroyItem_( 61 | Atom.TextEditor.asWorkspaceItem(editor), 62 | true, 63 | pane, 64 | ); 65 | }) 66 | |> then_(destroyed => { 67 | Assert.equal(AgdaMode.Instances.size(), destroyed ? 0 : 1); 68 | resolve(); 69 | }) 70 | ); 71 | 72 | it("should respect the number of opened .lagda file", () => 73 | File.openAsset("Blank2.lagda") 74 | |> then_(editor => { 75 | AgdaMode.Instances.size() |> Assert.equal(1); 76 | let pane = Atom.Workspace.getActivePane(); 77 | Atom.Pane.destroyItem_( 78 | Atom.TextEditor.asWorkspaceItem(editor), 79 | true, 80 | pane, 81 | ); 82 | }) 83 | |> then_(destroyed => { 84 | AgdaMode.Instances.size() |> Assert.equal(destroyed ? 0 : 1); 85 | resolve(); 86 | }) 87 | ); 88 | 89 | it("should include '.agda' in the classlist", () => 90 | File.openAsset("Temp.agda") 91 | |> then_(editor => { 92 | editor 93 | |> Atom.Views.getView 94 | |> Webapi.Dom.HtmlElement.classList 95 | |> Webapi.Dom.DomTokenList.contains("agda") 96 | |> Assert.yes; 97 | resolve(); 98 | }) 99 | ); 100 | }); 101 | -------------------------------------------------------------------------------- /test/Test__Misc.re: -------------------------------------------------------------------------------- 1 | open! BsMocha.Mocha; 2 | open! BsMocha.Promise; 3 | 4 | open Test__Util; 5 | 6 | // bindings for node-dir 7 | [@bs.module "node-dir"] 8 | external promiseFiles: string => Js.Promise.t(array(string)) = 9 | "promiseFiles"; 10 | 11 | describe_skip("when loading files", () => 12 | describe("when parsing responses from Agda", () => { 13 | let loadAndParse = path => { 14 | File.open_(path) 15 | |> Js.Promise.then_(editor => { 16 | let instance = Instance.make(editor); 17 | Connection.autoSearch("agda") 18 | ->Promise.flatMapOk(path => 19 | Connection.validateAndMake(path, [|" --no-libraries"|]) 20 | ) 21 | ->Promise.mapOk(Connection.connect) 22 | ->Promise.mapOk(Connection.wire) 23 | ->Promise.mapOk(Instance.Connections.persistConnection(instance)) 24 | ->Promise.mapError(error => BsMocha.Assert.fail(error)) 25 | ->Promise.flatMap(_ => 26 | TaskRunner.dispatchCommand(Command.Load, instance) 27 | ) 28 | // ->Promise.flatMapOk( 29 | // Instance.Handler.handleRequest(instance, (_, _) => 30 | // Promise.resolved(Rebase.Ok()) 31 | // ), 32 | // ) 33 | // ->Promise.mapOk(_ => Assert.ok()) 34 | // ->Promise.mapError(error => { 35 | // BsMocha.Assert.fail(error); 36 | // (); 37 | // }) 38 | ->Promise.Js.toBsPromise; 39 | }); 40 | }; 41 | 42 | it("should succeed", () => 43 | loadAndParse(Path.asset("Algebra.agda")) 44 | ); 45 | // promiseFiles("test/asset/agda-stdlib-1.0") 46 | // |> Js.Promise.then_(paths => 47 | // paths |> Array.slice(~from=0, ~to_=1) |> Js.Promise.resolve 48 | // ) 49 | // |> Js.Promise.then_(paths => 50 | // paths |> Array.map(loadAndParse) |> Js.Promise.all 51 | // ) 52 | }) 53 | ); -------------------------------------------------------------------------------- /test/asset/Blank1.agda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banacorn/agda-mode/878865c7220c49d93931198bcb8a4605c731fcb7/test/asset/Blank1.agda -------------------------------------------------------------------------------- /test/asset/Blank2.lagda: -------------------------------------------------------------------------------- 1 | module Blank where 2 | -------------------------------------------------------------------------------- /test/asset/Temp.agda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banacorn/agda-mode/878865c7220c49d93931198bcb8a4605c731fcb7/test/asset/Temp.agda -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | target: "electron-main", 5 | entry: './lib/js/src/AgdaMode.bs.js', 6 | devtool: 'source-map', 7 | output: { 8 | libraryTarget: 'commonjs', 9 | path: path.join(__dirname, 'lib/js/'), 10 | filename: 'bundled.js', 11 | }, 12 | target: 'node', 13 | externals: { 14 | atom: 'atom' 15 | } 16 | }; 17 | --------------------------------------------------------------------------------