├── tslint.json ├── .gitignore ├── .gitmodules ├── screencast.gif ├── keymaps └── keymap.cson ├── styles └── hint-panel.less ├── src ├── atom-config.d.ts ├── config.ts ├── opertator-regex.ts ├── last-suggestion-view.ts ├── autocomplete-haskell.ts └── suggestion-builder.ts ├── coffeelint.json ├── tsconfig.json ├── LICENSE.md ├── package.json ├── lib ├── config.js ├── opertator-regex.js ├── last-suggestion-view.js ├── autocomplete-haskell.js └── suggestion-builder.js ├── README.md └── CHANGELOG.md /tslint.json: -------------------------------------------------------------------------------- 1 | { "extends": "atom-haskell-tslint-rules" } 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | analyze* 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "typings"] 2 | path = typings 3 | url = git@github.com:atom-haskell/typings.git 4 | -------------------------------------------------------------------------------- /screencast.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atom-haskell-archive/autocomplete-haskell/HEAD/screencast.gif -------------------------------------------------------------------------------- /keymaps/keymap.cson: -------------------------------------------------------------------------------- 1 | 'atom-text-editor[data-grammar~="haskell"]': 2 | 'escape': 'autocomplete-haskell:conceal-hint-panel' 3 | -------------------------------------------------------------------------------- /styles/hint-panel.less: -------------------------------------------------------------------------------- 1 | autocomplete-haskell-hint { 2 | white-space: pre-wrap; 3 | margin: 0.1em 0.5em; 4 | min-height: 1.2em; 5 | display: block; 6 | } 7 | -------------------------------------------------------------------------------- /src/atom-config.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace AtomTypes { 2 | interface ConfigInterface { 3 | 'autocomplete-haskell.defaultHintPanelVisibility': 'Visible' | 'Hidden' 4 | 'autocomplete-haskell.hideHintPanelIfEmpty': boolean 5 | 'autocomplete-haskell.showIdeHaskellTooltip': boolean 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | export const config = { 2 | defaultHintPanelVisibility: { 3 | type: 'string', 4 | default: 'Visible', 5 | enum: ['Visible', 'Hidden'], 6 | }, 7 | hideHintPanelIfEmpty: { 8 | type: 'boolean', 9 | default: true, 10 | description: `\ 11 | Hide hint panel if it's empty. Also enables 'escape' key 12 | to hide it.\ 13 | `, 14 | }, 15 | showIdeHaskellTooltip: { 16 | type: 'boolean', 17 | default: false, 18 | description: `\ 19 | Show ide-haskell tooltip with last completion type\ 20 | `, 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /src/opertator-regex.ts: -------------------------------------------------------------------------------- 1 | import XRegExp = require('xregexp') 2 | // From language-haskell 3 | const identCharClass = `[\\p{Ll}_\\p{Lu}\\p{Lt}\\p{Nd}']` 4 | const classNameOne = `[\\p{Lu}\\p{Lt}]${identCharClass}*` 5 | const className = `${classNameOne}(?:\\.${classNameOne})*` 6 | const modulePrefix = `(?:${className}\\.)?` 7 | const operatorChar = '(?:(?![(),;\\[\\]`{}_"\'])[\\p{S}\\p{P}])' 8 | const operator = `${operatorChar}+` 9 | export const identRx = XRegExp(`(${modulePrefix})(${identCharClass}*)$`, 'u') 10 | export const operatorRx = XRegExp(`(${modulePrefix})(${operator})$`, 'u') 11 | -------------------------------------------------------------------------------- /coffeelint.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrow_spacing": { 3 | "name": "arrow_spacing", 4 | "level": "error" 5 | }, 6 | "ensure_comprehensions": { 7 | "name": "ensure_comprehensions", 8 | "level": "error" 9 | }, 10 | "max_line_length": { 11 | "name": "max_line_length", 12 | "value": 120, 13 | "level": "error", 14 | "limitComments": true 15 | }, 16 | "indentation": { 17 | "name": "indentation", 18 | "value": 2, 19 | "level": "error" 20 | }, 21 | "no_empty_param_list": { 22 | "name": "no_empty_param_list", 23 | "level": "error" 24 | }, 25 | "cyclomatic_complexity": { 26 | "name": "cyclomatic_complexity", 27 | "value": 22, 28 | "level": "error" 29 | }, 30 | "no_unnecessary_fat_arrows": { 31 | "name": "no_unnecessary_fat_arrows", 32 | "level": "error" 33 | }, 34 | "space_operators": { 35 | "name": "space_operators", 36 | "level": "error" 37 | }, 38 | "spacing_after_comma": { 39 | "name": "spacing_after_comma", 40 | "level": "error" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "isolatedModules": false, 7 | "jsx": "react", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "declaration": false, 11 | "noImplicitAny": true, 12 | "noImplicitUseStrict": false, 13 | "removeComments": true, 14 | "noLib": false, 15 | "jsxFactory": "etch.dom", 16 | "preserveConstEnums": true, 17 | "suppressImplicitAnyIndexErrors": true, 18 | "outDir": "lib", 19 | "inlineSources": true, 20 | "inlineSourceMap": true, 21 | "strictNullChecks": true, 22 | "allowJs": true, 23 | "lib":["dom","es2017"], 24 | "strict": true 25 | }, 26 | "exclude": [ 27 | "node_modules" 28 | ], 29 | "include": [ 30 | "src/**/*.ts", 31 | "src/**/*.tsx", 32 | "src/**/*.js", 33 | "typings/*.d.ts" 34 | ], 35 | "compileOnSave": true 36 | } 37 | -------------------------------------------------------------------------------- /src/last-suggestion-view.ts: -------------------------------------------------------------------------------- 1 | import { CompositeDisposable } from 'atom' 2 | import highlight = require('atom-highlight') 3 | 4 | export class LastSuggestionView { 5 | public element: HTMLElement 6 | private disposables: CompositeDisposable 7 | constructor(text: string = '') { 8 | this.element = document.createElement('div') 9 | this.disposables = new CompositeDisposable() 10 | this.disposables.add( 11 | atom.config.observe('editor.fontFamily', (val: string) => { 12 | this.element.style.fontFamily = val ? val : '' 13 | }), 14 | atom.config.observe('editor.fontSize', (val: number) => { 15 | this.element.style.fontSize = val ? `${val}px` : '' 16 | }), 17 | ) 18 | this.setText(text) 19 | } 20 | 21 | public destroy() { 22 | this.element.remove() 23 | } 24 | 25 | public setText(text: string) { 26 | this.element.innerHTML = highlight({ 27 | fileContents: text, 28 | scopeName: 'hint.haskell', 29 | nbsp: false, 30 | editorDiv: true, 31 | editorDivTag: 'autocomplete-haskell-hint', 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Atom-Haskell 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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "autocomplete-haskell", 3 | "main": "./lib/autocomplete-haskell", 4 | "version": "1.0.1", 5 | "description": "Autocomplete-plus provider for haskell", 6 | "keywords": [ 7 | "ide-haskell", 8 | "ide", 9 | "haskell", 10 | "autocomplete", 11 | "autocomplete-plus" 12 | ], 13 | "repository": "https://github.com/atom-haskell/autocomplete-haskell", 14 | "license": "MIT", 15 | "engines": { 16 | "atom": ">=1.19.0 <2.0.0" 17 | }, 18 | "activationHooks": [ 19 | "language-haskell:grammar-used" 20 | ], 21 | "dependencies": { 22 | "atom-highlight": "^0.3.0", 23 | "fuzzaldrin": "^2.1.0", 24 | "xregexp": "^3.2.0" 25 | }, 26 | "providedServices": { 27 | "autocomplete.provider": { 28 | "versions": { 29 | "2.0.0": "autocompleteProvider_2_0_0" 30 | } 31 | } 32 | }, 33 | "consumedServices": { 34 | "haskell-completion-backend": { 35 | "versions": { 36 | "0.1.0": "consumeCompBack", 37 | "^1.0.0": "consumeCompBack" 38 | } 39 | }, 40 | "ide-haskell-upi": { 41 | "description": "Uses ide-haskell's unified pluggable interface", 42 | "versions": { 43 | "^0.3.0": "consumeUPI" 44 | } 45 | } 46 | }, 47 | "devDependencies": { 48 | "@types/fuzzaldrin": "^2.1.0", 49 | "@types/xregexp": "^3.0.29", 50 | "atom-haskell-tslint-rules": "0.0.7", 51 | "atom-haskell-utils": "^1.0.0", 52 | "tslint": "^5.6.0", 53 | "typescript": "^2.4.2" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.config = { 4 | defaultHintPanelVisibility: { 5 | type: 'string', 6 | default: 'Visible', 7 | enum: ['Visible', 'Hidden'], 8 | }, 9 | hideHintPanelIfEmpty: { 10 | type: 'boolean', 11 | default: true, 12 | description: `\ 13 | Hide hint panel if it's empty. Also enables 'escape' key 14 | to hide it.\ 15 | `, 16 | }, 17 | showIdeHaskellTooltip: { 18 | type: 'boolean', 19 | default: false, 20 | description: `\ 21 | Show ide-haskell tooltip with last completion type\ 22 | `, 23 | }, 24 | }; 25 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFhLFFBQUEsTUFBTSxHQUFHO0lBQ3BCLDBCQUEwQixFQUFFO1FBQzFCLElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLFNBQVM7UUFDbEIsSUFBSSxFQUFFLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQztLQUM1QjtJQUNELG9CQUFvQixFQUFFO1FBQ3BCLElBQUksRUFBRSxTQUFTO1FBQ2YsT0FBTyxFQUFFLElBQUk7UUFDYixXQUFXLEVBQUU7OztDQUdoQjtLQUNFO0lBQ0QscUJBQXFCLEVBQUU7UUFDckIsSUFBSSxFQUFFLFNBQVM7UUFDZixPQUFPLEVBQUUsS0FBSztRQUNkLFdBQVcsRUFBRTs7Q0FFaEI7S0FDRTtDQUNGLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgY29uc3QgY29uZmlnID0ge1xuICBkZWZhdWx0SGludFBhbmVsVmlzaWJpbGl0eToge1xuICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgIGRlZmF1bHQ6ICdWaXNpYmxlJyxcbiAgICBlbnVtOiBbJ1Zpc2libGUnLCAnSGlkZGVuJ10sXG4gIH0sXG4gIGhpZGVIaW50UGFuZWxJZkVtcHR5OiB7XG4gICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgIGRlZmF1bHQ6IHRydWUsXG4gICAgZGVzY3JpcHRpb246IGBcXFxuSGlkZSBoaW50IHBhbmVsIGlmIGl0J3MgZW1wdHkuIEFsc28gZW5hYmxlcyAnZXNjYXBlJyBrZXlcbnRvIGhpZGUgaXQuXFxcbmAsXG4gIH0sXG4gIHNob3dJZGVIYXNrZWxsVG9vbHRpcDoge1xuICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICBkZWZhdWx0OiBmYWxzZSxcbiAgICBkZXNjcmlwdGlvbjogYFxcXG5TaG93IGlkZS1oYXNrZWxsIHRvb2x0aXAgd2l0aCBsYXN0IGNvbXBsZXRpb24gdHlwZVxcXG5gLFxuICB9LFxufVxuIl19 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # autocomplete-haskell atom package ![](https://david-dm.org/atom-haskell/autocomplete-haskell.svg) 2 | 3 | Autocomplete-haskell provides autocompletion facilities for your Haskell 4 | hacking. 5 | It relies on scope names provided by [language-haskell][1] and `haskell-completion-backend` service, provided by [haskell-ghc-mod][2] 6 | 7 | You can show auto-completions for hole `_`. This will try to find replacements 8 | based on type. It's no magic though, so if hole has some crazy type, it won't 9 | find anything. You can also refine hole completions based on name by using named holes, e.g. `_from` 10 | 11 | Current autocompletion scopes: 12 | 13 | * Import module name 14 | * Import module symbols 15 | * Language pragmas 16 | * OPTIONS_GHC pragma 17 | * Type name 18 | * Class name 19 | * Symbol name 20 | 21 | Sadly, it does not pick up types and/or other symbols defined in current file 22 | (ghc-mod seems to be incapable of this feat), so for this you have to rely on 23 | default autocomplete-plus SymbolProvider. 24 | 25 | ## Dependencies 26 | 27 | Atom packages: 28 | 29 | * [language-haskell][1] 30 | * [haskell-ghc-mod][2] 31 | 32 | [1]: https://atom.io/packages/language-haskell 33 | [2]: https://atom.io/packages/haskell-ghc-mod 34 | 35 | Autocompletion: 36 | 37 | ![autocomplete](https://cloud.githubusercontent.com/assets/7275622/9704861/e4474ec4-54bc-11e5-92f4-84a3995e45cb.gif) 38 | 39 | Import autocompletion: 40 | 41 | ![import](https://cloud.githubusercontent.com/assets/7275622/9704865/ff39f79a-54bc-11e5-9912-5fb2884b749b.gif) 42 | 43 | Hole autocompletion: 44 | 45 | ![hole](https://cloud.githubusercontent.com/assets/7275622/9704890/5581ccae-54bd-11e5-8ec6-8aa289e5a099.gif) 46 | 47 | # License 48 | 49 | Copyright © 2015 Atom-Haskell 50 | 51 | Contributors (by number of commits): 52 | 53 | 54 | * Nikolay Yakimov 55 | 56 | 57 | 58 | See the [LICENSE.md][LICENSE] for details. 59 | 60 | [LICENSE]: https://github.com/atom-haskell/autocomplete-haskell/blob/master/LICENSE.md 61 | -------------------------------------------------------------------------------- /lib/opertator-regex.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const XRegExp = require("xregexp"); 4 | const identCharClass = `[\\p{Ll}_\\p{Lu}\\p{Lt}\\p{Nd}']`; 5 | const classNameOne = `[\\p{Lu}\\p{Lt}]${identCharClass}*`; 6 | const className = `${classNameOne}(?:\\.${classNameOne})*`; 7 | const modulePrefix = `(?:${className}\\.)?`; 8 | const operatorChar = '(?:(?![(),;\\[\\]`{}_"\'])[\\p{S}\\p{P}])'; 9 | const operator = `${operatorChar}+`; 10 | exports.identRx = XRegExp(`(${modulePrefix})(${identCharClass}*)$`, 'u'); 11 | exports.operatorRx = XRegExp(`(${modulePrefix})(${operator})$`, 'u'); 12 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlcnRhdG9yLXJlZ2V4LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL29wZXJ0YXRvci1yZWdleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUFtQztBQUVuQyxNQUFNLGNBQWMsR0FBRyxrQ0FBa0MsQ0FBQTtBQUN6RCxNQUFNLFlBQVksR0FBRyxtQkFBbUIsY0FBYyxHQUFHLENBQUE7QUFDekQsTUFBTSxTQUFTLEdBQUcsR0FBRyxZQUFZLFNBQVMsWUFBWSxJQUFJLENBQUE7QUFDMUQsTUFBTSxZQUFZLEdBQUcsTUFBTSxTQUFTLE9BQU8sQ0FBQTtBQUMzQyxNQUFNLFlBQVksR0FBRywyQ0FBMkMsQ0FBQTtBQUNoRSxNQUFNLFFBQVEsR0FBRyxHQUFHLFlBQVksR0FBRyxDQUFBO0FBQ3RCLFFBQUEsT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLFlBQVksS0FBSyxjQUFjLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQTtBQUNoRSxRQUFBLFVBQVUsR0FBRyxPQUFPLENBQUMsSUFBSSxZQUFZLEtBQUssUUFBUSxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgWFJlZ0V4cCA9IHJlcXVpcmUoJ3hyZWdleHAnKVxuLy8gRnJvbSBsYW5ndWFnZS1oYXNrZWxsXG5jb25zdCBpZGVudENoYXJDbGFzcyA9IGBbXFxcXHB7TGx9X1xcXFxwe0x1fVxcXFxwe0x0fVxcXFxwe05kfSddYFxuY29uc3QgY2xhc3NOYW1lT25lID0gYFtcXFxccHtMdX1cXFxccHtMdH1dJHtpZGVudENoYXJDbGFzc30qYFxuY29uc3QgY2xhc3NOYW1lID0gYCR7Y2xhc3NOYW1lT25lfSg/OlxcXFwuJHtjbGFzc05hbWVPbmV9KSpgXG5jb25zdCBtb2R1bGVQcmVmaXggPSBgKD86JHtjbGFzc05hbWV9XFxcXC4pP2BcbmNvbnN0IG9wZXJhdG9yQ2hhciA9ICcoPzooPyFbKCksO1xcXFxbXFxcXF1ge31fXCJcXCddKVtcXFxccHtTfVxcXFxwe1B9XSknXG5jb25zdCBvcGVyYXRvciA9IGAke29wZXJhdG9yQ2hhcn0rYFxuZXhwb3J0IGNvbnN0IGlkZW50UnggPSBYUmVnRXhwKGAoJHttb2R1bGVQcmVmaXh9KSgke2lkZW50Q2hhckNsYXNzfSopJGAsICd1JylcbmV4cG9ydCBjb25zdCBvcGVyYXRvclJ4ID0gWFJlZ0V4cChgKCR7bW9kdWxlUHJlZml4fSkoJHtvcGVyYXRvcn0pJGAsICd1JylcbiJdfQ== -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.1 2 | * Unicode identifiers and operators properly supported via XRegExp 3 | * Parenthesized operators omitted from operator suggestions 4 | 5 | ## 1.0.0 6 | * Suggest operators in completions 7 | * Hide hint panel by default 8 | * Optionally show completion hint as ide-haskell tooltips 9 | * Cleanup & minor fixes 10 | * Rewrite in TypeScript 11 | * Migrate to UPI 0.3 12 | 13 | ## 0.7.2 14 | * Use atom-highlight for completion hint panel 15 | 16 | ## 0.7.1 17 | * Fix keybinding deactivation 18 | 19 | ## 0.7.0 20 | * hideHintPanelIfEmpty, remove old workarounds 21 | * Atom version bump 22 | * Fix LICENSE date 23 | * Update LICENSE 24 | 25 | ## 0.6.7 26 | * Add option for default hint panel visibility 27 | 28 | ## 0.6.6 29 | * Support instance overlap pragmas 30 | 31 | ## 0.6.5 32 | * Fix preprocessorSuggestions 33 | 34 | ## 0.6.4 35 | * Updates for ac-p 2.25 and bugfixes 36 | * 'ingoreMinimumWordLengthForHoleCompletions' option to control hole completions on keystroke. 37 | 38 | ## 0.6.3 39 | * Match type scope on meta.type-signature.haskell 40 | * Add package keywords 41 | 42 | ## 0.6.2 43 | * Delayed hint panel grammar setting, use hint grammar 44 | 45 | ## 0.6.1 46 | * Activate autocomplete-haskell only on Haskell files 47 | 48 | ## 0.6.0 49 | * Add a panel with last completion hint (https://github.com/atom-haskell/ide-haskell/issues/99) 50 | 51 | ## 0.5.1 52 | * Screencasts update 53 | 54 | ## 0.5.0 55 | * Allow for hole completion refinement 56 | 57 | ## 0.4.5 58 | * Support for haskell-ghc-mod 0.8.0 59 | 60 | ## 0.4.4 61 | * Bail on completion if no backend 62 | 63 | ## 0.4.3 64 | * Deactivation fix 65 | 66 | ## 0.4.2 67 | * Set inclusionPriority=0 68 | 69 | ## 0.4.1 70 | * atom-backend-helper version bump 71 | 72 | ## 0.4.0 73 | * Use haskell-completion-backend service 74 | * Add message on multiple backends and none selected 75 | * Possible undefined symbol module 76 | * Remove dep on underscore-plus 77 | * Specify atom version according to docs 78 | * Specify package versions 79 | * Add info on haskell-completion-backend service 80 | * Use fuzzaldrin 81 | * Added pragma words, general overhaul 82 | * Cleanup, array scopes, support for exportsScope 83 | 84 | ## 0.3.1 85 | * Fix deprecated ac+ blacklist option 86 | 87 | ## 0.3.0 88 | * Updated to work with newest haskell-ghc-mod 89 | * Hole completions no longer depend on Hoogle 90 | * Autocomplete+ API 2.0 91 | * Changed EditorController to BufferController 92 | 93 | ## 0.2.1 94 | * BUGFIX: activation problems 95 | 96 | ## 0.2.0 97 | * Migrate to new json-based service provider 98 | * Move out provider code to sep. file 99 | * Bump atom version 100 | 101 | ## 0.1.2 102 | * Fix typo 103 | * A little refactoring 104 | 105 | ## 0.1.1 106 | * Use atom.services.consume once and pass reference around 107 | 108 | ## 0.1.0 - First Release 109 | * Initial release 110 | -------------------------------------------------------------------------------- /lib/last-suggestion-view.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const atom_1 = require("atom"); 4 | const highlight = require("atom-highlight"); 5 | class LastSuggestionView { 6 | constructor(text = '') { 7 | this.element = document.createElement('div'); 8 | this.disposables = new atom_1.CompositeDisposable(); 9 | this.disposables.add(atom.config.observe('editor.fontFamily', (val) => { 10 | this.element.style.fontFamily = val ? val : ''; 11 | }), atom.config.observe('editor.fontSize', (val) => { 12 | this.element.style.fontSize = val ? `${val}px` : ''; 13 | })); 14 | this.setText(text); 15 | } 16 | destroy() { 17 | this.element.remove(); 18 | } 19 | setText(text) { 20 | this.element.innerHTML = highlight({ 21 | fileContents: text, 22 | scopeName: 'hint.haskell', 23 | nbsp: false, 24 | editorDiv: true, 25 | editorDivTag: 'autocomplete-haskell-hint', 26 | }); 27 | } 28 | } 29 | exports.LastSuggestionView = LastSuggestionView; 30 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGFzdC1zdWdnZXN0aW9uLXZpZXcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbGFzdC1zdWdnZXN0aW9uLXZpZXcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwrQkFBMEM7QUFDMUMsNENBQTRDO0FBRTVDO0lBR0UsWUFBWSxPQUFlLEVBQUU7UUFDM0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBQzVDLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSwwQkFBbUIsRUFBRSxDQUFBO1FBQzVDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUNsQixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLEdBQVcsRUFBRSxFQUFFO1lBQ3ZELElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFBO1FBQ2hELENBQUMsQ0FBQyxFQUNGLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLGlCQUFpQixFQUFFLENBQUMsR0FBVyxFQUFFLEVBQUU7WUFDckQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsUUFBUSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFBO1FBQ3JELENBQUMsQ0FBQyxDQUNILENBQUE7UUFDRCxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFBO0lBQ3BCLENBQUM7SUFFTSxPQUFPO1FBQ1osSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQTtJQUN2QixDQUFDO0lBRU0sT0FBTyxDQUFDLElBQVk7UUFDekIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1lBQ2pDLFlBQVksRUFBRSxJQUFJO1lBQ2xCLFNBQVMsRUFBRSxjQUFjO1lBQ3pCLElBQUksRUFBRSxLQUFLO1lBQ1gsU0FBUyxFQUFFLElBQUk7WUFDZixZQUFZLEVBQUUsMkJBQTJCO1NBQzFDLENBQUMsQ0FBQTtJQUNKLENBQUM7Q0FDRjtBQTlCRCxnREE4QkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb3NpdGVEaXNwb3NhYmxlIH0gZnJvbSAnYXRvbSdcbmltcG9ydCBoaWdobGlnaHQgPSByZXF1aXJlKCdhdG9tLWhpZ2hsaWdodCcpXG5cbmV4cG9ydCBjbGFzcyBMYXN0U3VnZ2VzdGlvblZpZXcge1xuICBwdWJsaWMgZWxlbWVudDogSFRNTEVsZW1lbnRcbiAgcHJpdmF0ZSBkaXNwb3NhYmxlczogQ29tcG9zaXRlRGlzcG9zYWJsZVxuICBjb25zdHJ1Y3Rvcih0ZXh0OiBzdHJpbmcgPSAnJykge1xuICAgIHRoaXMuZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpXG4gICAgdGhpcy5kaXNwb3NhYmxlcyA9IG5ldyBDb21wb3NpdGVEaXNwb3NhYmxlKClcbiAgICB0aGlzLmRpc3Bvc2FibGVzLmFkZChcbiAgICAgIGF0b20uY29uZmlnLm9ic2VydmUoJ2VkaXRvci5mb250RmFtaWx5JywgKHZhbDogc3RyaW5nKSA9PiB7XG4gICAgICAgIHRoaXMuZWxlbWVudC5zdHlsZS5mb250RmFtaWx5ID0gdmFsID8gdmFsIDogJydcbiAgICAgIH0pLFxuICAgICAgYXRvbS5jb25maWcub2JzZXJ2ZSgnZWRpdG9yLmZvbnRTaXplJywgKHZhbDogbnVtYmVyKSA9PiB7XG4gICAgICAgIHRoaXMuZWxlbWVudC5zdHlsZS5mb250U2l6ZSA9IHZhbCA/IGAke3ZhbH1weGAgOiAnJ1xuICAgICAgfSksXG4gICAgKVxuICAgIHRoaXMuc2V0VGV4dCh0ZXh0KVxuICB9XG5cbiAgcHVibGljIGRlc3Ryb3koKSB7XG4gICAgdGhpcy5lbGVtZW50LnJlbW92ZSgpXG4gIH1cblxuICBwdWJsaWMgc2V0VGV4dCh0ZXh0OiBzdHJpbmcpIHtcbiAgICB0aGlzLmVsZW1lbnQuaW5uZXJIVE1MID0gaGlnaGxpZ2h0KHtcbiAgICAgIGZpbGVDb250ZW50czogdGV4dCxcbiAgICAgIHNjb3BlTmFtZTogJ2hpbnQuaGFza2VsbCcsXG4gICAgICBuYnNwOiBmYWxzZSxcbiAgICAgIGVkaXRvckRpdjogdHJ1ZSxcbiAgICAgIGVkaXRvckRpdlRhZzogJ2F1dG9jb21wbGV0ZS1oYXNrZWxsLWhpbnQnLFxuICAgIH0pXG4gIH1cbn1cbiJdfQ== -------------------------------------------------------------------------------- /src/autocomplete-haskell.ts: -------------------------------------------------------------------------------- 1 | import { IEventDesc, CompositeDisposable, Disposable } from 'atom' 2 | import { SuggestionBuilder, IOptions, ISuggestion } from './suggestion-builder' 3 | import { LastSuggestionView } from './last-suggestion-view' 4 | 5 | let backend: UPI.CompletionBackend.ICompletionBackend | undefined 6 | let disposables: CompositeDisposable | undefined 7 | let panel: AtomTypes.Panel | undefined 8 | let upi: UPI.IUPIInstance | undefined 9 | let lastCompletionDesc: string | undefined 10 | 11 | interface IState { 12 | panelVisible?: boolean 13 | lastCompletionDesc: string | undefined 14 | } 15 | 16 | interface IACPDidInsertEventParams { 17 | editor: AtomTypes.TextEditor 18 | triggerPosition: AtomTypes.Point 19 | suggestion: ISuggestion 20 | } 21 | 22 | export { config } from './config' 23 | 24 | export function activate(state: IState) { 25 | disposables = new CompositeDisposable() 26 | 27 | if (state.panelVisible === undefined) { 28 | state.panelVisible = (atom.config.get('autocomplete-haskell.defaultHintPanelVisibility') === 'Visible') 29 | } 30 | 31 | lastCompletionDesc = state.lastCompletionDesc 32 | 33 | if (state.panelVisible) { 34 | createPanel() 35 | } 36 | 37 | disposables.add(atom.config.observe('autocomplete-haskell.hideHintPanelIfEmpty', (val) => { 38 | if (panel) { 39 | !val || lastCompletionDesc ? panel.show() : panel.hide() 40 | } 41 | })) 42 | 43 | disposables.add( 44 | atom.commands.add('atom-text-editor[data-grammar~="haskell"]', { 45 | 'autocomplete-haskell:conceal-hint-panel': ({ currentTarget, abortKeyBinding }: IEventDesc) => { 46 | if (panel && panel.isVisible() && atom.config.get('autocomplete-haskell.hideHintPanelIfEmpty')) { 47 | panel.hide() 48 | } else { 49 | if (typeof abortKeyBinding === 'function') { 50 | abortKeyBinding() 51 | } 52 | } 53 | }, 54 | }, 55 | ), 56 | ) 57 | 58 | disposables.add(atom.commands.add('atom-workspace', { 59 | 'autocomplete-haskell:toggle-completion-hint': () => { 60 | if (panel) { 61 | destroyPanel() 62 | } else { 63 | createPanel() 64 | } 65 | }, 66 | }, 67 | ), 68 | ) 69 | 70 | disposables.add(atom.menu.add([{ 71 | label: 'Haskell IDE', 72 | submenu: [{ 73 | label: 'Toggle Completion Hint Panel', 74 | command: 'autocomplete-haskell:toggle-completion-hint', 75 | }], 76 | }])) 77 | } 78 | 79 | export function serialize(): IState { 80 | return { 81 | panelVisible: !!panel, 82 | lastCompletionDesc, 83 | } 84 | } 85 | 86 | export function deactivate() { 87 | disposables && disposables.dispose() 88 | disposables = undefined 89 | upi = undefined 90 | destroyPanel() 91 | } 92 | 93 | function createPanel() { 94 | panel = atom.workspace.addBottomPanel({ 95 | item: new LastSuggestionView(lastCompletionDesc), 96 | visible: true, 97 | priority: 200, 98 | }) 99 | } 100 | 101 | function destroyPanel() { 102 | panel && panel.destroy() 103 | panel = undefined 104 | } 105 | 106 | export function autocompleteProvider_2_0_0() { 107 | return { 108 | selector: '.source.haskell', 109 | disableForSelector: '.source.haskell .comment', 110 | inclusionPriority: 0, 111 | getSuggestions: (options: IOptions) => { 112 | if (!backend) { return [] } 113 | return (new SuggestionBuilder(options, backend)).getSuggestions() 114 | }, 115 | onDidInsertSuggestion: ({ editor, triggerPosition, suggestion }: IACPDidInsertEventParams) => { 116 | if (suggestion && suggestion.description) { 117 | const desc = lastCompletionDesc = suggestion.description 118 | if (panel) { 119 | const view: LastSuggestionView = panel.getItem() 120 | view.setText(desc) 121 | if (atom.config.get('autocomplete-haskell.hideHintPanelIfEmpty')) { 122 | panel.show() 123 | } 124 | } 125 | if (upi && atom.config.get('autocomplete-haskell.showIdeHaskellTooltip')) { 126 | const p2 = editor.getLastCursor().getBufferPosition() 127 | const p1 = p2.translate([0, -suggestion.text.length]) 128 | setImmediate(() => { 129 | upi && upi.showTooltip({ 130 | editor, 131 | eventType: UPI.TEventRangeType.keyboard, 132 | tooltip: { 133 | range: [p1, p2], 134 | persistent: true, 135 | text: { 136 | text: desc, 137 | highlighter: 'hint.haskell', 138 | }, 139 | }, 140 | }) 141 | }) 142 | } 143 | } else if (panel) { 144 | const view: LastSuggestionView = panel.getItem() 145 | view.setText('') 146 | if (panel && atom.config.get('autocomplete-haskell.hideHintPanelIfEmpty')) { 147 | panel.hide() 148 | } 149 | } 150 | }, 151 | } 152 | } 153 | 154 | export function consumeUPI(service: UPI.IUPIRegistration) { 155 | upi = service({ 156 | name: 'autocomplete-haskell', 157 | }) 158 | disposables && disposables.add(upi) 159 | return upi 160 | } 161 | 162 | export function consumeCompBack(service: UPI.CompletionBackend.ICompletionBackend) { 163 | backend = service 164 | const mydisp = new CompositeDisposable() 165 | disposables && disposables.add(mydisp) 166 | mydisp.add( 167 | atom.workspace.observeTextEditors((editor) => { 168 | if (editor.getGrammar().scopeName === 'source.haskell') { 169 | mydisp.add(service.registerCompletionBuffer(editor.getBuffer())) 170 | } 171 | }), 172 | new Disposable(() => { 173 | backend = undefined 174 | disposables && disposables.remove(mydisp) 175 | }), 176 | ) 177 | return mydisp 178 | } 179 | -------------------------------------------------------------------------------- /src/suggestion-builder.ts: -------------------------------------------------------------------------------- 1 | import { Range } from 'atom' 2 | import { filter } from 'fuzzaldrin' 3 | import CB = UPI.CompletionBackend 4 | 5 | const typeScope = ['meta.type-signature.haskell'] 6 | const sourceScope = ['source.haskell'] 7 | const moduleScope = ['meta.import.haskell', 'support.other.module.haskell'] 8 | const preprocessorScope = ['meta.preprocessor.haskell'] 9 | const instancePreprocessorScope = ['meta.declaration.instance.haskell', 'meta.preprocessor.haskell'] 10 | const exportsScope = ['meta.import.haskell', 'meta.declaration.exports.haskell'] 11 | 12 | const pragmaWords = [ 13 | 'LANGUAGE', 'OPTIONS_GHC', 'INCLUDE', 'WARNING', 'DEPRECATED', 'INLINE', 14 | 'NOINLINE', 'ANN', 'LINE', 'RULES', 'SPECIALIZE', 'UNPACK', 'SOURCE', 15 | ] 16 | 17 | const instancePragmaWords = [ 18 | 'INCOHERENT', 19 | 'OVERLAPPABLE', 20 | 'OVERLAPPING', 21 | 'OVERLAPS', 22 | ] 23 | 24 | import { operatorRx, identRx } from './opertator-regex' 25 | 26 | export interface IOptions { 27 | editor: AtomTypes.TextEditor 28 | bufferPosition: AtomTypes.Point 29 | activatedManually: boolean 30 | scopeDescriptor: AtomTypes.ScopeDescriptor 31 | } 32 | 33 | export interface ISuggestion { 34 | text: string 35 | rightLabel?: string 36 | type: CB.SymbolType | 'import' | 'keyword' 37 | replacementPrefix: string 38 | description?: string 39 | } 40 | 41 | type GetSymbolsCallback = (buffer: AtomTypes.TextBuffer, prefix: string, position: AtomTypes.Point) => Promise 42 | 43 | export class SuggestionBuilder { 44 | private buffer: AtomTypes.TextBuffer 45 | private lineRange: AtomTypes.Range 46 | private line: string 47 | private mwl: number 48 | constructor(private options: IOptions, private backend: CB.ICompletionBackend) { 49 | this.buffer = this.options.editor.getBuffer() 50 | this.lineRange = new Range( 51 | [this.options.bufferPosition.row, 0], 52 | this.options.bufferPosition, 53 | ) 54 | this.line = this.buffer.getTextInRange(this.lineRange) 55 | this.mwl = 56 | this.options.activatedManually ? 57 | 0 58 | : 59 | atom.config.get('autocomplete-plus.minimumWordLength') 60 | } 61 | 62 | public async getSuggestions(): Promise { 63 | if (this.isIn(instancePreprocessorScope)) { 64 | return this.preprocessorSuggestions(instancePragmaWords) 65 | } else if (this.isIn(typeScope)) { 66 | return this.symbolSuggestions(this.backend.getCompletionsForType.bind(this.backend)) 67 | } else if (this.isIn(moduleScope)) { 68 | return this.moduleSuggestions() 69 | } else if (this.isIn(exportsScope)) { 70 | return this.symbolSuggestions(this.backend.getCompletionsForSymbolInModule.bind(this.backend)) 71 | } else if (this.isIn(preprocessorScope)) { 72 | return this.preprocessorSuggestions(pragmaWords) 73 | // should be last as least sepcialized 74 | } else if (this.isIn(sourceScope)) { 75 | if (this.getPrefix().startsWith('_')) { 76 | return this.symbolSuggestions(this.backend.getCompletionsForHole.bind(this.backend)) 77 | } else if (this.getPrefix() === '' && this.getPrefix(operatorRx) !== '') { 78 | return this.operatorSuggestions() 79 | } else { 80 | return this.symbolSuggestions(this.backend.getCompletionsForSymbol.bind(this.backend)) 81 | } 82 | } else { 83 | return [] 84 | } 85 | } 86 | 87 | private lineSearch(rx: RegExp, idx: number = 0) { 88 | const match = this.line.match(rx) 89 | if (match) { 90 | return match 91 | } else { 92 | return [''] 93 | } 94 | } 95 | 96 | private isIn(scope: string[]) { 97 | return scope.every((s1) => this.options.scopeDescriptor.getScopesArray().includes(s1)) 98 | } 99 | 100 | private getPrefix(rx?: RegExp) { 101 | if (!rx) { rx = identRx } 102 | return this.lineSearch(rx)[0] 103 | } 104 | 105 | private buildSymbolSuggestion(s: CB.ISymbol, prefix: string): ISuggestion { 106 | return { 107 | text: s.qname ? s.qname : s.name, 108 | rightLabel: (s.module ? s.module.name : undefined), 109 | type: s.symbolType, 110 | replacementPrefix: prefix, 111 | description: this.nameFix(s) + ' :: ' + s.typeSignature, 112 | } 113 | } 114 | 115 | private nameFix(s: CB.ISymbol) { 116 | if (s.symbolType === 'operator') { 117 | return `(${s.name})` 118 | } else { 119 | return s.name 120 | } 121 | } 122 | 123 | private buildSimpleSuggestion( 124 | type: 'import' | 'keyword', text: string, prefix: string, label?: string, 125 | ): ISuggestion { 126 | return { 127 | text, 128 | type, 129 | replacementPrefix: prefix, 130 | rightLabel: label, 131 | } 132 | } 133 | 134 | private async processSuggestions( 135 | f: GetSymbolsCallback, rx: RegExp | undefined, p: (s: T, p: string) => ISuggestion, 136 | ) { 137 | const prefix = this.getPrefix(rx) 138 | if (prefix.length < this.mwl) { 139 | return [] 140 | } 141 | const symbols = await f(this.buffer, prefix, this.options.bufferPosition) 142 | return symbols.map((s) => p(s, prefix)) 143 | } 144 | 145 | private async symbolSuggestions(f: GetSymbolsCallback, rx?: RegExp) { 146 | return this.processSuggestions(f, rx, this.buildSymbolSuggestion.bind(this)) 147 | } 148 | 149 | private async moduleSuggestions() { 150 | return this.processSuggestions(this.backend.getCompletionsForModule.bind(this.backend), undefined, (s, prefix) => 151 | this.buildSimpleSuggestion('import', s, prefix)) 152 | } 153 | 154 | private preprocessorSuggestions(pragmaList: string[]) { 155 | let f: GetSymbolsCallback 156 | const kwrx = new RegExp(`\\b(${pragmaList.join('|')})\\b`) 157 | const kw = this.lineSearch(kwrx)[0] 158 | let label = '' 159 | let rx 160 | switch (false) { 161 | case kw !== 'OPTIONS_GHC': 162 | rx = /[\w-]+$/ 163 | label = 'GHC Flag' 164 | f = this.backend.getCompletionsForCompilerOptions 165 | break 166 | case kw !== 'LANGUAGE': 167 | label = 'Language' 168 | f = this.backend.getCompletionsForLanguagePragmas 169 | break 170 | case !!kw: 171 | label = 'Pragma' 172 | f = async (b, p) => filter(pragmaList, p) 173 | break 174 | default: 175 | return [] 176 | } 177 | 178 | return this.processSuggestions(f, rx, (s, prefix) => 179 | this.buildSimpleSuggestion('keyword', s, prefix, label)) 180 | } 181 | 182 | private async operatorSuggestions() { 183 | const prefixMatch = this.lineSearch(operatorRx) 184 | if (!prefixMatch) { return [] } 185 | const [mod, op] = prefixMatch.slice(1) 186 | if (prefixMatch[0].length < this.mwl) { 187 | return [] 188 | } 189 | const symbols = 190 | await this.backend.getCompletionsForSymbol(this.buffer, `${mod || ''}${op}`, this.options.bufferPosition) 191 | const newSyms = 192 | symbols 193 | .filter(({ symbolType }) => symbolType === 'operator') 194 | const allSyms = filter(newSyms, prefixMatch[0], { key: 'qname' }) 195 | return allSyms.map((s) => this.buildSymbolSuggestion(s, prefixMatch[0])) 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /lib/autocomplete-haskell.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const atom_1 = require("atom"); 4 | const suggestion_builder_1 = require("./suggestion-builder"); 5 | const last_suggestion_view_1 = require("./last-suggestion-view"); 6 | let backend; 7 | let disposables; 8 | let panel; 9 | let upi; 10 | let lastCompletionDesc; 11 | var config_1 = require("./config"); 12 | exports.config = config_1.config; 13 | function activate(state) { 14 | disposables = new atom_1.CompositeDisposable(); 15 | if (state.panelVisible === undefined) { 16 | state.panelVisible = (atom.config.get('autocomplete-haskell.defaultHintPanelVisibility') === 'Visible'); 17 | } 18 | lastCompletionDesc = state.lastCompletionDesc; 19 | if (state.panelVisible) { 20 | createPanel(); 21 | } 22 | disposables.add(atom.config.observe('autocomplete-haskell.hideHintPanelIfEmpty', (val) => { 23 | if (panel) { 24 | !val || lastCompletionDesc ? panel.show() : panel.hide(); 25 | } 26 | })); 27 | disposables.add(atom.commands.add('atom-text-editor[data-grammar~="haskell"]', { 28 | 'autocomplete-haskell:conceal-hint-panel': ({ currentTarget, abortKeyBinding }) => { 29 | if (panel && panel.isVisible() && atom.config.get('autocomplete-haskell.hideHintPanelIfEmpty')) { 30 | panel.hide(); 31 | } 32 | else { 33 | if (typeof abortKeyBinding === 'function') { 34 | abortKeyBinding(); 35 | } 36 | } 37 | }, 38 | })); 39 | disposables.add(atom.commands.add('atom-workspace', { 40 | 'autocomplete-haskell:toggle-completion-hint': () => { 41 | if (panel) { 42 | destroyPanel(); 43 | } 44 | else { 45 | createPanel(); 46 | } 47 | }, 48 | })); 49 | disposables.add(atom.menu.add([{ 50 | label: 'Haskell IDE', 51 | submenu: [{ 52 | label: 'Toggle Completion Hint Panel', 53 | command: 'autocomplete-haskell:toggle-completion-hint', 54 | }], 55 | }])); 56 | } 57 | exports.activate = activate; 58 | function serialize() { 59 | return { 60 | panelVisible: !!panel, 61 | lastCompletionDesc, 62 | }; 63 | } 64 | exports.serialize = serialize; 65 | function deactivate() { 66 | disposables && disposables.dispose(); 67 | disposables = undefined; 68 | upi = undefined; 69 | destroyPanel(); 70 | } 71 | exports.deactivate = deactivate; 72 | function createPanel() { 73 | panel = atom.workspace.addBottomPanel({ 74 | item: new last_suggestion_view_1.LastSuggestionView(lastCompletionDesc), 75 | visible: true, 76 | priority: 200, 77 | }); 78 | } 79 | function destroyPanel() { 80 | panel && panel.destroy(); 81 | panel = undefined; 82 | } 83 | function autocompleteProvider_2_0_0() { 84 | return { 85 | selector: '.source.haskell', 86 | disableForSelector: '.source.haskell .comment', 87 | inclusionPriority: 0, 88 | getSuggestions: (options) => { 89 | if (!backend) { 90 | return []; 91 | } 92 | return (new suggestion_builder_1.SuggestionBuilder(options, backend)).getSuggestions(); 93 | }, 94 | onDidInsertSuggestion: ({ editor, triggerPosition, suggestion }) => { 95 | if (suggestion && suggestion.description) { 96 | const desc = lastCompletionDesc = suggestion.description; 97 | if (panel) { 98 | const view = panel.getItem(); 99 | view.setText(desc); 100 | if (atom.config.get('autocomplete-haskell.hideHintPanelIfEmpty')) { 101 | panel.show(); 102 | } 103 | } 104 | if (upi && atom.config.get('autocomplete-haskell.showIdeHaskellTooltip')) { 105 | const p2 = editor.getLastCursor().getBufferPosition(); 106 | const p1 = p2.translate([0, -suggestion.text.length]); 107 | setImmediate(() => { 108 | upi && upi.showTooltip({ 109 | editor, 110 | eventType: "keyboard", 111 | tooltip: { 112 | range: [p1, p2], 113 | persistent: true, 114 | text: { 115 | text: desc, 116 | highlighter: 'hint.haskell', 117 | }, 118 | }, 119 | }); 120 | }); 121 | } 122 | } 123 | else if (panel) { 124 | const view = panel.getItem(); 125 | view.setText(''); 126 | if (panel && atom.config.get('autocomplete-haskell.hideHintPanelIfEmpty')) { 127 | panel.hide(); 128 | } 129 | } 130 | }, 131 | }; 132 | } 133 | exports.autocompleteProvider_2_0_0 = autocompleteProvider_2_0_0; 134 | function consumeUPI(service) { 135 | upi = service({ 136 | name: 'autocomplete-haskell', 137 | }); 138 | disposables && disposables.add(upi); 139 | return upi; 140 | } 141 | exports.consumeUPI = consumeUPI; 142 | function consumeCompBack(service) { 143 | backend = service; 144 | const mydisp = new atom_1.CompositeDisposable(); 145 | disposables && disposables.add(mydisp); 146 | mydisp.add(atom.workspace.observeTextEditors((editor) => { 147 | if (editor.getGrammar().scopeName === 'source.haskell') { 148 | mydisp.add(service.registerCompletionBuffer(editor.getBuffer())); 149 | } 150 | }), new atom_1.Disposable(() => { 151 | backend = undefined; 152 | disposables && disposables.remove(mydisp); 153 | })); 154 | return mydisp; 155 | } 156 | exports.consumeCompBack = consumeCompBack; 157 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0b2NvbXBsZXRlLWhhc2tlbGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYXV0b2NvbXBsZXRlLWhhc2tlbGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwrQkFBa0U7QUFDbEUsNkRBQStFO0FBQy9FLGlFQUEyRDtBQUUzRCxJQUFJLE9BQTZELENBQUE7QUFDakUsSUFBSSxXQUE0QyxDQUFBO0FBQ2hELElBQUksS0FBc0QsQ0FBQTtBQUMxRCxJQUFJLEdBQWlDLENBQUE7QUFDckMsSUFBSSxrQkFBc0MsQ0FBQTtBQWExQyxtQ0FBaUM7QUFBeEIsMEJBQUEsTUFBTSxDQUFBO0FBRWYsa0JBQXlCLEtBQWE7SUFDcEMsV0FBVyxHQUFHLElBQUksMEJBQW1CLEVBQUUsQ0FBQTtJQUV2QyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsWUFBWSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDckMsS0FBSyxDQUFDLFlBQVksR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLGlEQUFpRCxDQUFDLEtBQUssU0FBUyxDQUFDLENBQUE7SUFDekcsQ0FBQztJQUVELGtCQUFrQixHQUFHLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQTtJQUU3QyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQztRQUN2QixXQUFXLEVBQUUsQ0FBQTtJQUNmLENBQUM7SUFFRCxXQUFXLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLDJDQUEyQyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUU7UUFDdkYsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztZQUNWLENBQUMsR0FBRyxJQUFJLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQTtRQUMxRCxDQUFDO0lB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LEVBQ0YsSUFBSSxpQkFBVSxDQUFDLEdBQUcsRUFBRTtRQUNsQixPQUFPLEdBQUcsU0FBUyxDQUFBO1FBQ25CLFdBQVcsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQzNDLENBQUMsQ0FBQyxDQUNILENBQUE7SUFDRCxNQUFNLENBQUMsTUFBTSxDQUFBO0FBQ2YsQ0FBQztBQWhCRCwwQ0FnQkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJRXZlbnREZXNjLCBDb21wb3NpdGVEaXNwb3NhYmxlLCBEaXNwb3NhYmxlIH0gZnJvbSAnYXRvbSdcbmltcG9ydCB7IFN1Z2dlc3Rpb25CdWlsZGVyLCBJT3B0aW9ucywgSVN1Z2dlc3Rpb24gfSBmcm9tICcuL3N1Z2dlc3Rpb24tYnVpbGRlcidcbmltcG9ydCB7IExhc3RTdWdnZXN0aW9uVmlldyB9IGZyb20gJy4vbGFzdC1zdWdnZXN0aW9uLXZpZXcnXG5cbmxldCBiYWNrZW5kOiBVUEkuQ29tcGxldGlvbkJhY2tlbmQuSUNvbXBsZXRpb25CYWNrZW5kIHwgdW5kZWZpbmVkXG5sZXQgZGlzcG9zYWJsZXM6IENvbXBvc2l0ZURpc3Bvc2FibGUgfCB1bmRlZmluZWRcbmxldCBwYW5lbDogQXRvbVR5cGVzLlBhbmVsPExhc3RTdWdnZXN0aW9uVmlldz4gfCB1bmRlZmluZWRcbmxldCB1cGk6IFVQSS5JVVBJSW5zdGFuY2UgfCB1bmRlZmluZWRcbmxldCBsYXN0Q29tcGxldGlvbkRlc2M6IHN0cmluZyB8IHVuZGVmaW5lZFxuXG5pbnRlcmZhY2UgSVN0YXRlIHtcbiAgcGFuZWxWaXNpYmxlPzogYm9vbGVhblxuICBsYXN0Q29tcGxldGlvbkRlc2M6IHN0cmluZyB8IHVuZGVmaW5lZFxufVxuXG5pbnRlcmZhY2UgSUFDUERpZEluc2VydEV2ZW50UGFyYW1zIHtcbiAgZWRpdG9yOiBBdG9tVHlwZXMuVGV4dEVkaXRvclxuICB0cmlnZ2VyUG9zaXRpb246IEF0b21UeXBlcy5Qb2ludFxuICBzdWdnZXN0aW9uOiBJU3VnZ2VzdGlvblxufVxuXG5leHBvcnQgeyBjb25maWcgfSBmcm9tICcuL2NvbmZpZydcblxuZXhwb3J0IGZ1bmN0aW9uIGFjdGl2YXRlKHN0YXRlOiBJU3RhdGUpIHtcbiAgZGlzcG9zYWJsZXMgPSBuZXcgQ29tcG9zaXRlRGlzcG9zYWJsZSgpXG5cbiAgaWYgKHN0YXRlLnBhbmVsVmlzaWJsZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgc3RhdGUucGFuZWxWaXNpYmxlID0gKGF0b20uY29uZmlnLmdldCgnYXV0b2NvbXBsZXRlLWhhc2tlbGwuZGVmYXVsdEhpbnRQYW5lbFZpc2liaWxpdHknKSA9PT0gJ1Zpc2libGUnKVxuICB9XG5cbiAgbGFzdENvbXBsZXRpb25EZXNjID0gc3RhdGUubGFzdENvbXBsZXRpb25EZXNjXG5cbiAgaWYgKHN0YXRlLnBhbmVsVmlzaWJsZSkge1xuICAgIGNyZWF0ZVBhbmVsKClcbiAgfVxuXG4gIGRpc3Bvc2FibGVzLmFkZChhdG9tLmNvbmZpZy5vYnNlcnZlKCdhdXRvY29tcGxldGUtaGFza2VsbC5oaWRlSGludFBhbmVsSWZFbXB0eScsICh2YWwpID0+IHtcbiAgICBpZiAocGFuZWwpIHtcbiAgICAgICF2YWwgfHwgbGFzdENvbXBsZXRpb25EZXNjID8gcGFuZWwuc2hvdygpIDogcGFuZWwuaGlkZSgpXG4gICAgfVxuICB9KSlcblxuICBkaXNwb3NhYmxlcy5hZGQoXG4gICAgYXRvbS5jb21tYW5kcy5hZGQoJ2F0b20tdGV4dC1lZGl0b3JbZGF0YS1ncmFtbWFyfj1cImhhc2tlbGxcIl0nLCB7XG4gICAgICAnYXV0b2NvbXBsZXRlLWhhc2tlbGw6Y29uY2VhbC1oaW50LXBhbmVsJzogKHsgY3VycmVudFRhcmdldCwgYWJvcnRLZXlCaW5kaW5nIH06IElFdmVudERlc2MpID0+IHtcbiAgICAgICAgaWYgKHBhbmVsICYmIHBhbmVsLmlzVmlzaWJsZSgpICYmIGF0b20uY29uZmlnLmdldCgnYXV0b2NvbXBsZXRlLWhhc2tlbGwuaGlkZUhpbnRQYW5lbElmRW1wdHknKSkge1xuICAgICAgICAgIHBhbmVsLmhpZGUoKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGlmICh0eXBlb2YgYWJvcnRLZXlCaW5kaW5nID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBhYm9ydEtleUJpbmRpbmcoKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9LFxuICApLFxuICApXG5cbiAgZGlzcG9zYWJsZXMuYWRkKGF0b20uY29tbWFuZHMuYWRkKCdhdG9tLXdvcmtzcGFjZScsIHtcbiAgICAnYXV0b2NvbXBsZXRlLWhhc2tlbGw6dG9nZ2xlLWNvbXBsZXRpb24taGludCc6ICgpID0+IHtcbiAgICAgIGlmIChwYW5lbCkge1xuICAgICAgICBkZXN0cm95UGFuZWwoKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY3JlYXRlUGFuZWwoKVxuICAgICAgfVxuICAgIH0sXG4gIH0sXG4pLFxuICApXG5cbiAgZGlzcG9zYWJsZXMuYWRkKGF0b20ubWVudS5hZGQoW3tcbiAgICBsYWJlbDogJ0hhc2tlbGwgSURFJyxcbiAgICBzdWJtZW51OiBbe1xuICAgICAgbGFiZWw6ICdUb2dnbGUgQ29tcGxldGlvbiBIaW50IFBhbmVsJyxcbiAgICAgIGNvbW1hbmQ6ICdhdXRvY29tcGxldGUtaGFza2VsbDp0b2dnbGUtY29tcGxldGlvbi1oaW50JyxcbiAgICB9XSxcbiAgfV0pKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplKCk6IElTdGF0ZSB7XG4gIHJldHVybiB7XG4gICAgcGFuZWxWaXNpYmxlOiAhIXBhbmVsLFxuICAgIGxhc3RDb21wbGV0aW9uRGVzYyxcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZGVhY3RpdmF0ZSgpIHtcbiAgZGlzcG9zYWJsZXMgJiYgZGlzcG9zYWJsZXMuZGlzcG9zZSgpXG4gIGRpc3Bvc2FibGVzID0gdW5kZWZpbmVkXG4gIHVwaSA9IHVuZGVmaW5lZFxuICBkZXN0cm95UGFuZWwoKVxufVxuXG5mdW5jdGlvbiBjcmVhdGVQYW5lbCgpIHtcbiAgcGFuZWwgPSBhdG9tLndvcmtzcGFjZS5hZGRCb3R0b21QYW5lbCh7XG4gICAgaXRlbTogbmV3IExhc3RTdWdnZXN0aW9uVmlldyhsYXN0Q29tcGxldGlvbkRlc2MpLFxuICAgIHZpc2libGU6IHRydWUsXG4gICAgcHJpb3JpdHk6IDIwMCxcbiAgfSlcbn1cblxuZnVuY3Rpb24gZGVzdHJveVBhbmVsKCkge1xuICBwYW5lbCAmJiBwYW5lbC5kZXN0cm95KClcbiAgcGFuZWwgPSB1bmRlZmluZWRcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGF1dG9jb21wbGV0ZVByb3ZpZGVyXzJfMF8wKCkge1xuICByZXR1cm4ge1xuICAgIHNlbGVjdG9yOiAnLnNvdXJjZS5oYXNrZWxsJyxcbiAgICBkaXNhYmxlRm9yU2VsZWN0b3I6ICcuc291cmNlLmhhc2tlbGwgLmNvbW1lbnQnLFxuICAgIGluY2x1c2lvblByaW9yaXR5OiAwLFxuICAgIGdldFN1Z2dlc3Rpb25zOiAob3B0aW9uczogSU9wdGlvbnMpID0+IHtcbiAgICAgIGlmICghYmFja2VuZCkgeyByZXR1cm4gW10gfVxuICAgICAgcmV0dXJuIChuZXcgU3VnZ2VzdGlvbkJ1aWxkZXIob3B0aW9ucywgYmFja2VuZCkpLmdldFN1Z2dlc3Rpb25zKClcbiAgICB9LFxuICAgIG9uRGlkSW5zZXJ0U3VnZ2VzdGlvbjogKHsgZWRpdG9yLCB0cmlnZ2VyUG9zaXRpb24sIHN1Z2dlc3Rpb24gfTogSUFDUERpZEluc2VydEV2ZW50UGFyYW1zKSA9PiB7XG4gICAgICBpZiAoc3VnZ2VzdGlvbiAmJiBzdWdnZXN0aW9uLmRlc2NyaXB0aW9uKSB7XG4gICAgICAgIGNvbnN0IGRlc2MgPSBsYXN0Q29tcGxldGlvbkRlc2MgPSBzdWdnZXN0aW9uLmRlc2NyaXB0aW9uXG4gICAgICAgIGlmIChwYW5lbCkge1xuICAgICAgICAgIGNvbnN0IHZpZXc6IExhc3RTdWdnZXN0aW9uVmlldyA9IHBhbmVsLmdldEl0ZW0oKVxuICAgICAgICAgIHZpZXcuc2V0VGV4dChkZXNjKVxuICAgICAgICAgIGlmIChhdG9tLmNvbmZpZy5nZXQoJ2F1dG9jb21wbGV0ZS1oYXNrZWxsLmhpZGVIaW50UGFuZWxJZkVtcHR5JykpIHtcbiAgICAgICAgICAgIHBhbmVsLnNob3coKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAodXBpICYmIGF0b20uY29uZmlnLmdldCgnYXV0b2NvbXBsZXRlLWhhc2tlbGwuc2hvd0lkZUhhc2tlbGxUb29sdGlwJykpIHtcbiAgICAgICAgICBjb25zdCBwMiA9IGVkaXRvci5nZXRMYXN0Q3Vyc29yKCkuZ2V0QnVmZmVyUG9zaXRpb24oKVxuICAgICAgICAgIGNvbnN0IHAxID0gcDIudHJhbnNsYXRlKFswLCAtc3VnZ2VzdGlvbi50ZXh0Lmxlbmd0aF0pXG4gICAgICAgICAgc2V0SW1tZWRpYXRlKCgpID0+IHtcbiAgICAgICAgICAgIHVwaSAmJiB1cGkuc2hvd1Rvb2x0aXAoe1xuICAgICAgICAgICAgICBlZGl0b3IsXG4gICAgICAgICAgICAgIGV2ZW50VHlwZTogVVBJLlRFdmVudFJhbmdlVHlwZS5rZXlib2FyZCxcbiAgICAgICAgICAgICAgdG9vbHRpcDoge1xuICAgICAgICAgICAgICAgIHJhbmdlOiBbcDEsIHAyXSxcbiAgICAgICAgICAgICAgICBwZXJzaXN0ZW50OiB0cnVlLFxuICAgICAgICAgICAgICAgIHRleHQ6IHtcbiAgICAgICAgICAgICAgICAgIHRleHQ6IGRlc2MsXG4gICAgICAgICAgICAgICAgICBoaWdobGlnaHRlcjogJ2hpbnQuaGFza2VsbCcsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChwYW5lbCkge1xuICAgICAgICBjb25zdCB2aWV3OiBMYXN0U3VnZ2VzdGlvblZpZXcgPSBwYW5lbC5nZXRJdGVtKClcbiAgICAgICAgdmlldy5zZXRUZXh0KCcnKVxuICAgICAgICBpZiAocGFuZWwgJiYgYXRvbS5jb25maWcuZ2V0KCdhdXRvY29tcGxldGUtaGFza2VsbC5oaWRlSGludFBhbmVsSWZFbXB0eScpKSB7XG4gICAgICAgICAgcGFuZWwuaGlkZSgpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjb25zdW1lVVBJKHNlcnZpY2U6IFVQSS5JVVBJUmVnaXN0cmF0aW9uKSB7XG4gIHVwaSA9IHNlcnZpY2Uoe1xuICAgIG5hbWU6ICdhdXRvY29tcGxldGUtaGFza2VsbCcsXG4gIH0pXG4gIGRpc3Bvc2FibGVzICYmIGRpc3Bvc2FibGVzLmFkZCh1cGkpXG4gIHJldHVybiB1cGlcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNvbnN1bWVDb21wQmFjayhzZXJ2aWNlOiBVUEkuQ29tcGxldGlvbkJhY2tlbmQuSUNvbXBsZXRpb25CYWNrZW5kKSB7XG4gIGJhY2tlbmQgPSBzZXJ2aWNlXG4gIGNvbnN0IG15ZGlzcCA9IG5ldyBDb21wb3NpdGVEaXNwb3NhYmxlKClcbiAgZGlzcG9zYWJsZXMgJiYgZGlzcG9zYWJsZXMuYWRkKG15ZGlzcClcbiAgbXlkaXNwLmFkZChcbiAgICBhdG9tLndvcmtzcGFjZS5vYnNlcnZlVGV4dEVkaXRvcnMoKGVkaXRvcikgPT4ge1xuICAgICAgaWYgKGVkaXRvci5nZXRHcmFtbWFyKCkuc2NvcGVOYW1lID09PSAnc291cmNlLmhhc2tlbGwnKSB7XG4gICAgICAgIG15ZGlzcC5hZGQoc2VydmljZS5yZWdpc3RlckNvbXBsZXRpb25CdWZmZXIoZWRpdG9yLmdldEJ1ZmZlcigpKSlcbiAgICAgIH1cbiAgICB9KSxcbiAgICBuZXcgRGlzcG9zYWJsZSgoKSA9PiB7XG4gICAgICBiYWNrZW5kID0gdW5kZWZpbmVkXG4gICAgICBkaXNwb3NhYmxlcyAmJiBkaXNwb3NhYmxlcy5yZW1vdmUobXlkaXNwKVxuICAgIH0pLFxuICApXG4gIHJldHVybiBteWRpc3Bcbn1cbiJdfQ== -------------------------------------------------------------------------------- /lib/suggestion-builder.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | Object.defineProperty(exports, "__esModule", { value: true }); 11 | const atom_1 = require("atom"); 12 | const fuzzaldrin_1 = require("fuzzaldrin"); 13 | const typeScope = ['meta.type-signature.haskell']; 14 | const sourceScope = ['source.haskell']; 15 | const moduleScope = ['meta.import.haskell', 'support.other.module.haskell']; 16 | const preprocessorScope = ['meta.preprocessor.haskell']; 17 | const instancePreprocessorScope = ['meta.declaration.instance.haskell', 'meta.preprocessor.haskell']; 18 | const exportsScope = ['meta.import.haskell', 'meta.declaration.exports.haskell']; 19 | const pragmaWords = [ 20 | 'LANGUAGE', 'OPTIONS_GHC', 'INCLUDE', 'WARNING', 'DEPRECATED', 'INLINE', 21 | 'NOINLINE', 'ANN', 'LINE', 'RULES', 'SPECIALIZE', 'UNPACK', 'SOURCE', 22 | ]; 23 | const instancePragmaWords = [ 24 | 'INCOHERENT', 25 | 'OVERLAPPABLE', 26 | 'OVERLAPPING', 27 | 'OVERLAPS', 28 | ]; 29 | const opertator_regex_1 = require("./opertator-regex"); 30 | class SuggestionBuilder { 31 | constructor(options, backend) { 32 | this.options = options; 33 | this.backend = backend; 34 | this.buffer = this.options.editor.getBuffer(); 35 | this.lineRange = new atom_1.Range([this.options.bufferPosition.row, 0], this.options.bufferPosition); 36 | this.line = this.buffer.getTextInRange(this.lineRange); 37 | this.mwl = 38 | this.options.activatedManually ? 39 | 0 40 | : 41 | atom.config.get('autocomplete-plus.minimumWordLength'); 42 | } 43 | getSuggestions() { 44 | return __awaiter(this, void 0, void 0, function* () { 45 | if (this.isIn(instancePreprocessorScope)) { 46 | return this.preprocessorSuggestions(instancePragmaWords); 47 | } 48 | else if (this.isIn(typeScope)) { 49 | return this.symbolSuggestions(this.backend.getCompletionsForType.bind(this.backend)); 50 | } 51 | else if (this.isIn(moduleScope)) { 52 | return this.moduleSuggestions(); 53 | } 54 | else if (this.isIn(exportsScope)) { 55 | return this.symbolSuggestions(this.backend.getCompletionsForSymbolInModule.bind(this.backend)); 56 | } 57 | else if (this.isIn(preprocessorScope)) { 58 | return this.preprocessorSuggestions(pragmaWords); 59 | } 60 | else if (this.isIn(sourceScope)) { 61 | if (this.getPrefix().startsWith('_')) { 62 | return this.symbolSuggestions(this.backend.getCompletionsForHole.bind(this.backend)); 63 | } 64 | else if (this.getPrefix() === '' && this.getPrefix(opertator_regex_1.operatorRx) !== '') { 65 | return this.operatorSuggestions(); 66 | } 67 | else { 68 | return this.symbolSuggestions(this.backend.getCompletionsForSymbol.bind(this.backend)); 69 | } 70 | } 71 | else { 72 | return []; 73 | } 74 | }); 75 | } 76 | lineSearch(rx, idx = 0) { 77 | const match = this.line.match(rx); 78 | if (match) { 79 | return match; 80 | } 81 | else { 82 | return ['']; 83 | } 84 | } 85 | isIn(scope) { 86 | return scope.every((s1) => this.options.scopeDescriptor.getScopesArray().includes(s1)); 87 | } 88 | getPrefix(rx) { 89 | if (!rx) { 90 | rx = opertator_regex_1.identRx; 91 | } 92 | return this.lineSearch(rx)[0]; 93 | } 94 | buildSymbolSuggestion(s, prefix) { 95 | return { 96 | text: s.qname ? s.qname : s.name, 97 | rightLabel: (s.module ? s.module.name : undefined), 98 | type: s.symbolType, 99 | replacementPrefix: prefix, 100 | description: this.nameFix(s) + ' :: ' + s.typeSignature, 101 | }; 102 | } 103 | nameFix(s) { 104 | if (s.symbolType === 'operator') { 105 | return `(${s.name})`; 106 | } 107 | else { 108 | return s.name; 109 | } 110 | } 111 | buildSimpleSuggestion(type, text, prefix, label) { 112 | return { 113 | text, 114 | type, 115 | replacementPrefix: prefix, 116 | rightLabel: label, 117 | }; 118 | } 119 | processSuggestions(f, rx, p) { 120 | return __awaiter(this, void 0, void 0, function* () { 121 | const prefix = this.getPrefix(rx); 122 | if (prefix.length < this.mwl) { 123 | return []; 124 | } 125 | const symbols = yield f(this.buffer, prefix, this.options.bufferPosition); 126 | return symbols.map((s) => p(s, prefix)); 127 | }); 128 | } 129 | symbolSuggestions(f, rx) { 130 | return __awaiter(this, void 0, void 0, function* () { 131 | return this.processSuggestions(f, rx, this.buildSymbolSuggestion.bind(this)); 132 | }); 133 | } 134 | moduleSuggestions() { 135 | return __awaiter(this, void 0, void 0, function* () { 136 | return this.processSuggestions(this.backend.getCompletionsForModule.bind(this.backend), undefined, (s, prefix) => this.buildSimpleSuggestion('import', s, prefix)); 137 | }); 138 | } 139 | preprocessorSuggestions(pragmaList) { 140 | let f; 141 | const kwrx = new RegExp(`\\b(${pragmaList.join('|')})\\b`); 142 | const kw = this.lineSearch(kwrx)[0]; 143 | let label = ''; 144 | let rx; 145 | switch (false) { 146 | case kw !== 'OPTIONS_GHC': 147 | rx = /[\w-]+$/; 148 | label = 'GHC Flag'; 149 | f = this.backend.getCompletionsForCompilerOptions; 150 | break; 151 | case kw !== 'LANGUAGE': 152 | label = 'Language'; 153 | f = this.backend.getCompletionsForLanguagePragmas; 154 | break; 155 | case !!kw: 156 | label = 'Pragma'; 157 | f = (b, p) => __awaiter(this, void 0, void 0, function* () { return fuzzaldrin_1.filter(pragmaList, p); }); 158 | break; 159 | default: 160 | return []; 161 | } 162 | return this.processSuggestions(f, rx, (s, prefix) => this.buildSimpleSuggestion('keyword', s, prefix, label)); 163 | } 164 | operatorSuggestions() { 165 | return __awaiter(this, void 0, void 0, function* () { 166 | const prefixMatch = this.lineSearch(opertator_regex_1.operatorRx); 167 | if (!prefixMatch) { 168 | return []; 169 | } 170 | const [mod, op] = prefixMatch.slice(1); 171 | if (prefixMatch[0].length < this.mwl) { 172 | return []; 173 | } 174 | const symbols = yield this.backend.getCompletionsForSymbol(this.buffer, `${mod || ''}${op}`, this.options.bufferPosition); 175 | const newSyms = symbols 176 | .filter(({ symbolType }) => symbolType === 'operator'); 177 | const allSyms = fuzzaldrin_1.filter(newSyms, prefixMatch[0], { key: 'qname' }); 178 | return allSyms.map((s) => this.buildSymbolSuggestion(s, prefixMatch[0])); 179 | }); 180 | } 181 | } 182 | exports.SuggestionBuilder = SuggestionBuilder; 183 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VnZ2VzdGlvbi1idWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3N1Z2dlc3Rpb24tYnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUEsK0JBQTRCO0FBQzVCLDJDQUFtQztBQUduQyxNQUFNLFNBQVMsR0FBRyxDQUFDLDZCQUE2QixDQUFDLENBQUE7QUFDakQsTUFBTSxXQUFXLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFBO0FBQ3RDLE1BQU0sV0FBVyxHQUFHLENBQUMscUJBQXFCLEVBQUUsOEJBQThCLENBQUMsQ0FBQTtBQUMzRSxNQUFNLGlCQUFpQixHQUFHLENBQUMsMkJBQTJCLENBQUMsQ0FBQTtBQUN2RCxNQUFNLHlCQUF5QixHQUFHLENBQUMsbUNBQW1DLEVBQUUsMkJBQTJCLENBQUMsQ0FBQTtBQUNwRyxNQUFNLFlBQVksR0FBRyxDQUFDLHFCQUFxQixFQUFFLGtDQUFrQyxDQUFDLENBQUE7QUFFaEYsTUFBTSxXQUFXLEdBQUc7SUFDbEIsVUFBVSxFQUFFLGFBQWEsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxRQUFRO0lBQ3ZFLFVBQVUsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLFFBQVE7Q0FDckUsQ0FBQTtBQUVELE1BQU0sbUJBQW1CLEdBQUc7SUFDMUIsWUFBWTtJQUNaLGNBQWM7SUFDZCxhQUFhO0lBQ2IsVUFBVTtDQUNYLENBQUE7QUFFRCx1REFBdUQ7QUFtQnZEO0lBS0UsWUFBb0IsT0FBaUIsRUFBVSxPQUE4QjtRQUF6RCxZQUFPLEdBQVAsT0FBTyxDQUFVO1FBQVUsWUFBTyxHQUFQLE9BQU8sQ0FBdUI7UUFDM0UsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQTtRQUM3QyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksWUFB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LElBQUksRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUE7WUFDM0csTUFBTSxPQUFPLEdBQ1gsT0FBTztpQkFDSixNQUFNLENBQUMsQ0FBQyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxVQUFVLEtBQUssVUFBVSxDQUFDLENBQUE7WUFDMUQsTUFBTSxPQUFPLEdBQUcsbUJBQU0sQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUE7WUFDakUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUMxRSxDQUFDO0tBQUE7Q0FDRjtBQTFKRCw4Q0EwSkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSYW5nZSB9IGZyb20gJ2F0b20nXG5pbXBvcnQgeyBmaWx0ZXIgfSBmcm9tICdmdXp6YWxkcmluJ1xuaW1wb3J0IENCID0gVVBJLkNvbXBsZXRpb25CYWNrZW5kXG5cbmNvbnN0IHR5cGVTY29wZSA9IFsnbWV0YS50eXBlLXNpZ25hdHVyZS5oYXNrZWxsJ11cbmNvbnN0IHNvdXJjZVNjb3BlID0gWydzb3VyY2UuaGFza2VsbCddXG5jb25zdCBtb2R1bGVTY29wZSA9IFsnbWV0YS5pbXBvcnQuaGFza2VsbCcsICdzdXBwb3J0Lm90aGVyLm1vZHVsZS5oYXNrZWxsJ11cbmNvbnN0IHByZXByb2Nlc3NvclNjb3BlID0gWydtZXRhLnByZXByb2Nlc3Nvci5oYXNrZWxsJ11cbmNvbnN0IGluc3RhbmNlUHJlcHJvY2Vzc29yU2NvcGUgPSBbJ21ldGEuZGVjbGFyYXRpb24uaW5zdGFuY2UuaGFza2VsbCcsICdtZXRhLnByZXByb2Nlc3Nvci5oYXNrZWxsJ11cbmNvbnN0IGV4cG9ydHNTY29wZSA9IFsnbWV0YS5pbXBvcnQuaGFza2VsbCcsICdtZXRhLmRlY2xhcmF0aW9uLmV4cG9ydHMuaGFza2VsbCddXG5cbmNvbnN0IHByYWdtYVdvcmRzID0gW1xuICAnTEFOR1VBR0UnLCAnT1BUSU9OU19HSEMnLCAnSU5DTFVERScsICdXQVJOSU5HJywgJ0RFUFJFQ0FURUQnLCAnSU5MSU5FJyxcbiAgJ05PSU5MSU5FJywgJ0FOTicsICdMSU5FJywgJ1JVTEVTJywgJ1NQRUNJQUxJWkUnLCAnVU5QQUNLJywgJ1NPVVJDRScsXG5dXG5cbmNvbnN0IGluc3RhbmNlUHJhZ21hV29yZHMgPSBbXG4gICdJTkNPSEVSRU5UJyxcbiAgJ09WRVJMQVBQQUJMRScsXG4gICdPVkVSTEFQUElORycsXG4gICdPVkVSTEFQUycsXG5dXG5cbmltcG9ydCB7IG9wZXJhdG9yUngsIGlkZW50UnggfSBmcm9tICcuL29wZXJ0YXRvci1yZWdleCdcblxuZXhwb3J0IGludGVyZmFjZSBJT3B0aW9ucyB7XG4gIGVkaXRvcjogQXRvbVR5cGVzLlRleHRFZGl0b3JcbiAgYnVmZmVyUG9zaXRpb246IEF0b21UeXBlcy5Qb2ludFxuICBhY3RpdmF0ZWRNYW51YWxseTogYm9vbGVhblxuICBzY29wZURlc2NyaXB0b3I6IEF0b21UeXBlcy5TY29wZURlc2NyaXB0b3Jcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJU3VnZ2VzdGlvbiB7XG4gIHRleHQ6IHN0cmluZ1xuICByaWdodExhYmVsPzogc3RyaW5nXG4gIHR5cGU6IENCLlN5bWJvbFR5cGUgfCAnaW1wb3J0JyB8ICdrZXl3b3JkJ1xuICByZXBsYWNlbWVudFByZWZpeDogc3RyaW5nXG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nXG59XG5cbnR5cGUgR2V0U3ltYm9sc0NhbGxiYWNrPFQ+ID0gKGJ1ZmZlcjogQXRvbVR5cGVzLlRleHRCdWZmZXIsIHByZWZpeDogc3RyaW5nLCBwb3NpdGlvbjogQXRvbVR5cGVzLlBvaW50KSA9PiBQcm9taXNlPFRbXT5cblxuZXhwb3J0IGNsYXNzIFN1Z2dlc3Rpb25CdWlsZGVyIHtcbiAgcHJpdmF0ZSBidWZmZXI6IEF0b21UeXBlcy5UZXh0QnVmZmVyXG4gIHByaXZhdGUgbGluZVJhbmdlOiBBdG9tVHlwZXMuUmFuZ2VcbiAgcHJpdmF0ZSBsaW5lOiBzdHJpbmdcbiAgcHJpdmF0ZSBtd2w6IG51bWJlclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIG9wdGlvbnM6IElPcHRpb25zLCBwcml2YXRlIGJhY2tlbmQ6IENCLklDb21wbGV0aW9uQmFja2VuZCkge1xuICAgIHRoaXMuYnVmZmVyID0gdGhpcy5vcHRpb25zLmVkaXRvci5nZXRCdWZmZXIoKVxuICAgIHRoaXMubGluZVJhbmdlID0gbmV3IFJhbmdlKFxuICAgICAgW3RoaXMub3B0aW9ucy5idWZmZXJQb3NpdGlvbi5yb3csIDBdLFxuICAgICAgdGhpcy5vcHRpb25zLmJ1ZmZlclBvc2l0aW9uLFxuICAgIClcbiAgICB0aGlzLmxpbmUgPSB0aGlzLmJ1ZmZlci5nZXRUZXh0SW5SYW5nZSh0aGlzLmxpbmVSYW5nZSlcbiAgICB0aGlzLm13bCA9XG4gICAgICB0aGlzLm9wdGlvbnMuYWN0aXZhdGVkTWFudWFsbHkgP1xuICAgICAgICAwXG4gICAgICAgIDpcbiAgICAgICAgYXRvbS5jb25maWcuZ2V0KCdhdXRvY29tcGxldGUtcGx1cy5taW5pbXVtV29yZExlbmd0aCcpXG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZ2V0U3VnZ2VzdGlvbnMoKTogUHJvbWlzZTxJU3VnZ2VzdGlvbltdPiB7XG4gICAgaWYgKHRoaXMuaXNJbihpbnN0YW5jZVByZXByb2Nlc3NvclNjb3BlKSkge1xuICAgICAgcmV0dXJuIHRoaXMucHJlcHJvY2Vzc29yU3VnZ2VzdGlvbnMoaW5zdGFuY2VQcmFnbWFXb3JkcylcbiAgICB9IGVsc2UgaWYgKHRoaXMuaXNJbih0eXBlU2NvcGUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5zeW1ib2xTdWdnZXN0aW9ucyh0aGlzLmJhY2tlbmQuZ2V0Q29tcGxldGlvbnNGb3JUeXBlLmJpbmQodGhpcy5iYWNrZW5kKSlcbiAgICB9IGVsc2UgaWYgKHRoaXMuaXNJbihtb2R1bGVTY29wZSkpIHtcbiAgICAgIHJldHVybiB0aGlzLm1vZHVsZVN1Z2dlc3Rpb25zKClcbiAgICB9IGVsc2UgaWYgKHRoaXMuaXNJbihleHBvcnRzU2NvcGUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5zeW1ib2xTdWdnZXN0aW9ucyh0aGlzLmJhY2tlbmQuZ2V0Q29tcGxldGlvbnNGb3JTeW1ib2xJbk1vZHVsZS5iaW5kKHRoaXMuYmFja2VuZCkpXG4gICAgfSBlbHNlIGlmICh0aGlzLmlzSW4ocHJlcHJvY2Vzc29yU2NvcGUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5wcmVwcm9jZXNzb3JTdWdnZXN0aW9ucyhwcmFnbWFXb3JkcylcbiAgICAgIC8vIHNob3VsZCBiZSBsYXN0IGFzIGxlYXN0IHNlcGNpYWxpemVkXG4gICAgfSBlbHNlIGlmICh0aGlzLmlzSW4oc291cmNlU2NvcGUpKSB7XG4gICAgICBpZiAodGhpcy5nZXRQcmVmaXgoKS5zdGFydHNXaXRoKCdfJykpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3ltYm9sU3VnZ2VzdGlvbnModGhpcy5iYWNrZW5kLmdldENvbXBsZXRpb25zRm9ySG9sZS5iaW5kKHRoaXMuYmFja2VuZCkpXG4gICAgICB9IGVsc2UgaWYgKHRoaXMuZ2V0UHJlZml4KCkgPT09ICcnICYmIHRoaXMuZ2V0UHJlZml4KG9wZXJhdG9yUngpICE9PSAnJykge1xuICAgICAgICByZXR1cm4gdGhpcy5vcGVyYXRvclN1Z2dlc3Rpb25zKClcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN5bWJvbFN1Z2dlc3Rpb25zKHRoaXMuYmFja2VuZC5nZXRDb21wbGV0aW9uc0ZvclN5bWJvbC5iaW5kKHRoaXMuYmFja2VuZCkpXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBbXVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbGluZVNlYXJjaChyeDogUmVnRXhwLCBpZHg6IG51bWJlciA9IDApIHtcbiAgICBjb25zdCBtYXRjaCA9IHRoaXMubGluZS5tYXRjaChyeClcbiAgICBpZiAobWF0Y2gpIHtcbiAgICAgIHJldHVybiBtYXRjaFxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gWycnXVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaXNJbihzY29wZTogc3RyaW5nW10pIHtcbiAgICByZXR1cm4gc2NvcGUuZXZlcnkoKHMxKSA9PiB0aGlzLm9wdGlvbnMuc2NvcGVEZXNjcmlwdG9yLmdldFNjb3Blc0FycmF5KCkuaW5jbHVkZXMoczEpKVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRQcmVmaXgocng/OiBSZWdFeHApIHtcbiAgICBpZiAoIXJ4KSB7IHJ4ID0gaWRlbnRSeCB9XG4gICAgcmV0dXJuIHRoaXMubGluZVNlYXJjaChyeClbMF1cbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRTeW1ib2xTdWdnZXN0aW9uKHM6IENCLklTeW1ib2wsIHByZWZpeDogc3RyaW5nKTogSVN1Z2dlc3Rpb24ge1xuICAgIHJldHVybiB7XG4gICAgICB0ZXh0OiBzLnFuYW1lID8gcy5xbmFtZSA6IHMubmFtZSxcbiAgICAgIHJpZ2h0TGFiZWw6IChzLm1vZHVsZSA/IHMubW9kdWxlLm5hbWUgOiB1bmRlZmluZWQpLFxuICAgICAgdHlwZTogcy5zeW1ib2xUeXBlLFxuICAgICAgcmVwbGFjZW1lbnRQcmVmaXg6IHByZWZpeCxcbiAgICAgIGRlc2NyaXB0aW9uOiB0aGlzLm5hbWVGaXgocykgKyAnIDo6ICcgKyBzLnR5cGVTaWduYXR1cmUsXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBuYW1lRml4KHM6IENCLklTeW1ib2wpIHtcbiAgICBpZiAocy5zeW1ib2xUeXBlID09PSAnb3BlcmF0b3InKSB7XG4gICAgICByZXR1cm4gYCgke3MubmFtZX0pYFxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gcy5uYW1lXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFNpbXBsZVN1Z2dlc3Rpb24oXG4gICAgdHlwZTogJ2ltcG9ydCcgfCAna2V5d29yZCcsIHRleHQ6IHN0cmluZywgcHJlZml4OiBzdHJpbmcsIGxhYmVsPzogc3RyaW5nLFxuICApOiBJU3VnZ2VzdGlvbiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRleHQsXG4gICAgICB0eXBlLFxuICAgICAgcmVwbGFjZW1lbnRQcmVmaXg6IHByZWZpeCxcbiAgICAgIHJpZ2h0TGFiZWw6IGxhYmVsLFxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcHJvY2Vzc1N1Z2dlc3Rpb25zPFQ+KFxuICAgIGY6IEdldFN5bWJvbHNDYWxsYmFjazxUPiwgcng6IFJlZ0V4cCB8IHVuZGVmaW5lZCwgcDogKHM6IFQsIHA6IHN0cmluZykgPT4gSVN1Z2dlc3Rpb24sXG4gICkge1xuICAgIGNvbnN0IHByZWZpeCA9IHRoaXMuZ2V0UHJlZml4KHJ4KVxuICAgIGlmIChwcmVmaXgubGVuZ3RoIDwgdGhpcy5td2wpIHtcbiAgICAgIHJldHVybiBbXVxuICAgIH1cbiAgICBjb25zdCBzeW1ib2xzID0gYXdhaXQgZih0aGlzLmJ1ZmZlciwgcHJlZml4LCB0aGlzLm9wdGlvbnMuYnVmZmVyUG9zaXRpb24pXG4gICAgcmV0dXJuIHN5bWJvbHMubWFwKChzKSA9PiBwKHMsIHByZWZpeCkpXG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHN5bWJvbFN1Z2dlc3Rpb25zKGY6IEdldFN5bWJvbHNDYWxsYmFjazxDQi5JU3ltYm9sPiwgcng/OiBSZWdFeHApIHtcbiAgICByZXR1cm4gdGhpcy5wcm9jZXNzU3VnZ2VzdGlvbnMoZiwgcngsIHRoaXMuYnVpbGRTeW1ib2xTdWdnZXN0aW9uLmJpbmQodGhpcykpXG4gIH1cblxuICBwcml2YXRlIGFzeW5jIG1vZHVsZVN1Z2dlc3Rpb25zKCkge1xuICAgIHJldHVybiB0aGlzLnByb2Nlc3NTdWdnZXN0aW9ucyh0aGlzLmJhY2tlbmQuZ2V0Q29tcGxldGlvbnNGb3JNb2R1bGUuYmluZCh0aGlzLmJhY2tlbmQpLCB1bmRlZmluZWQsIChzLCBwcmVmaXgpID0+XG4gICAgICB0aGlzLmJ1aWxkU2ltcGxlU3VnZ2VzdGlvbignaW1wb3J0JywgcywgcHJlZml4KSlcbiAgfVxuXG4gIHByaXZhdGUgcHJlcHJvY2Vzc29yU3VnZ2VzdGlvbnMocHJhZ21hTGlzdDogc3RyaW5nW10pIHtcbiAgICBsZXQgZjogR2V0U3ltYm9sc0NhbGxiYWNrPHN0cmluZz5cbiAgICBjb25zdCBrd3J4ID0gbmV3IFJlZ0V4cChgXFxcXGIoJHtwcmFnbWFMaXN0LmpvaW4oJ3wnKX0pXFxcXGJgKVxuICAgIGNvbnN0IGt3ID0gdGhpcy5saW5lU2VhcmNoKGt3cngpWzBdXG4gICAgbGV0IGxhYmVsID0gJydcbiAgICBsZXQgcnhcbiAgICBzd2l0Y2ggKGZhbHNlKSB7XG4gICAgICBjYXNlIGt3ICE9PSAnT1BUSU9OU19HSEMnOlxuICAgICAgICByeCA9IC9bXFx3LV0rJC9cbiAgICAgICAgbGFiZWwgPSAnR0hDIEZsYWcnXG4gICAgICAgIGYgPSB0aGlzLmJhY2tlbmQuZ2V0Q29tcGxldGlvbnNGb3JDb21waWxlck9wdGlvbnNcbiAgICAgICAgYnJlYWtcbiAgICAgIGNhc2Uga3cgIT09ICdMQU5HVUFHRSc6XG4gICAgICAgIGxhYmVsID0gJ0xhbmd1YWdlJ1xuICAgICAgICBmID0gdGhpcy5iYWNrZW5kLmdldENvbXBsZXRpb25zRm9yTGFuZ3VhZ2VQcmFnbWFzXG4gICAgICAgIGJyZWFrXG4gICAgICBjYXNlICEha3c6XG4gICAgICAgIGxhYmVsID0gJ1ByYWdtYSdcbiAgICAgICAgZiA9IGFzeW5jIChiLCBwKSA9PiBmaWx0ZXIocHJhZ21hTGlzdCwgcClcbiAgICAgICAgYnJlYWtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBbXVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnByb2Nlc3NTdWdnZXN0aW9ucyhmLCByeCwgKHMsIHByZWZpeCkgPT5cbiAgICAgIHRoaXMuYnVpbGRTaW1wbGVTdWdnZXN0aW9uKCdrZXl3b3JkJywgcywgcHJlZml4LCBsYWJlbCkpXG4gIH1cblxuICBwcml2YXRlIGFzeW5jIG9wZXJhdG9yU3VnZ2VzdGlvbnMoKSB7XG4gICAgY29uc3QgcHJlZml4TWF0Y2ggPSB0aGlzLmxpbmVTZWFyY2gob3BlcmF0b3JSeClcbiAgICBpZiAoIXByZWZpeE1hdGNoKSB7IHJldHVybiBbXSB9XG4gICAgY29uc3QgW21vZCwgb3BdID0gcHJlZml4TWF0Y2guc2xpY2UoMSlcbiAgICBpZiAocHJlZml4TWF0Y2hbMF0ubGVuZ3RoIDwgdGhpcy5td2wpIHtcbiAgICAgIHJldHVybiBbXVxuICAgIH1cbiAgICBjb25zdCBzeW1ib2xzID1cbiAgICAgIGF3YWl0IHRoaXMuYmFja2VuZC5nZXRDb21wbGV0aW9uc0ZvclN5bWJvbCh0aGlzLmJ1ZmZlciwgYCR7bW9kIHx8ICcnfSR7b3B9YCwgdGhpcy5vcHRpb25zLmJ1ZmZlclBvc2l0aW9uKVxuICAgIGNvbnN0IG5ld1N5bXMgPVxuICAgICAgc3ltYm9sc1xuICAgICAgICAuZmlsdGVyKCh7IHN5bWJvbFR5cGUgfSkgPT4gc3ltYm9sVHlwZSA9PT0gJ29wZXJhdG9yJylcbiAgICBjb25zdCBhbGxTeW1zID0gZmlsdGVyKG5ld1N5bXMsIHByZWZpeE1hdGNoWzBdLCB7IGtleTogJ3FuYW1lJyB9KVxuICAgIHJldHVybiBhbGxTeW1zLm1hcCgocykgPT4gdGhpcy5idWlsZFN5bWJvbFN1Z2dlc3Rpb24ocywgcHJlZml4TWF0Y2hbMF0pKVxuICB9XG59XG4iXX0= --------------------------------------------------------------------------------