[
  {
    "path": ".gitignore",
    "content": "out/*\ndist/*\ncoverage/*\nsettingsViewer/*\nnode_modules\ntemp\n*.vsix\n*.cpuprofile\nserver/*.js.map\n.DS_Store\n"
  },
  {
    "path": ".npmignore",
    "content": "server/*.d.ts\nserver/*.js.map\nsrc/\nyarn.lock\nwebpack.config.js\ntslint.json\ntsconfig.json\nnode_modules/\ndicts/\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Release Notes\n\n## v1.0.0\n\n- get it work\n"
  },
  {
    "path": "FAQ.md",
    "content": "# Spell Checker FAQ\n\nThis is a place to capture common questions and possible confusions. Please feel\nfree to make suggestion for things to be added to this file.\n\nSee: [FAQ Issues](https://github.com/streetsidesoftware/vscode-spell-checker/issues?utf8=%E2%9C%93&q=label%3AFAQ+)\n\n## Things to know\n\n### *Is the spell checker case sensitive?*\n\n> The spell checker is NOT case sensitive.\n\n### *What files are excluded by the spell checker?*\n\n> By default the spell checker excludes the same files excluded by the VS Code *search.exclude* setting.  See discussion: [#16](https://github.com/streetsidesoftware/vscode-spell-checker/issues/16), [#55](https://github.com/streetsidesoftware/vscode-spell-checker/issues/55) and [#95](https://github.com/streetsidesoftware/vscode-spell-checker/issues/95)\n\n### *Does the spell checker use any online services?*\n\n> No, the spell checker is self contained. It does not send your code off to a service to be checked.\n\n### *Can I use the spell checker with other languages like Spanish or French?*\n\n> Yes, please visit [cspell-dicts](https://github.com/Jason3S/cspell-dicts).\n> See also: [#119](https://github.com/streetsidesoftware/vscode-spell-checker/issues/119)\n\n### *Is it possible to only spell check comments*\n\n> Yes. It is necessary to define `includeRegExpList` for each language. See [#107](https://github.com/streetsidesoftware/vscode-spell-checker/issues/107) and [#116](https://github.com/streetsidesoftware/vscode-spell-checker/issues/116)\n\n### Can I use the spell checker as a linter or part of the build process?\n\n> Yes you can: [Spell Checker as Npm package #137](https://github.com/streetsidesoftware/vscode-spell-checker/issues/137)\n\n### Can I remove a word from the dictionary?\n\n> [How to remove word from dictionary? #117](https://github.com/streetsidesoftware/vscode-spell-checker/issues/117)\n\n### Can I add a many words to the dictionary at once?\n\n> Yes, select the words and right click to get the menu. Choose `Add Word to Dictionary` or `Add Word to Global Dictionary`. [Add all words in the current document to dictionary #59](https://github.com/streetsidesoftware/vscode-spell-checker/issues/59)\n\n### Can I ignore words.\n\n> See: [Option to ignore words #146](https://github.com/streetsidesoftware/vscode-spell-checker/issues/146)\n"
  },
  {
    "path": "License.txt",
    "content": "Copyright (c) Jason Dent\r\n\r\nAll rights reserved.\r\n\r\nMIT License\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n"
  },
  {
    "path": "README.md",
    "content": "# Spelling Checker for (Neo)vim\n\n> fork from [vscode-spell-checker](https://github.com/streetsidesoftware/vscode-spell-checker) v1.7.24\nand [commit](https://github.com/streetsidesoftware/vscode-spell-checker/commit/f9c2a9eabf3bc41f19d2d0216472afd003fa65bb)\n\nA basic spell checker that works well with camelCase code.\n\nThe goal of this spell checker is to help catch common spelling errors while keeping\nthe number of false positives low.\n\n## Functionality\n\nLoad a TypeScript, JavaScript, Text, etc. file.  Words not in the dictionary\nfiles will have a squiggly underline.\n\n![screenshot](https://user-images.githubusercontent.com/5492542/71676618-9e86f380-2dbb-11ea-9838-2291e895c7ff.png)\n\nTo see the list of suggestions:\n\n![screenshot](https://user-images.githubusercontent.com/5492542/71676668-bc545880-2dbb-11ea-8bcc-4bd9140ef959.png)\n\nPaste below configurations to your `init.vim` or `.vimrc`\n\n- Remap for do codeAction of selected region\n\n  ``` vim\n  vmap <leader>a <Plug>(coc-codeaction-selected)\n  nmap <leader>a <Plug>(coc-codeaction-selected)\n  ```\n\nThen positioning the cursor in the word, any of the following should\ndisplay the list of suggestions:\n\n- `<leader>aap` for current paragraph\n- `<leader>aw` for current word\n\nOr use the [coc-actions](https://github.com/iamcco/coc-actions)\n\n![image](https://user-images.githubusercontent.com/5492542/71774253-78717700-2fa6-11ea-9629-1e88d0b5114e.png)\n\n## Install\n\n`:CocInstall coc-spell-checker`\n\n### Commands and Configurations\n\n- [commands](https://github.com/iamcco/coc-spell-checker/blob/master/package.json#L30)\n- [configurations](https://github.com/iamcco/coc-spell-checker/blob/master/package.json#L125)\n\n## Supported Languages\n\n- English (US)\n- English (GB) - turn on by changing `\"cSpell.language\": \"en\"` to\n`\"cSpell.language\": \"en-GB\"`\n\n## Add-On Dictionaries\n\n- [catalan](https://github.com/iamcco/coc-cspell-dicts)\n- [czech](https://github.com/iamcco/coc-cspell-dicts)\n- [danish](https://github.com/iamcco/coc-cspell-dicts)\n- [dutch](https://github.com/iamcco/coc-cspell-dicts)\n- [french](https://github.com/iamcco/coc-cspell-dicts)\n- [french-reforme](https://github.com/iamcco/coc-cspell-dicts)\n- [german](https://github.com/iamcco/coc-cspell-dicts)\n- [greek](https://github.com/iamcco/coc-cspell-dicts)\n- [italian](https://github.com/iamcco/coc-cspell-dicts)\n- [persian](https://github.com/iamcco/coc-cspell-dicts)\n- [polish](https://github.com/iamcco/coc-cspell-dicts)\n- [portuguese](https://github.com/iamcco/coc-cspell-dicts)\n- [portuguese-brazilian](https://github.com/iamcco/coc-cspell-dicts)\n- [russian](https://github.com/iamcco/coc-cspell-dicts)\n- [spanish](https://github.com/iamcco/coc-cspell-dicts)\n- [swedish](https://github.com/iamcco/coc-cspell-dicts)\n- [turkish](https://github.com/iamcco/coc-cspell-dicts)\n- [ukrainian](https://github.com/iamcco/coc-cspell-dicts)\n- [medical-terms](https://github.com/iamcco/coc-cspell-dicts)\n\n## Enabled File Types\n\n- vim\n- AsciiDoc\n- C, C++\n- C#\n- css, less, scss\n- Elixir\n- Go\n- Html\n- Java\n- JavaScript\n- JSON / JSONC\n- LaTex\n- Markdown\n- PHP\n- PowerShell\n- Pug / Jade\n- Python\n- reStructuredText\n- Rust\n- Scala\n- Text\n- TypeScript\n- YAML\n\n## How it works with camelCase\n\nThe concept is simple, split camelCase words before checking them against\na list of known English words.\n\n- camelCase -> camel case\n- HTMLInput -> html input -- Notice that the `I` is associated with `Input` and not `HTML`\n- snake_case_words -> snake case words\n- camel2snake -> camel snake -- (the 2 is ignored)\n\n### Special case will ALL CAPS words\n\nThere are a few special cases to help will common spelling practices for\nALL CAPS words.\n\nTrailing `s`, `ing`, `ies`, `es`, `ed` are kept with the previous word.\n\n- CURLs -> curls -- trailing `s`\n- CURLedRequest -> curled request -- trailing `ed`\n\n## Things to note\n\n- This spellchecker is case insensitive.  It will not catch errors like\nenglish which should be English.\n- The spellchecker uses a local word dictionary.  It does not send anything\noutside your machine.\n- The words in the dictionary can and do contain errors.\n- There are missing words.\n- Only words longer than 3 characters are checked.  \"jsj\" is ok, while \"jsja\"\nis not.\n- All symbols and punctuation are ignored.\n\n## In Document Settings\n\nIt is possible to add spell check settings into your source code.\nThis is to help with file specific issues that may not be applicable to the\nentire project.\n\nAll settings are prefixed with `cSpell:` or `spell-checker:`.\n\n- `disable` -- turn off the spell checker for a section of code.\n- `enable` -- turn the spell checker back on after it has been turned off.\n- `ignore` -- specify a list of words to be ignored.\n- `words` -- specify a list of words to be considered correct and will appear\nin the suggestions list.\n- `ignoreRegExp` -- Any text matching the regular expression will NOT be checked\nfor spelling.\n- `includeRegExp` -- Only text matching the collection of includeRegExp will be checked.\n- `enableCompoundWords` / `disableCompoundWords` -- Allow / disallow words\nlike: \"stringlength\".\n\n### Enable / Disable checking sections of code\n\nIt is possible to disable / enable the spell checker by adding comments to your code.\n\n#### Disable Checking\n\n- `/* cSpell:disable */`\n- `/* spell-checker: disable */`\n- `/* spellchecker: disable */`\n- `/* cspell: disable-line */`\n- `/* cspell: disable-next-line */`\n\n#### Enable Checking\n\n- `/* cSpell:enable */`\n- `/* spell-checker: enable */`\n- `/* spellchecker: enable */`\n\n#### Example\n\n``` javascript\n\n// cSpell:disable\nconst wackyWord = ['zaallano', 'wooorrdd', 'zzooommmmmmmm'];\n/* cSpell:enable */\n\n// Nest disable / enable is not Supported\n\n// spell-checker:disable\n// It is now disabled.\n\nvar liep = 1;\n\n/* cspell:disable */\n// It is still disabled\n\n// cSpell:enable\n// It is now enabled\n\nconst str = \"goededag\";  // <- will be flagged as an error.\n\n// spell-checker:enable <- doesn't do anything\n\n// cSPELL:DISABLE <-- also works.\n\n// if there isn't an enable, spelling is disabled till the end of the file.\nconst str = \"goedemorgen\";  // <- will NOT be flagged as an error.\n\n```\n<!--- cSpell:enable -->\n\n### Ignore\n\nIgnore allows you the specify a list of words you want to ignore within the document.\n\n```javascript\n// cSpell:ignore zaallano, wooorrdd\n// cSpell:ignore zzooommmmmmmm\nconst wackyWord = ['zaallano', 'wooorrdd', 'zzooommmmmmmm'];\n```\n\n**Note:** words defined with `ignore` will be ignored for the entire file.\n\n### Words\n\nThe words list allows you to add words that will be considered correct and will be used as suggestions.\n\n```javascript\n// cSpell:words woorxs sweeetbeat\nconst companyName = 'woorxs sweeetbeat';\n```\n\n**Note:** words defined with `words` will be used for the entire file.\n\n### Enable / Disable compound words\n\nIn some programing language it is common to glue words together.\n\n```c\n// cSpell:enableCompoundWords\nchar * errormessage;  // Is ok with cSpell:enableCompoundWords\nint    errornumber;   // Is also ok.\n```\n\n**Note:** Compound word checking cannot be turned on / off in the same file.\nThe last setting in the file determines the value for the entire file.\n\n### Excluding and Including Text to be checked.\n\nBy default, the entire document is checked for spelling.\n`cSpell:disable`/`cSpell:enable` above allows you to block off sections of the document.\n`ignoreRegExp` and `includeRegExp` give you the ability to ignore or include patterns of text.\nBy default the flags `gim` are added if no flags are given.\n\nThe spell checker works in the following way:\n\n1. Find all text matching `includeRegExp`\n2. Remove any text matching `excludeRegExp`\n3. Check the remaining text.\n\n#### Exclude Example\n\n```javascript\n// cSpell:ignoreRegExp 0x[0-9a-f]+     -- will ignore c style hex numbers\n// cSpell:ignoreRegExp /0x[0-9A-F]+/g  -- will ignore upper case c style hex numbers.\n// cSpell:ignoreRegExp g{5} h{5}       -- will only match ggggg, but not hhhhh or 'ggggg hhhhh'\n// cSpell:ignoreRegExp g{5}|h{5}       -- will match both ggggg and hhhhh\n// cSpell:ignoreRegExp /g{5} h{5}/     -- will match 'ggggg hhhhh'\n/* cSpell:ignoreRegExp /n{5}/          -- will NOT work as expected because of the ending comment -> */\n/*\n   cSpell:ignoreRegExp /q{5}/          -- will match qqqqq just fine but NOT QQQQQ\n*/\n// cSpell:ignoreRegExp /[^\\s]{40,}/    -- will ignore long strings with no spaces.\n// cSpell:ignoreRegExp Email           -- this will ignore email like patterns -- see Predefined RegExp expressions\nvar encodedImage = 'HR+cPzr7XGAOJNurPL0G8I2kU0UhKcqFssoKvFTR7z0T3VJfK37vS025uKroHfJ9nA6WWbHZ/ASn...';\nvar email1 = 'emailaddress@myfancynewcompany.com';\nvar email2 = '<emailaddress@myfancynewcompany.com>';\n```\n\n**Note:** ignoreRegExp and includeRegExp are applied to the entire file.  They do not start and stop.\n\n#### Include Example\n\nIn general you should not need to use `includeRegExp`. But if you are mixing languages then it could come in helpful.\n\n```Python\n# cSpell:includeRegExp #.*\n# cSpell:includeRegExp (\"\"\"|''')[^\\1]*\\1\n# only comments and block strings will be checked for spelling.\ndef sum_it(self, seq):\n    \"\"\"This is checked for spelling\"\"\"\n    variabele = 0\n    alinea = 'this is not checked'\n    for num in seq:\n        # The local state of 'value' will be retained between iterations\n        variabele += num\n        yield variabele\n```\n\n\n## Predefined RegExp expressions\n\n### Exclude patterns\n* `Urls`<sup>1</sup> -- Matches urls\n* `HexDigits` -- Matches hex digits: `/^x?[0-1a-f]+$/i`\n* `HexValues` -- Matches common hex format like #aaa, 0xfeef, \\\\u0134\n* `EscapeCharacters`<sup>1</sup> -- matches special characters: '\\\\n', '\\\\t' etc.\n* `Base64`<sup>1</sup> -- matches base64 blocks of text longer than 40 characters.\n* `Email` -- matches most email addresses.\n\n### Include Patterns\n* `Everything`<sup>1</sup> -- By default we match an entire document and remove the excludes.\n* `string` -- This matches common string formats like '...', \"...\", and \\`...\\`\n* `CStyleComment` -- These are C Style comments /* */ and //\n* `PhpHereDoc` -- This matches PHPHereDoc strings.\n\n<sup>1.</sup> These patterns are part of the default include/exclude list for every file.\n\n## Customization\n\n### Adding words to the Workspace Dictionary\n\nYou have the option to add you own words to the workspace dictionary.  The easiest,\nis to put your cursor on the word you wish to add, hit `<leader>aw`  You will get a list\nof suggestions and the option to add the word.\n\nYou can also type in a word you want to add to the dictionary: `:CocCommand cSpell.addWordToDictionary`\nand type in the word you wish to add.\n\n### cSpell.json\n\nWords added to the dictionary are placed in the `cSpell.json` file in the `.vim` folder found in the _workspace_.\nNote, the settings in cSpell.json will override the equivalent cSpell settings in settings.json.\n\n#### Example _cSpell.json_ file\n```javascript\n// cSpell Settings\n{\n    // Version of the setting file.  Always 0.1\n    \"version\": \"0.1\",\n    // language - current active spelling language\n    \"language\": \"en\",\n    // words - list of words to be always considered correct\n    \"words\": [\n        \"mkdirp\",\n        \"tsmerge\",\n        \"githubusercontent\",\n        \"streetsidesoftware\",\n        \"vsmarketplacebadge\",\n        \"visualstudio\"\n    ],\n    // flagWords - list of words to be always considered incorrect\n    // This is useful for offensive words and common spelling errors.\n    // For example \"hte\" should be \"the\"\n    \"flagWords\": [\n        \"hte\"\n    ]\n}\n```\n\n### Configuration Settings\n\n```javascript\n    //-------- Code Spell Checker Configuration --------\n    // The Language local to use when spell checking. \"en\" and \"en-GB\" are currently supported.\n    \"cSpell.language\": \"en\",\n\n    // Controls the maximum number of spelling errors per document.\n    \"cSpell.maxNumberOfProblems\": 100,\n\n    // Controls the number of suggestions shown.\n    \"cSpell.numSuggestions\": 8,\n\n    // The minimum length of a word before checking it against a dictionary.\n    \"cSpell.minWordLength\": 4,\n\n    // Specify file types to spell check.\n    \"cSpell.enabledLanguageIds\": [\n        \"csharp\",\n        \"go\",\n        \"javascript\",\n        \"javascriptreact\",\n        \"markdown\",\n        \"php\",\n        \"plaintext\",\n        \"typescript\",\n        \"typescriptreact\",\n        \"yml\"\n    ],\n\n    // Enable / Disable the spell checker.\n    \"cSpell.enabled\": true,\n\n    // Display the spell checker status on the status bar.\n    \"cSpell.showStatus\": true,\n\n    // Words to add to dictionary for a workspace.\n    \"cSpell.words\": [],\n\n    // Enable / Disable compound words like 'errormessage'\n    \"cSpell.allowCompoundWords\": false,\n\n    // Words to be ignored and not suggested.\n    \"cSpell.ignoreWords\": [\"behaviour\"],\n\n    // User words to add to dictionary.  Should only be in the user settings.\n    \"cSpell.userWords\": [],\n\n    // Specify paths/files to ignore.\n    \"cSpell.ignorePaths\": [\n        \"node_modules\",        // this will ignore anything the node_modules directory\n        \"**/node_modules\",     // the same for this one\n        \"**/node_modules/**\",  // the same for this one\n        \"node_modules/**\",     // Doesn't currently work due to how the current working directory is determined.\n        \"vscode-extension\",    //\n        \".git\",                // Ignore the .git directory\n        \"*.dll\",               // Ignore all .dll files.\n        \"**/*.dll\"             // Ignore all .dll files\n    ],\n\n    // flagWords - list of words to be always considered incorrect\n    // This is useful for offensive words and common spelling errors.\n    // For example \"hte\" should be \"the\"`\n    \"cSpell.flagWords\": [\"hte\"],\n\n    // Set the delay before spell checking the document. Default is 50.\n    \"cSpell.spellCheckDelayMs\": 50,\n```\n\n## Dictionaries\n\nThe spell checker includes a set of default dictionaries.\n\n### General Dictionaries\n\n- **wordsEn** - Derived from Hunspell US English words.\n- **wordsEnGb** - Derived from Hunspell GB English words.\n- **companies** - List of well known companies\n- **softwareTerms** - Software Terms and concepts like \"coroutine\", \"debounce\", \"tree\", etc.\n- **misc** - Terms that do not belong in the other dictionaries.\n\n### Programming Language Dictionaries\n\n- **typescript** - keywords for Typescript and Javascript\n- **node** - terms related to using nodejs.\n- **php** - *php* keywords and library methods\n- **go** - *go* keywords and library methods\n- **python** - *python* keywords\n- **powershell** - *powershell* keywords\n- **html** - *html* related keywords\n- **css** - *css*, *less*, and *scss* related keywords\n\n### Miscellaneous Dictionaries\n\n- **fonts** - long list of fonts - to assist with *css*\n\nBased upon the programming language, different dictionaries will be loaded.\n\nHere are the default rules: \"*\" matches any language.\n`\"local\"` is used to filter based upon the `\"cSpell.language\"` setting.\n\n``` javascript\n{\n\"cSpell.languageSettings\": [\n    { \"languageId\": '*',      \"local\": 'en',               \"dictionaries\": ['wordsEn'] },\n    { \"languageId\": '*',      \"local\": 'en-US',            \"dictionaries\": ['wordsEn'] },\n    { \"languageId\": '*',      \"local\": 'en-GB',            \"dictionaries\": ['wordsEnGb'] },\n    { \"languageId\": '*',                                   \"dictionaries\": ['companies', 'softwareTerms', 'misc'] },\n    { \"languageId\": \"python\", \"allowCompoundWords\": true,  \"dictionaries\": [\"python\"]},\n    { \"languageId\": \"go\",     \"allowCompoundWords\": true,  \"dictionaries\": [\"go\"] },\n    { \"languageId\": \"javascript\",                          \"dictionaries\": [\"typescript\", \"node\"] },\n    { \"languageId\": \"javascriptreact\",                     \"dictionaries\": [\"typescript\", \"node\"] },\n    { \"languageId\": \"typescript\",                          \"dictionaries\": [\"typescript\", \"node\"] },\n    { \"languageId\": \"typescriptreact\",                     \"dictionaries\": [\"typescript\", \"node\"] },\n    { \"languageId\": \"html\",                                \"dictionaries\": [\"html\", \"fonts\", \"typescript\", \"css\"] },\n    { \"languageId\": \"php\",                                 \"dictionaries\": [\"php\", \"html\", \"fonts\", \"css\", \"typescript\"] },\n    { \"languageId\": \"css\",                                 \"dictionaries\": [\"fonts\", \"css\"] },\n    { \"languageId\": \"less\",                                \"dictionaries\": [\"fonts\", \"css\"] },\n    { \"languageId\": \"scss\",                                \"dictionaries\": [\"fonts\", \"css\"] },\n];\n}\n```\n\n### How to add your own Dictionaries\n\n#### Global Dictionary\n\nTo add a global dictionary, you will need change your user settings.\n\n##### Define the Dictionary\n\nIn your user settings, you will need to tell the spell checker where to find your word list.\n\nExample adding medical terms, so words like *acanthopterygious* can be found.\n\n```javascript\n// A List of Dictionary Definitions.\n\"cSpell.dictionaryDefinitions\": [\n    { \"name\": \"medicalTerms\", \"path\": \"/Users/guest/projects/cSpell-WordLists/dictionaries/medicalterms-en.txt\"}\n],\n// List of dictionaries to use when checking files.\n\"cSpell.dictionaries\": [\n    \"medicalTerms\"\n]\n```\n\n**Explained:** In this example, we have told the spell checker where to find the word list file.\nSince it is in the user settings, we have to use absolute paths.\n\nOnce the dictionary is defined. We need to tell the spell checker when to use it.\nAdding it to `cSpell.dictionaries` advises the spell checker to always include the medical terms when spell checking.\n\n**Note:** Adding large dictionary files to be always used will slow down the generation of suggestions.\n\n#### Project / Workspace Dictionary\n\nTo add a dictionary at the project level, it needs to be in the **cSpell.json** file.\nThis file can be either at the project root or in the .vim directory.\n\nExample adding medical terms, where the terms are checked into the project and we only want to use it for .md files.\n```javascript\n{\n    \"dictionaryDefinitions\": [\n        { \"name\": \"medicalTerms\", \"path\": \"./dictionaries/medicalterms-en.txt\"},\n        { \"name\": \"cities\", \"path\": \"./dictionaries/cities.txt\"}\n    ],\n    \"dictionaries\": [\n        \"cities\"\n    ],\n    \"languageSettings\": [\n        { \"languageId\": \"markdown\", \"dictionaries\": [\"medicalTerms\"] },\n        { \"languageId\": \"plaintext\", \"dictionaries\": [\"medicalTerms\"] }\n    ]\n}\n```\n\n**Explained:** In this example, two dictionaries were defined: *cities* and *medicalTerms*.\nThe paths are relative to the location of the *cSpell.json* file.  This allows for dictionaries to be checked into the project.\n\nThe *cities* dictionary is used for every file type, because it was added to the list to *dictionaries*.\nThe *medicalTerms* dictionary is only used when editing *markdown* or *plaintext* files.\n\n## FAQ\n\nSee: [FAQ](https://github.com/iamcco/coc-spell-checker/blob/master/FAQ.md)\n\n### Buy Me A Coffee ☕️\n\n![btc](https://img.shields.io/keybase/btc/iamcco.svg?style=popout-square)\n\n![image](https://user-images.githubusercontent.com/5492542/42771079-962216b0-8958-11e8-81c0-520363ce1059.png)\n"
  },
  {
    "path": "cspell.code-snippets",
    "content": "{\n  \"words\": {\n    \"prefix\": \"spell words\",\n      \"scope\": \"\",\n      \"body\": \"${LINE_COMMENT} cspell:words ${1:word} ${2:word}\",\n      \"description\": \"Words to be allowed in the document\"\n  },\n  \"ignore\": {\n    \"prefix\": \"spell ignore words\",\n    \"scope\": \"\",\n    \"body\": \"${LINE_COMMENT} cspell:ignore ${1:word} ${2:word}\",\n    \"description\": \"Words to be ignored in the document\"\n  },\n  \"ignore regexp\": {\n    \"prefix\": \"spell ignore regexp\",\n    \"scope\": \"\",\n    \"body\": \"${LINE_COMMENT} cspell:ignoreRegExp /${1:expression}/\",\n    \"description\": \"Ignore text matching the regular expression.\"\n  },\n  \"disable next line\": {\n    \"prefix\": \"spell disable next line\",\n    \"scope\": \"\",\n    \"body\": \"${LINE_COMMENT} cspell:disable-next-line\",\n    \"description\": \"Do not spell check the next line\"\n  },\n  \"disable current line\": {\n    \"prefix\": \"spell disable line\",\n    \"scope\": \"\",\n    \"body\": \"${LINE_COMMENT} cspell:disable-line\",\n    \"description\": \"Do not spell check the current line\"\n  },\n  \"disable spell checker\": {\n    \"prefix\": \"spell disable spell checker\",\n    \"scope\": \"\",\n    \"body\": \"${LINE_COMMENT} cspell:disable\",\n    \"description\": \"Disable spell checking from this point further.\"\n  },\n  \"enable spell checker\": {\n    \"prefix\": \"spell enable spell checker\",\n    \"scope\": \"\",\n    \"body\": \"${LINE_COMMENT} cspell:enable\",\n    \"description\": \"Enable spell checking from this point further.\"\n  }\n}\n"
  },
  {
    "path": "dicts/README.md",
    "content": "# Dict bundle with extensions\n"
  },
  {
    "path": "dicts/vim/CHANGELOG.md",
    "content": "# Change Log\n\n- add vim help tag\n"
  },
  {
    "path": "dicts/vim/README.md",
    "content": "# Cspell Vim Language Dictionary\n\nVim Language dictionary for cspell.\n\nThis is a pre-built dictionary for use with cspell.\n\nSupports keywords of (Neo)vim\n\nThis dictionary is included by default in cSpell.\n\n## Installation\n\nGlobal Install and add to cspell global settings.\n\n```sh\nnpm install -g cspell-dict-vimlang\ncspell-dict-vimlang-link\n```\n\n## Uninstall from cspell\n\n```sh\ncspell-dict-vimlang-unlink\n```\n\n## Manual Installation\n\nThe `cspell-ext.json` file in this package should be added to the import section in your cspell.json file.\n\n```javascript\n{\n    // …\n    \"import\": [\"<path to node_modules>/cspell-dict-vimlang/cspell-ext.json\"],\n    // …\n}\n```\n\n## Building\n\nI's only necessary if you want to modify the contents of the dictionary.\nNote: Building will take a few minutes for large files.\n\n```sh\nnpm run build\n```\n"
  },
  {
    "path": "dicts/vim/build-dict.js",
    "content": "#!/usr/bin/env node\n\nconst {join} = require(\"path\")\nconst {existsSync, readFileSync, writeFileSync} = require(\"fs\")\n\nconst doc = process.argv.slice(2)\n\nif (doc.length === 0) {\n  console.log('do not have files');\n  return\n}\n\nconst dict = new Set()\n\ndoc.forEach(rtp => {\n  const tagPath = join(rtp, 'doc', 'tags')\n  if (existsSync(tagPath)) {\n    const tags = readFileSync(tagPath).toString().split('\\n')\n    tags.forEach(line => {\n      line = line.trim()\n      firstSection = line.split(' ')[0]\n      // delete first `xxxx:`\n      firstSection = firstSection.replace(/^[^:]:/, '')\n      const words = firstSection.split(/[^a-zA-Z]/g)\n      words.forEach(word => {\n        word = word.replace(/[^a-zA-Z]/g, '')\n        if (word.length > 2) {\n          dict.add(word)\n        }\n      })\n    })\n  } else {\n    console.log(`file ${tagPath} does not exists`)\n  }\n})\n\nlet content = ''\n\nfor (let word of dict) {\n  if (content !== '') {\n    content += ('\\n' + word)\n  } else {\n    content = word\n  }\n}\n\nconsole.log(`write to ${join(__dirname, 'vim.txt')}`);\n\nwriteFileSync(join(__dirname, 'vim.txt'), content)\n"
  },
  {
    "path": "dicts/vim/cspell-ext.json",
    "content": "// cSpell Settings\n{\n    \"id\": \"vimlang\",\n    \"name\": \"vim script Language\",\n    \"description\": \"Go Language Dictionary\",\n    // List of dictionary files to add to the global list of dictionaries\n    \"dictionaryDefinitions\": [\n        {\n            \"name\": \"vimlang\",\n            \"file\": \"./vim.txt.gz\",\n            \"description\": \"Vim Script Language Dictionary\"\n        }\n    ],\n    // Dictionaries to always be used.\n    // Generally left empty\n    \"dictionaries\": [],\n    // Language Rules to apply to matching files.\n    // Files are matched on `languageId` and `local`\n    \"languageSettings\": [\n        {\n            // VSCode languageId. i.e. typescript, java, go, cpp, javascript, markdown, latex\n            // * will match against any file type.\n            \"languageId\": \"vim\",\n            // Language local. i.e. en-US, de-AT, or ru. * will match all locals.\n            // Multiple locals can be specified like: \"en, en-US\" to match both English and English US.\n            \"local\": \"*\",\n            // It is common in vim to glue words together.\n            \"allowCompoundWords\": true,\n            // By default the whole text of a file is included for spell checking\n            // Adding patterns to the \"includeRegExpList\" to only include matching patterns\n            \"includeRegExpList\": [],\n            // To exclude patterns, add them to \"ignoreRegExpList\"\n            \"ignoreRegExpList\": [],\n            // regex patterns than can be used with ignoreRegExpList or includeRegExpList\n            // Example: \"pattern\": [{ \"name\": \"mdash\", \"pattern\": \"&mdash;\" }]\n            // This could be included in \"ignoreRegExpList\": [\"mdash\"]\n            \"patterns\": [],\n            // List of dictionaries to enable by name in `dictionaryDefinitions`\n            \"dictionaries\": [\"vimlang\"],\n            // Dictionary definitions can also be supplied here. They are only used iff \"languageId\" and \"local\" match.\n            \"dictionaryDefinitions\": []\n        }\n    ]\n}\n"
  },
  {
    "path": "dicts/vim/index.d.ts",
    "content": "export function getConfigLocation(): string;\n"
  },
  {
    "path": "dicts/vim/index.js",
    "content": "'use strict';\n\nvar util = require('./util');\n\nfunction getConfigLocation() {\n    return util.configLocation;\n}\n\nmodule.exports = {\n  getConfigLocation,\n};\n"
  },
  {
    "path": "dicts/vim/link.js",
    "content": "#!/usr/bin/env node\n\n'use strict';\n\nvar util = require('./util');\n\nutil.install();\n\n"
  },
  {
    "path": "dicts/vim/package.json",
    "content": "{\n  \"name\": \"cspell-dict-vimlang\",\n  \"version\": \"1.0.1\",\n  \"description\": \"Vim Language dictionary for cspell.\",\n  \"bin\": {\n    \"cspell-dict-vimlang-link\": \"./link.js\",\n    \"cspell-dict-vimlang-unlink\": \"./unlink.js\"\n  },\n  \"scripts\": {\n    \"build\": \"./node_modules/.bin/cspell-tools compile \\\"vim.txt\\\" -o .\",\n    \"test\": \"head -n 100 \\\"vim.txt\\\" | cspell -v -c ./cspell-ext.json --local=* --languageId=vim stdin\",\n    \"cspell-link\": \"node link.js\",\n    \"cspell-unlink\": \"node unlink.js\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/iamcco/coc-spell-checker.git\"\n  },\n  \"keywords\": [\n    \"cspell\",\n    \"vimlang\",\n    \"vim script language\",\n    \"dictionary\",\n    \"spelling\"\n  ],\n  \"main\": \"index.js\",\n  \"typings\": \"index.d.ts\",\n  \"author\": \"iamcco <ooiss@qq.com>\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/streetsidesoftware/cspell-dicts/issues\"\n  },\n  \"homepage\": \"https://github.com/iamcco/coc-spell-checker/packages/README.md\",\n  \"devDependcies\": {\n    \"cspell-tools\": \"*\"\n  },\n  \"dependencies\": {\n    \"configstore\": \"^5.0.0\"\n  },\n  \"files\": [\n    \"vim.txt.gz\",\n    \"cspell-ext.json\",\n    \"*.js\",\n    \"*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "dicts/vim/unlink.js",
    "content": "#!/usr/bin/env node\n\n'use strict';\n\nvar util = require('./util');\n\nutil.uninstall();\n"
  },
  {
    "path": "dicts/vim/util.js",
    "content": "'use strict';\n\n// Cspell:word configstore\nvar Configstore = require('configstore');\nvar Path = require('path');\n\nvar packageName = 'cspell';\nvar importPath = 'import';\nvar configLocation = Path.join(__dirname, 'cspell-ext.json');\n\nfunction getImports(conf) {\n  var imports = conf.get(importPath);\n\n  imports = imports || [];\n  if (typeof imports === 'string') {\n    imports = [imports];\n  }\n\n  return imports;\n}\n\nfunction install() {\n  var conf = new Configstore(packageName);\n  /** @type {string[]|string|undefined} */\n\n  var imports = getImports(conf);\n  if (imports.indexOf(configLocation) < 0) {\n    imports.push(configLocation);\n    conf.set(importPath, imports);\n  }\n}\n\nfunction uninstall() {\n  var conf = new Configstore(packageName);\n  /** @type {string[]|string|undefined} */\n  var imports = getImports(conf);\n\n  var index = imports.indexOf(configLocation);\n\n  if (index >= 0) {\n    imports.splice(index, 1);\n    conf.set(importPath, imports);\n  }\n}\n\nmodule.exports = {\n  install,\n  uninstall,\n  configLocation,\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"coc-spell-checker\",\n  \"description\": \"Spelling checker for source code\",\n  \"keywords\": [\n    \"coc.nvim\",\n    \"spell\",\n    \"checker\",\n    \"spellchecker\",\n    \"multi-root ready\"\n  ],\n  \"license\": \"MIT\",\n  \"version\": \"1.3.2\",\n  \"publisher\": \"iamcco\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/iamcco/coc-spell-checker\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/iamcco/coc-spell-checker/issues\"\n  },\n  \"homepage\": \"https://github.com/iamcco/coc-spell-checker\",\n  \"engines\": {\n    \"coc\": \"^0.0.74\"\n  },\n  \"activationEvents\": [\n    \"*\"\n  ],\n  \"main\": \"./out/index.js\",\n  \"contributes\": {\n    \"commands\": [\n      {\n        \"command\": \"cSpell.addWordToWorkspaceDictionary\",\n        \"title\": \"Add Word to Workspace Dictionary\"\n      },\n      {\n        \"command\": \"cSpell.addWordToDictionary\",\n        \"title\": \"Add Word to Folder Dictionary\"\n      },\n      {\n        \"command\": \"cSpell.addWordToUserDictionary\",\n        \"title\": \"Add Word to User Dictionary\"\n      },\n      {\n        \"command\": \"cSpell.enableForWorkspace\",\n        \"title\": \"Enable Spell Checking For Workspace\"\n      },\n      {\n        \"command\": \"cSpell.disableForWorkspace\",\n        \"title\": \"Disable Spell Checking For Workspace\"\n      },\n      {\n        \"command\": \"cSpell.enableLanguage\",\n        \"title\": \"Enable Spell Checking For Specify Document Language\"\n      },\n      {\n        \"command\": \"cSpell.disableLanguage\",\n        \"title\": \"Disable Spell Checking For Specify Document Language\"\n      },\n      {\n        \"command\": \"cSpell.enableCurrentLanguage\",\n        \"title\": \"Enable Spell Checking Document Language\"\n      },\n      {\n        \"command\": \"cSpell.disableCurrentLanguage\",\n        \"title\": \"Disable Spell Checking Document Language\"\n      },\n      {\n        \"command\": \"cSpell.toggleEnableSpellChecker\",\n        \"title\": \"Toggle Spell Checking For the Current Workspace\"\n      },\n      {\n        \"command\": \"cSpell.removeWordFromFolderDictionary\",\n        \"title\": \"Remove Words from the Folder Dictionary\"\n      },\n      {\n        \"command\": \"cSpell.removeWordFromWorkspaceDictionary\",\n        \"title\": \"Remove Words from the Workspace Dictionary\"\n      },\n      {\n        \"command\": \"cSpell.removeWordFromUserDictionary\",\n        \"title\": \"Remove Words from the Global Dictionary\"\n      },\n      {\n        \"command\": \"cSpell.addIgnoreWord\",\n        \"title\": \"Ignore Word\"\n      },\n      {\n        \"command\": \"cSpell.addIgnoreWordToFolder\",\n        \"title\": \"Ignore Word in Folder Settings\"\n      },\n      {\n        \"command\": \"cSpell.addIgnoreWordToWorkspace\",\n        \"title\": \"Ignore Word in Workspace Settings\"\n      },\n      {\n        \"command\": \"cSpell.addIgnoreWordToUser\",\n        \"title\": \"Ignore Word in User Settings\"\n      }\n    ],\n    \"languages\": [\n      {\n        \"id\": \"jsonc\",\n        \"extensions\": [\n          \"cspell-ext.json\",\n          \"cspell-default.json\",\n          \"cspell.json\",\n          \"cSpell.json\"\n        ]\n      }\n    ],\n    \"jsonValidation\": [\n      {\n        \"fileMatch\": \"cSpell.json\",\n        \"url\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/cspell%404.0.47/cspell.schema.json\"\n      },\n      {\n        \"fileMatch\": \"cspell.json\",\n        \"url\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/cspell%404.0.47/cspell.schema.json\"\n      },\n      {\n        \"fileMatch\": \"cspell-default.json\",\n        \"url\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/cspell%404.0.47/cspell.schema.json\"\n      },\n      {\n        \"fileMatch\": \"cspell-ext.json\",\n        \"url\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/cspell%404.0.47/cspell.schema.json\"\n      }\n    ],\n    \"configuration\": {\n      \"type\": \"object\",\n      \"title\": \"Code Spell Checker Configuration\",\n      \"properties\": {\n        \"cSpell.trace.server\": {\n          \"type\": \"string\",\n          \"default\": \"off\",\n          \"enum\": [\n            \"off\",\n            \"messages\",\n            \"verbose\"\n          ],\n          \"description\": \"Trace level of log\"\n        },\n        \"cSpell.language\": {\n          \"type\": \"string\",\n          \"scope\": \"resource\",\n          \"default\": \"en\",\n          \"description\": \"The Language local to use when spell checking. \\\"en\\\" and \\\"en-GB\\\" are currently supported.\"\n        },\n        \"cSpell.maxNumberOfProblems\": {\n          \"type\": \"number\",\n          \"scope\": \"resource\",\n          \"default\": 100,\n          \"description\": \"Controls the maximum number of spelling errors per document.\"\n        },\n        \"cSpell.checkLimit\": {\n          \"type\": \"number\",\n          \"scope\": \"resource\",\n          \"default\": 500,\n          \"description\": \"The limit in K-Bytes to be checked in a file.\"\n        },\n        \"cSpell.numSuggestions\": {\n          \"type\": \"number\",\n          \"scope\": \"resource\",\n          \"default\": 8,\n          \"description\": \"Controls the number of suggestions shown.\"\n        },\n        \"cSpell.minWordLength\": {\n          \"type\": \"number\",\n          \"scope\": \"resource\",\n          \"default\": 4,\n          \"description\": \"The minimum length of a word before checking it against a dictionary.\"\n        },\n        \"cSpell.maxDuplicateProblems\": {\n          \"type\": \"number\",\n          \"scope\": \"resource\",\n          \"default\": 5,\n          \"description\": \"The maximum number of times the same word can be flagged as an error in a file.\"\n        },\n        \"cSpell.enabledLanguageIds\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [\n            \"vim\",\n            \"asciidoc\",\n            \"c\",\n            \"cpp\",\n            \"csharp\",\n            \"css\",\n            \"git-commit\",\n            \"gitcommit\",\n            \"go\",\n            \"handlebars\",\n            \"haskell\",\n            \"html\",\n            \"jade\",\n            \"java\",\n            \"javascript\",\n            \"javascriptreact\",\n            \"json\",\n            \"jsonc\",\n            \"latex\",\n            \"less\",\n            \"markdown\",\n            \"php\",\n            \"plaintext\",\n            \"python\",\n            \"pug\",\n            \"restructuredtext\",\n            \"rust\",\n            \"scala\",\n            \"scss\",\n            \"text\",\n            \"typescript\",\n            \"typescriptreact\",\n            \"yaml\",\n            \"yml\"\n          ],\n          \"description\": \"Specify file types to spell check.\"\n        },\n        \"cSpell.import\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [],\n          \"description\": \"List of paths of cspell.json files to import.\"\n        },\n        \"cSpell.words\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [],\n          \"description\": \"Words to add to dictionary for a workspace.\"\n        },\n        \"cSpell.userWords\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [],\n          \"description\": \"User words to add to dictionary.  Should only be in the user settings.\"\n        },\n        \"cSpell.ignoreWords\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [],\n          \"description\": \"A list of words to be ignored by the spell checker.\"\n        },\n        \"cSpell.enabled\": {\n          \"type\": \"boolean\",\n          \"scope\": \"resource\",\n          \"default\": true,\n          \"description\": \"Enable / Disable the spell checker.\"\n        },\n        \"cSpell.diagnosticLevel\": {\n          \"type\": \"string\",\n          \"scope\": \"resource\",\n          \"enum\": [\n            \"Error\",\n            \"Warning\",\n            \"Information\",\n            \"Hint\"\n          ],\n          \"default\": \"Information\",\n          \"description\": \"Issues found by the spell checker are marked with a Diagnostic Severity Level. This affects the color of squiggle.\"\n        },\n        \"cSpell.showStatus\": {\n          \"type\": \"boolean\",\n          \"scope\": \"resource\",\n          \"default\": true,\n          \"description\": \"Display the spell checker status on the status bar.\"\n        },\n        \"cSpell.spellCheckDelayMs\": {\n          \"type\": \"number\",\n          \"default\": 50,\n          \"description\": \"Delay in ms after a document has changed before checking it for spelling errors.\"\n        },\n        \"cSpell.ignorePaths\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [\n            \"**/package-lock.json\",\n            \"**/node_modules/**\",\n            \"**/vscode-extension/**\",\n            \"**/.git/objects/**\",\n            \".vscode\"\n          ],\n          \"description\": \"Specify paths/files to ignore. (Supports Globs)\"\n        },\n        \"cSpell.flagWords\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [],\n          \"description\": \"Words to always be flagged as an error.\"\n        },\n        \"cSpell.patterns\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"name\": {\n                \"type\": \"string\",\n                \"description\": \"The pattern identifier.\"\n              },\n              \"pattern\": {\n                \"type\": \"string\",\n                \"description\": \"Regular expression, default flags are: 'gim'\"\n              }\n            },\n            \"description\": \"Define a pattern\"\n          },\n          \"default\": [],\n          \"description\": \"Defines a list of named regular expression patterns that can be used in exclusion or inclusion lists.\"\n        },\n        \"cSpell.ignoreRegExpList\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [],\n          \"description\": \"List of regular expressions used to exclude the matching text from being checked.\\n Example: \\\"0x[a-f0-9]+\\\" to skip 0x hex values.\\n By default the flags are 'gim'.\\n You can specify them like this:\\n \\\"/0x[A-F0-9]/g\\\" to match only upper case hex numbers.\\n Example to match email: \\\"<?[\\\\\\\\w.\\\\\\\\-+]+@\\\\\\\\w+(\\\\\\\\.\\\\\\\\w+)+>?\\\" \"\n        },\n        \"cSpell.includeRegExpList\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [],\n          \"description\": \"List of regular expressions used to include text to be spell checked.\\nBy default, all text is checked.  Adding regular expresses to this list will limit the text to be spell checked to only text that matches any of the expressions in the list.\\nLogic: text to be checked = include - exclude\\nNote: Slashes need to be double: \\\\\\\\ because it is in a json string. \\nExamples:\\n* \\\".*\\\" -- include everything.\\n* \\\"'(?:[^'\\\\\\\\n]|\\\\\\\\\\\\\\\\')*'\\\" -- single quote strings. \\n\"\n        },\n        \"cSpell.allowCompoundWords\": {\n          \"type\": \"boolean\",\n          \"scope\": \"resource\",\n          \"default\": false,\n          \"description\": \"Enable / Disable allowing word compounds. true means 'arraylength' would be ok, false means it would not pass.\"\n        },\n        \"cSpell.languageSettings\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"description\": \"Define settings on a per programming language basis.\",\n          \"items\": {\n            \"$ref\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/cspell%404.0.47/cspell.schema.json#/definitions/LanguageSetting\"\n          }\n        },\n        \"cSpell.dictionaries\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"description\": \"List of dictionaries to use when checking files.\",\n          \"items\": {\n            \"type\": \"string\",\n            \"description\": \"Name of dictionary to use.\"\n          }\n        },\n        \"cSpell.dictionaryDefinitions\": {\n          \"type\": \"array\",\n          \"scope\": \"resource\",\n          \"description\": \"A List of Dictionary Definitions.\",\n          \"items\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"name\": {\n                \"type\": \"string\",\n                \"description\": \"Name of dictionary\"\n              },\n              \"path\": {\n                \"type\": \"string\",\n                \"description\": \"Path to the dictionary file. Relative paths will be relative to the workspace.\"\n              }\n            },\n            \"required\": [\n              \"name\",\n              \"path\"\n            ]\n          }\n        },\n        \"cSpell.showCommandsInEditorContextMenu\": {\n          \"type\": \"boolean\",\n          \"scope\": \"application\",\n          \"description\": \"Show Spell Checker actions in Editor Context Menu\",\n          \"default\": true\n        },\n        \"cSpell.fixSpellingWithRenameProvider\": {\n          \"type\": \"boolean\",\n          \"scope\": \"application\",\n          \"description\": \"Experimental: Use Rename when fixing spelling issues.\",\n          \"default\": false\n        },\n        \"cSpell.logLevel\": {\n          \"type\": \"string\",\n          \"scope\": \"window\",\n          \"description\": \"Set the Debug Level for logging messages.\",\n          \"enum\": [\n            \"None\",\n            \"Error\",\n            \"Warning\",\n            \"Information\",\n            \"Debug\"\n          ],\n          \"default\": \"Error\"\n        },\n        \"cSpell.allowedSchemas\": {\n          \"type\": \"array\",\n          \"scope\": \"window\",\n          \"description\": \"Control which file schemas will be checked for spelling (VS Code must be restarted for this setting to take effect).\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"default\": [\n            \"file\",\n            \"untitled\"\n          ]\n        },\n        \"cSpell.overrides\": {\n          \"type\": \"array\",\n          \"description\": \"Overrides to apply based upon the file path.\",\n          \"items\": {\n            \"$ref\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/cspell%404.0.47/cspell.schema.json#/definitions/OverrideSettings\"\n          }\n        },\n        \"cSpell.status-bar-text\": {\n          \"type\": \"string\",\n          \"description\": \"Text show in status bar, default cSpell\",\n          \"default\": \"cSpell\"\n        }\n      }\n    }\n  },\n  \"scripts\": {\n    \"clean\": \"rm -rf ./out\",\n    \"clean:server\": \"rm -rf ./server\",\n    \"clean:all\": \"npm-run-all clean:server clean\",\n    \"build\": \"webpack\",\n    \"build:server\": \"git clone https://github.com/streetsidesoftware/vscode-spell-checker && cd vscode-spell-checker/packages/_server && yarn && yarn compile && mv ../client/server ../../../ && cd ../../../ && rm -rf vscode-spell-checker\",\n    \"build:all\": \"npm-run-all build:server build\",\n    \"prepublishOnly\": \"npm-run-all clean:all build:all\",\n    \"prepare\": \"npm-run-all clean build\"\n  },\n  \"devDependencies\": {\n    \"@types/comment-json\": \"^1.1.1\",\n    \"@types/fs-extra\": \"^8.1.0\",\n    \"@types/node\": \"^12.12.27\",\n    \"coc.nvim\": \"^0.0.74\",\n    \"lorem-ipsum\": \"^1.0.6\",\n    \"npm-run-all\": \"4.1.5\",\n    \"rimraf\": \"^3.0.2\",\n    \"ts-loader\": \"^6.2.1\",\n    \"tslint\": \"^5.20.1\",\n    \"typescript\": \"^3.7.5\",\n    \"vscode-languageserver-protocol\": \"^3.14.1\",\n    \"webpack\": \"^4.41.6\",\n    \"webpack-cli\": \"^3.3.11\"\n  },\n  \"dependencies\": {\n    \"comment-json\": \"^1.1.3\",\n    \"cspell-dict-vimlang\": \"^1.0.1\",\n    \"cspell-glob\": \"^0.1.17\",\n    \"cspell-lib\": \"^4.1.16\",\n    \"fs-extra\": \"^8.1.0\",\n    \"gensequence\": \"^2.3.0\",\n    \"iconv-lite\": \"^0.4.24\",\n    \"micromatch\": \"^4.0.2\",\n    \"minimatch\": \"^3.0.4\",\n    \"node-watch\": \"^0.6.3\",\n    \"rxjs\": \"^6.5.4\",\n    \"vscode-jsonrpc\": \"^4.0.0\",\n    \"vscode-languageserver\": \"^5.2.1\",\n    \"vscode-uri\": \"^2.1.1\"\n  }\n}\n"
  },
  {
    "path": "server/SuggestionsGenerator.d.ts",
    "content": "import { CSpellUserSettings } from './cspellConfig';\nimport { SuggestionResult } from 'cspell-lib';\nimport { SpellingDictionaryCollection } from 'cspell-lib/dist/SpellingDictionary';\nexport declare const maxWordLengthForSuggestions = 20;\nexport declare const wordLengthForLimitingSuggestions = 15;\nexport declare const maxNumberOfSuggestionsForLongWords = 1;\nexport interface GetSettingsResult {\n    settings: CSpellUserSettings;\n    dictionary: SpellingDictionaryCollection;\n}\nexport declare class SuggestionGenerator<DocInfo> {\n    readonly getSettings: (doc: DocInfo) => GetSettingsResult | Promise<GetSettingsResult>;\n    constructor(getSettings: (doc: DocInfo) => GetSettingsResult | Promise<GetSettingsResult>);\n    genSuggestions(doc: DocInfo, word: string): Promise<SuggestionResult[]>;\n    genWordSuggestions(doc: DocInfo, word: string): Promise<string[]>;\n}\n"
  },
  {
    "path": "server/SuggestionsGenerator.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst cspell_lib_1 = require(\"cspell-lib\");\nconst defaultNumSuggestions = 10;\nconst regexJoinedWords = /[+]/g;\nexports.maxWordLengthForSuggestions = 20;\nexports.wordLengthForLimitingSuggestions = 15;\nexports.maxNumberOfSuggestionsForLongWords = 1;\nconst maxEdits = 3;\nclass SuggestionGenerator {\n    constructor(getSettings) {\n        this.getSettings = getSettings;\n    }\n    async genSuggestions(doc, word) {\n        const { settings, dictionary } = await this.getSettings(doc);\n        const { numSuggestions = defaultNumSuggestions } = settings;\n        if (word.length > exports.maxWordLengthForSuggestions) {\n            return [];\n        }\n        const numSugs = word.length > exports.wordLengthForLimitingSuggestions ? exports.maxNumberOfSuggestionsForLongWords : numSuggestions;\n        const options = {\n            numChanges: maxEdits,\n            numSuggestions: numSugs,\n            // Turn off compound suggestions for now until it works a bit better.\n            compoundMethod: cspell_lib_1.CompoundWordsMethod.NONE,\n            ignoreCase: !settings.caseSensitive,\n        };\n        return dictionary.suggest(word, options).map(s => (Object.assign(Object.assign({}, s), { word: s.word.replace(regexJoinedWords, '') })));\n    }\n    async genWordSuggestions(doc, word) {\n        return (await this.genSuggestions(doc, word)).map(sr => sr.word);\n    }\n}\nexports.SuggestionGenerator = SuggestionGenerator;\n//# sourceMappingURL=SuggestionsGenerator.js.map"
  },
  {
    "path": "server/SuggestionsGenerator.test.d.ts",
    "content": "export {};\n"
  },
  {
    "path": "server/SuggestionsGenerator.test.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst cspell = require(\"cspell-lib\");\nconst SuggestionsGenerator_1 = require(\"./SuggestionsGenerator\");\ndescribe('Validate Suggestions', () => {\n    test('genWordSuggestions', async () => {\n        const gen = new SuggestionsGenerator_1.SuggestionGenerator(getSettings);\n        const doc = { languageId: 'typescript', text: '' };\n        const { settings } = await getSettings(doc);\n        const result = await gen.genWordSuggestions(doc, 'code');\n        expect(result).toContain('code');\n        expect(result).toHaveLength(settings.numSuggestions || 0);\n    });\n    test('genWordSuggestions for long words', async () => {\n        const gen = new SuggestionsGenerator_1.SuggestionGenerator(getSettings);\n        const doc = { languageId: 'typescript', text: '' };\n        const result = await gen.genWordSuggestions(doc, 'Acknowledgements');\n        expect(result).toHaveLength(SuggestionsGenerator_1.maxNumberOfSuggestionsForLongWords);\n        expect(result).toContain('acknowledgements');\n    });\n    async function getSettings(doc) {\n        const settings = await cspell.constructSettingsForText(cspell.getDefaultSettings(), doc.text || '', doc.languageId);\n        const dictionary = await cspell.getDictionary(settings);\n        return { settings, dictionary };\n    }\n});\n//# sourceMappingURL=SuggestionsGenerator.test.js.map"
  },
  {
    "path": "server/api.d.ts",
    "content": "import * as config from './cspellConfig';\nexport interface GetConfigurationForDocumentResult {\n    languageEnabled: boolean | undefined;\n    fileEnabled: boolean | undefined;\n    settings: config.CSpellUserSettings | undefined;\n    docSettings: config.CSpellUserSettings | undefined;\n}\nexport interface IsSpellCheckEnabledResult {\n    languageEnabled: boolean | undefined;\n    fileEnabled: boolean | undefined;\n}\nexport interface SplitTextIntoWordsResult {\n    words: string[];\n}\nexport interface SpellingSuggestionsResult {\n}\nexport interface TextDocumentInfo {\n    uri?: string;\n    languageId?: string;\n    text?: string;\n}\nexport declare type ServerRequestMethods = keyof ServerMethodRequestResult;\nexport declare type ServerRequestMethodConstants = {\n    [key in ServerRequestMethods]: key;\n};\ndeclare type ServerRequestResult<Req, Res> = {\n    request: Req;\n    result: Res;\n};\nexport declare type ServerMethodRequestResult = {\n    getConfigurationForDocument: ServerRequestResult<TextDocumentInfo, GetConfigurationForDocumentResult>;\n    isSpellCheckEnabled: ServerRequestResult<TextDocumentInfo, IsSpellCheckEnabledResult>;\n    splitTextIntoWords: ServerRequestResult<string, SplitTextIntoWordsResult>;\n    spellingSuggestions: ServerRequestResult<TextDocumentInfo, SpellingSuggestionsResult>;\n};\nexport declare type ServerRequestMethodResults = {\n    [key in keyof ServerMethodRequestResult]: ServerMethodRequestResult[key]['result'];\n};\nexport declare type ServerRequestMethodRequests = {\n    [key in keyof ServerMethodRequestResult]: ServerMethodRequestResult[key]['request'];\n};\nexport declare type NotifyServerMethods = 'onConfigChange' | 'registerConfigurationFile';\nexport declare type NotifyServerMethodConstants = {\n    [key in NotifyServerMethods]: NotifyServerMethods;\n};\nexport {};\n"
  },
  {
    "path": "server/api.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=api.js.map"
  },
  {
    "path": "server/autoLoad.d.ts",
    "content": "export interface AutoLoadCache<K, T> {\n    (key: K): T;\n    get: (key: K) => T;\n    clear: () => void;\n    has: (key: K) => boolean;\n    delete: (key: K) => void;\n}\nexport declare function createAutoLoadCache<K, T>(loader: (key: K) => T): AutoLoadCache<K, T>;\nexport interface LazyValue<T> {\n    (): T;\n    get: () => T;\n    clear: () => void;\n}\nexport declare function createLazyValue<T>(loader: () => T): LazyValue<T>;\n"
  },
  {
    "path": "server/autoLoad.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nfunction createAutoLoadCache(loader) {\n    const cache = new Map();\n    const getter = ((key) => {\n        const found = cache.get(key);\n        if (found)\n            return found;\n        const value = loader(key);\n        cache.set(key, value);\n        return value;\n    });\n    getter.get = getter;\n    getter.has = (key) => cache.has(key);\n    getter.delete = (key) => cache.delete(key);\n    getter.clear = () => cache.clear();\n    return getter;\n}\nexports.createAutoLoadCache = createAutoLoadCache;\nconst notSet = Symbol('Value Not Set');\nfunction createLazyValue(loader) {\n    let v = notSet;\n    const getter = (() => {\n        if (v === notSet) {\n            v = loader();\n        }\n        return v;\n    });\n    getter.clear = () => v = notSet;\n    getter.get = getter;\n    return getter;\n}\nexports.createLazyValue = createLazyValue;\n//# sourceMappingURL=autoLoad.js.map"
  },
  {
    "path": "server/autoLoad.test.d.ts",
    "content": "export {};\n"
  },
  {
    "path": "server/autoLoad.test.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst autoLoad_1 = require(\"./autoLoad\");\ndescribe('Validate AutoLoadCache', () => {\n    test('create', () => {\n        let n = 0;\n        const loader = (key) => key + n++;\n        const cache = autoLoad_1.createAutoLoadCache(loader);\n        expect(cache(5)).toEqual(5 + n - 1);\n        expect(n).toEqual(1);\n        expect(cache.has(5)).toBe(true);\n        expect(cache.has(4)).toBe(false);\n        expect(cache(4)).toEqual(4 + n - 1);\n        expect(n).toEqual(2);\n        expect(cache(5)).toEqual(5 + n - 2);\n        expect(n).toEqual(2);\n        cache.delete(5);\n        expect(cache(5)).toEqual(5 + n - 1);\n        expect(n).toEqual(3);\n        cache.clear();\n        expect(cache).toEqual(cache.get);\n    });\n});\ndescribe('Validate LazyValue', () => {\n    test('', () => {\n        let n = 0;\n        const loader = () => n++;\n        const value = autoLoad_1.createLazyValue(loader);\n        expect(n).toEqual(0);\n        expect(value()).toEqual(0);\n        expect(value()).toEqual(0);\n        value.clear();\n        expect(value()).toEqual(1);\n    });\n});\n//# sourceMappingURL=autoLoad.test.js.map"
  },
  {
    "path": "server/codeActions.d.ts",
    "content": "import { TextDocument, TextDocuments, CodeActionParams } from 'vscode-languageserver';\nimport { CodeAction } from 'vscode-languageserver-types';\nimport { CSpellUserSettings } from './cspellConfig';\nimport { DocumentSettings } from './documentSettings';\nexport declare function onCodeActionHandler(documents: TextDocuments, fnSettings: (doc: TextDocument) => Promise<CSpellUserSettings>, fnSettingsVersion: (doc: TextDocument) => number, documentSettings: DocumentSettings): (params: CodeActionParams) => Promise<CodeAction[]>;\n"
  },
  {
    "path": "server/codeActions.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst LangServer = require(\"vscode-languageserver\");\nconst cspell_lib_1 = require(\"cspell-lib\");\nconst Validator = require(\"./validator\");\nconst cspell = require(\"cspell-lib\");\nconst documentSettings_1 = require(\"./documentSettings\");\nconst SuggestionsGenerator_1 = require(\"./SuggestionsGenerator\");\nconst util_1 = require(\"./util\");\nfunction extractText(textDocument, range) {\n    const { start, end } = range;\n    const offStart = textDocument.offsetAt(start);\n    const offEnd = textDocument.offsetAt(end);\n    return textDocument.getText().slice(offStart, offEnd);\n}\nfunction onCodeActionHandler(documents, fnSettings, fnSettingsVersion, documentSettings) {\n    const sugGen = new SuggestionsGenerator_1.SuggestionGenerator(getSettings);\n    const settingsCache = new Map();\n    async function getSettings(doc) {\n        const cached = settingsCache.get(doc.uri);\n        const settingsVersion = fnSettingsVersion(doc);\n        if (!cached || cached.docVersion !== doc.version || cached.settingsVersion !== settingsVersion) {\n            const settings = constructSettings(doc);\n            settingsCache.set(doc.uri, { docVersion: doc.version, settings, settingsVersion });\n        }\n        return settingsCache.get(doc.uri).settings;\n    }\n    async function constructSettings(doc) {\n        const settings = cspell.constructSettingsForText(await fnSettings(doc), doc.getText(), doc.languageId);\n        const dictionary = await cspell.getDictionary(settings);\n        return { settings, dictionary };\n    }\n    const handler = async (params) => {\n        const actions = [];\n        const { context, textDocument: { uri } } = params;\n        const { diagnostics } = context;\n        const spellCheckerDiags = diagnostics.filter(diag => diag.source === Validator.diagSource);\n        if (!spellCheckerDiags.length)\n            return [];\n        const optionalTextDocument = documents.get(uri);\n        if (!optionalTextDocument)\n            return [];\n        util_1.log(`CodeAction Only: ${context.only} Num: ${diagnostics.length}`, uri);\n        const textDocument = optionalTextDocument;\n        const { settings: docSetting, dictionary } = await getSettings(textDocument);\n        if (!documentSettings_1.isUriAllowed(uri, docSetting.allowedSchemas)) {\n            util_1.log(`CodeAction Uri Not allowed: ${uri}`);\n            return [];\n        }\n        const folders = await documentSettings.folders;\n        const showAddToWorkspace = folders && folders.length > 1;\n        const showAddToFolder = folders && folders.length > 0;\n        function replaceText(range, text) {\n            return LangServer.TextEdit.replace(range, text || '');\n        }\n        function getSuggestions(word) {\n            return sugGen.genWordSuggestions(textDocument, word);\n        }\n        function createAction(title, command, diags, ...args) {\n            const cmd = LangServer.Command.create(title, command, ...args);\n            const action = LangServer.CodeAction.create(title, cmd);\n            action.diagnostics = diags;\n            action.kind = LangServer.CodeActionKind.QuickFix;\n            return action;\n        }\n        async function genCodeActionsForSuggestions(_dictionary) {\n            util_1.log('CodeAction generate suggestions');\n            let diagWord;\n            for (const diag of spellCheckerDiags) {\n                const word = extractText(textDocument, diag.range);\n                diagWord = diagWord || word;\n                const sugs = await getSuggestions(word);\n                sugs\n                    .map(sug => cspell_lib_1.Text.isLowerCase(sug) ? cspell_lib_1.Text.matchCase(word, sug) : sug)\n                    .filter(util_1.uniqueFilter())\n                    .forEach(sugWord => {\n                    const action = createAction(sugWord, 'cSpell.editText', [diag], uri, textDocument.version, [replaceText(diag.range, sugWord)]);\n                    /**\n                      * Waiting on [Add isPreferred to the CodeAction protocol. Pull Request #489 · Microsoft/vscode-languageserver-node](https://github.com/Microsoft/vscode-languageserver-node/pull/489)\n                      * Note we might want this to be a config setting incase someone has `\"editor.codeActionsOnSave\": { \"source.fixAll\": true }`\n                      * if (!actions.length) {\n                      *     action.isPreferred = true;\n                      * }\n                      */\n                    actions.push(action);\n                });\n            }\n            const word = diagWord || extractText(textDocument, params.range);\n            // Only suggest adding if it is our diagnostic and there is a word.\n            if (word && spellCheckerDiags.length) {\n                actions.push(createAction('Add: \"' + word + '\" to user dictionary', 'cSpell.addWordToUserDictionarySilent', spellCheckerDiags, word, textDocument.uri));\n                if (showAddToFolder) {\n                    // Allow the them to add it to the project dictionary.\n                    actions.push(createAction('Add: \"' + word + '\" to folder dictionary', 'cSpell.addWordToDictionarySilent', spellCheckerDiags, word, textDocument.uri));\n                }\n                if (showAddToWorkspace) {\n                    // Allow the them to add it to the workspace dictionary.\n                    actions.push(createAction('Add: \"' + word + '\" to workspace dictionary', 'cSpell.addWordToWorkspaceDictionarySilent', spellCheckerDiags, word, textDocument.uri));\n                }\n            }\n            return actions;\n        }\n        return genCodeActionsForSuggestions(dictionary);\n    };\n    return handler;\n}\nexports.onCodeActionHandler = onCodeActionHandler;\n//# sourceMappingURL=codeActions.js.map"
  },
  {
    "path": "server/cspellConfig.d.ts",
    "content": "import * as cspell from 'cspell-lib';\nexport { LanguageSetting, DictionaryDefinition } from 'cspell-lib';\nexport interface SpellCheckerSettings {\n    checkLimit?: number;\n    diagnosticLevel?: string;\n    allowedSchemas?: string[];\n    logLevel?: 'None' | 'Error' | 'Warning' | 'Information' | 'Debug';\n    showStatus?: boolean;\n    spellCheckDelayMs?: number;\n    showCommandsInEditorContextMenu?: boolean;\n}\nexport interface CSpellUserSettingsWithComments extends cspell.CSpellUserSettingsWithComments, SpellCheckerSettings {\n}\nexport interface CSpellUserSettings extends cspell.CSpellSettings, SpellCheckerSettings {\n}\n"
  },
  {
    "path": "server/cspellConfig.js",
    "content": "\"use strict\";\n// Export the cspell settings to the client.\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=cspellConfig.js.map"
  },
  {
    "path": "server/documentSettings.d.ts",
    "content": "import { Connection, TextDocumentUri } from './vscode.config';\nimport * as vscode from 'vscode-languageserver';\nimport { ExcludeFilesGlobMap, RegExpPatternDefinition, Pattern } from 'cspell-lib';\nimport { CSpellUserSettings } from './cspellConfig';\nimport { AutoLoadCache } from './autoLoad';\nexport interface SettingsCspell {\n    cSpell?: CSpellUserSettings;\n}\nexport interface SettingsVSCode {\n    search?: {\n        exclude?: ExcludeFilesGlobMap;\n    };\n}\nexport declare class DocumentSettings {\n    readonly connection: Connection;\n    readonly defaultSettings: CSpellUserSettings;\n    private cachedValues;\n    readonly getUriSettings: AutoLoadCache<string | undefined, Promise<CSpellUserSettings>>;\n    private readonly fetchSettingsForUri;\n    private readonly _cspellFileSettingsByFolderCache;\n    private readonly fetchVSCodeConfiguration;\n    private readonly _folders;\n    readonly configsToImport: Set<string>;\n    private readonly importedSettings;\n    private _version;\n    constructor(connection: Connection, defaultSettings: CSpellUserSettings);\n    getSettings(document: TextDocumentUri): Promise<CSpellUserSettings>;\n    _getUriSettings(uri: string): Promise<CSpellUserSettings>;\n    isExcluded(uri: string): Promise<boolean>;\n    resetSettings(): void;\n    get folders(): Promise<vscode.WorkspaceFolder[]>;\n    private _importSettings;\n    get version(): number;\n    registerConfigurationFile(path: string): void;\n    private fetchUriSettings;\n    private findMatchingFolder;\n    private fetchFolders;\n    private _fetchVSCodeConfiguration;\n    private fetchSettingsFromVSCode;\n    private _fetchSettingsForUri;\n    private matchingFoldersForUri;\n    private createCache;\n    private createLazy;\n    private readSettingsForFolderUri;\n}\ndeclare function resolvePath(...parts: string[]): string;\nexport declare function isUriAllowed(uri: string, schemes?: string[]): boolean;\nexport declare function isUriBlackListed(uri: string, schemes?: string[]): boolean;\nexport declare function doesUriMatchAnyScheme(uri: string, schemes: string[]): boolean;\ndeclare function fixRegEx(pat: Pattern): Pattern;\ndeclare function fixPattern(pat: RegExpPatternDefinition): RegExpPatternDefinition;\nexport declare function correctBadSettings(settings: CSpellUserSettings): CSpellUserSettings;\nexport declare const debugExports: {\n    fixRegEx: typeof fixRegEx;\n    fixPattern: typeof fixPattern;\n    resolvePath: typeof resolvePath;\n};\nexport {};\n"
  },
  {
    "path": "server/documentSettings.js",
    "content": "\"use strict\";\nvar __rest = (this && this.__rest) || function (s, e) {\n    var t = {};\n    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n        t[p] = s[p];\n    if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n                t[p[i]] = s[p[i]];\n        }\n    return t;\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\n// cSpell:ignore pycache\nconst vscode_config_1 = require(\"./vscode.config\");\nconst path = require(\"path\");\nconst fs = require(\"fs-extra\");\nconst CSpell = require(\"cspell-lib\");\nconst vscode_uri_1 = require(\"vscode-uri\");\nconst util_1 = require(\"./util\");\nconst autoLoad_1 = require(\"./autoLoad\");\nconst cspell_glob_1 = require(\"cspell-glob\");\nconst os = require(\"os\");\nconst cSpellSection = 'cSpell';\nconst defaultExclude = [\n    '**/*.rendered',\n    '**/*.*.rendered',\n    '__pycache__/**',\n];\nconst defaultAllowedSchemes = ['file', 'untitled'];\nconst schemeBlackList = ['git', 'output', 'debug', 'vscode'];\nconst defaultRootUri = vscode_uri_1.URI.file('').toString();\nclass DocumentSettings {\n    constructor(connection, defaultSettings) {\n        this.connection = connection;\n        this.defaultSettings = defaultSettings;\n        // Cache per folder settings\n        this.cachedValues = [];\n        this.getUriSettings = this.createCache((key = '') => this._getUriSettings(key));\n        this.fetchSettingsForUri = this.createCache((key) => this._fetchSettingsForUri(key));\n        this._cspellFileSettingsByFolderCache = this.createCache(_readSettingsForFolderUri);\n        this.fetchVSCodeConfiguration = this.createCache((key) => this._fetchVSCodeConfiguration(key));\n        this._folders = this.createLazy(() => this.fetchFolders());\n        this.configsToImport = new Set();\n        this.importedSettings = this.createLazy(() => this._importSettings());\n        this._version = 0;\n    }\n    async getSettings(document) {\n        return this.getUriSettings(document.uri);\n    }\n    async _getUriSettings(uri) {\n        util_1.log('getUriSettings:', uri);\n        const r = uri\n            ? await this.fetchUriSettings(uri)\n            : CSpell.mergeSettings(this.defaultSettings, this.importedSettings());\n        return r;\n    }\n    async isExcluded(uri) {\n        const settings = await this.fetchSettingsForUri(uri);\n        return settings.globMatcher.match(vscode_uri_1.URI.parse(uri).path);\n    }\n    resetSettings() {\n        util_1.log('resetSettings');\n        CSpell.clearCachedSettings();\n        this.cachedValues.forEach(cache => cache.clear());\n        this._version += 1;\n    }\n    get folders() {\n        return this._folders();\n    }\n    _importSettings() {\n        util_1.log('importSettings');\n        const importPaths = [...this.configsToImport.keys()].sort();\n        return readSettingsFiles(importPaths);\n    }\n    get version() {\n        return this._version;\n    }\n    registerConfigurationFile(path) {\n        util_1.log('registerConfigurationFile:', path);\n        this.configsToImport.add(path);\n        this.importedSettings.clear();\n        this.resetSettings();\n    }\n    async fetchUriSettings(uri) {\n        util_1.log('Start fetchUriSettings:', uri);\n        const folderSettings = await this.fetchSettingsForUri(uri);\n        const spellSettings = CSpell.mergeSettings(this.defaultSettings, this.importedSettings(), folderSettings.settings);\n        const fileUri = vscode_uri_1.URI.parse(uri);\n        const fileSettings = CSpell.calcOverrideSettings(spellSettings, fileUri.fsPath);\n        util_1.log('Finish fetchUriSettings:', uri);\n        return fileSettings;\n    }\n    async findMatchingFolder(docUri) {\n        const root = vscode_uri_1.URI.parse(docUri || defaultRootUri).with({ path: '' });\n        return (await this.matchingFoldersForUri(docUri))[0] || { uri: root.toString(), name: 'root' };\n    }\n    async fetchFolders() {\n        return (await vscode_config_1.getWorkspaceFolders(this.connection)) || [];\n    }\n    async _fetchVSCodeConfiguration(uri) {\n        return (await vscode_config_1.getConfiguration(this.connection, [\n            { scopeUri: uri || undefined, section: cSpellSection },\n            { section: 'search' }\n        ])).map(v => v || {});\n    }\n    async fetchSettingsFromVSCode(uri) {\n        const configs = await this.fetchVSCodeConfiguration(uri || '');\n        const [cSpell, search] = configs;\n        const { exclude = {} } = search;\n        const { ignorePaths = [] } = cSpell;\n        const cSpellConfigSettings = Object.assign(Object.assign({}, cSpell), { id: 'VSCode-Config', ignorePaths: ignorePaths.concat(CSpell.ExclusionHelper.extractGlobsFromExcludeFilesGlobMap(exclude)) });\n        return cSpellConfigSettings;\n    }\n    async _fetchSettingsForUri(uri) {\n        util_1.log(`fetchFolderSettings: URI ${uri}`);\n        const cSpellConfigSettings = await this.fetchSettingsFromVSCode(uri);\n        const folder = await this.findMatchingFolder(uri);\n        const cSpellFolderSettings = resolveConfigImports(cSpellConfigSettings, folder.uri);\n        const settings = this.readSettingsForFolderUri(folder.uri);\n        // cspell.json file settings take precedence over the vscode settings.\n        const mergedSettings = CSpell.mergeSettings(cSpellFolderSettings, settings);\n        const { ignorePaths = [] } = mergedSettings;\n        const globs = defaultExclude.concat(ignorePaths);\n        const root = vscode_uri_1.URI.parse(folder.uri).path;\n        const globMatcher = new cspell_glob_1.GlobMatcher(globs, root);\n        const ext = {\n            uri,\n            vscodeSettings: { cSpell: cSpellConfigSettings },\n            settings: mergedSettings,\n            globMatcher,\n        };\n        return ext;\n    }\n    async matchingFoldersForUri(docUri) {\n        const folders = await this.folders;\n        return folders\n            .filter(({ uri }) => uri === docUri.slice(0, uri.length))\n            .sort((a, b) => a.uri.length - b.uri.length)\n            .reverse();\n    }\n    createCache(loader) {\n        const cache = autoLoad_1.createAutoLoadCache(loader);\n        this.cachedValues.push(cache);\n        return cache;\n    }\n    createLazy(loader) {\n        const lazy = autoLoad_1.createLazyValue(loader);\n        this.cachedValues.push(lazy);\n        return lazy;\n    }\n    readSettingsForFolderUri(folderUri) {\n        return this._cspellFileSettingsByFolderCache.get(folderUri);\n    }\n}\nexports.DocumentSettings = DocumentSettings;\nfunction configPathsForRoot(workspaceRootUri) {\n    const workspaceRoot = workspaceRootUri ? vscode_uri_1.URI.parse(workspaceRootUri).fsPath : '';\n    const paths = workspaceRoot ? [\n        path.join(workspaceRoot, '.vscode', CSpell.defaultSettingsFilename.toLowerCase()),\n        path.join(workspaceRoot, '.vscode', CSpell.defaultSettingsFilename),\n        path.join(workspaceRoot, '.' + CSpell.defaultSettingsFilename.toLowerCase()),\n        path.join(workspaceRoot, CSpell.defaultSettingsFilename.toLowerCase()),\n        path.join(workspaceRoot, CSpell.defaultSettingsFilename),\n    ] : [];\n    return paths;\n}\nfunction resolveConfigImports(config, folderUri) {\n    util_1.log('resolveConfigImports:', folderUri);\n    const uriFsPath = vscode_uri_1.URI.parse(folderUri).fsPath;\n    const imports = typeof config.import === 'string' ? [config.import] : config.import || [];\n    const importAbsPath = imports.map(file => resolvePath(uriFsPath, file));\n    util_1.log(`resolvingConfigImports: [\\n${imports.join('\\n')}]`);\n    util_1.log(`resolvingConfigImports ABS: [\\n${importAbsPath.join('\\n')}]`);\n    const _a = importAbsPath.length\n        ? CSpell.mergeSettings(readSettingsFiles([...importAbsPath]), config)\n        : config, { import: _import } = _a, result = __rest(_a, [\"import\"]);\n    return result;\n}\nfunction _readSettingsForFolderUri(folderUri) {\n    return folderUri ? readSettingsFiles(configPathsForRoot(folderUri)) : {};\n}\nfunction readSettingsFiles(paths) {\n    util_1.log('readSettingsFiles:', paths);\n    const existingPaths = paths.filter(filename => exists(filename));\n    util_1.log('readSettingsFiles actual:', existingPaths);\n    return existingPaths.length ? CSpell.readSettingsFiles(existingPaths) : {};\n}\nfunction exists(file) {\n    try {\n        const s = fs.statSync(file);\n        return s.isFile();\n    }\n    catch (e) { }\n    return false;\n}\nfunction resolvePath(...parts) {\n    const normalizedParts = parts.map(part => part[0] === '~' ? os.homedir() + part.slice(1) : part);\n    return path.resolve(...normalizedParts);\n}\nfunction isUriAllowed(uri, schemes) {\n    schemes = schemes || defaultAllowedSchemes;\n    return doesUriMatchAnyScheme(uri, schemes);\n}\nexports.isUriAllowed = isUriAllowed;\nfunction isUriBlackListed(uri, schemes = schemeBlackList) {\n    return doesUriMatchAnyScheme(uri, schemes);\n}\nexports.isUriBlackListed = isUriBlackListed;\nfunction doesUriMatchAnyScheme(uri, schemes) {\n    const schema = vscode_uri_1.URI.parse(uri).scheme;\n    return schemes.findIndex(v => v === schema) >= 0;\n}\nexports.doesUriMatchAnyScheme = doesUriMatchAnyScheme;\nconst correctRegExMap = new Map([\n    ['/\"\"\"(.*?\\\\n?)+?\"\"\"/g', '/(\"\"\")[^\\\\1]*?\\\\1/g'],\n    [\"/'''(.*?\\\\n?)+?'''/g\", \"/(''')[^\\\\1]*?\\\\1/g\"],\n]);\nfunction fixRegEx(pat) {\n    if (typeof pat != 'string') {\n        return pat;\n    }\n    return correctRegExMap.get(pat) || pat;\n}\nfunction fixPattern(pat) {\n    const pattern = fixRegEx(pat.pattern);\n    if (pattern === pat.pattern) {\n        return pat;\n    }\n    return Object.assign(Object.assign({}, pat), { pattern });\n}\nfunction correctBadSettings(settings) {\n    var _a, _b, _c, _d, _e, _f;\n    const newSettings = Object.assign({}, settings);\n    // Fix patterns\n    newSettings.patterns = (_b = (_a = newSettings) === null || _a === void 0 ? void 0 : _a.patterns) === null || _b === void 0 ? void 0 : _b.map(fixPattern);\n    newSettings.ignoreRegExpList = (_d = (_c = newSettings) === null || _c === void 0 ? void 0 : _c.ignoreRegExpList) === null || _d === void 0 ? void 0 : _d.map(fixRegEx);\n    newSettings.includeRegExpList = (_f = (_e = newSettings) === null || _e === void 0 ? void 0 : _e.includeRegExpList) === null || _f === void 0 ? void 0 : _f.map(fixRegEx);\n    return newSettings;\n}\nexports.correctBadSettings = correctBadSettings;\nexports.debugExports = {\n    fixRegEx,\n    fixPattern,\n    resolvePath,\n};\n//# sourceMappingURL=documentSettings.js.map"
  },
  {
    "path": "server/documentSettings.test.d.ts",
    "content": "export {};\n"
  },
  {
    "path": "server/documentSettings.test.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst documentSettings_1 = require(\"./documentSettings\");\nconst vscode_config_1 = require(\"./vscode.config\");\nconst Path = require(\"path\");\nconst vscode_uri_1 = require(\"vscode-uri\");\nconst cspell = require(\"cspell-lib\");\nconst os = require(\"os\");\njest.mock('vscode-languageserver');\njest.mock('./vscode.config');\njest.mock('./util');\nconst mockGetWorkspaceFolders = vscode_config_1.getWorkspaceFolders;\nconst mockGetConfiguration = vscode_config_1.getConfiguration;\nconst workspaceRoot = Path.resolve(Path.join(__dirname, '..'));\nconst workspaceFolder = {\n    uri: vscode_uri_1.URI.file(workspaceRoot).toString(),\n    name: '_server',\n};\ndescribe('Validate DocumentSettings', () => {\n    beforeEach(() => {\n        // Clear all mock instances and calls to constructor and all methods:\n        mockGetWorkspaceFolders.mockClear();\n    });\n    test('version', () => {\n        const docSettings = newDocumentSettings();\n        expect(docSettings.version).toEqual(0);\n        docSettings.resetSettings();\n        expect(docSettings.version).toEqual(1);\n    });\n    it('checks isUriAllowed', () => {\n        expect(documentSettings_1.isUriAllowed(vscode_uri_1.URI.file(__filename).toString())).toBe(true);\n    });\n    it('checks isUriBlackListed', () => {\n        const uriFile = vscode_uri_1.URI.file(__filename);\n        expect(documentSettings_1.isUriBlackListed(uriFile.toString())).toBe(false);\n        const uriGit = uriFile.with({ scheme: 'debug' });\n        expect(documentSettings_1.isUriBlackListed(uriGit.toString())).toBe(true);\n    });\n    it('folders', async () => {\n        const mockFolders = [workspaceFolder];\n        mockGetWorkspaceFolders.mockReturnValue(mockFolders);\n        const docSettings = newDocumentSettings();\n        const folders = await docSettings.folders;\n        expect(folders).toBe(mockFolders);\n    });\n    it('tests register config path', () => {\n        const mockFolders = [workspaceFolder];\n        mockGetWorkspaceFolders.mockReturnValue(mockFolders);\n        const docSettings = newDocumentSettings();\n        const configFile = Path.resolve(Path.join(__dirname, '..', '..', '..', 'cSpell.json'));\n        expect(docSettings.version).toEqual(0);\n        docSettings.registerConfigurationFile(configFile);\n        expect(docSettings.version).toEqual(1);\n        expect(docSettings.configsToImport).toContain(configFile);\n    });\n    it('test getSettings', async () => {\n        const mockFolders = [workspaceFolder];\n        mockGetWorkspaceFolders.mockReturnValue(mockFolders);\n        mockGetConfiguration.mockReturnValue([{}, {}]);\n        const docSettings = newDocumentSettings();\n        const configFile = Path.resolve(Path.join(__dirname, '..', 'sampleSourceFiles', 'cSpell.json'));\n        docSettings.registerConfigurationFile(configFile);\n        const settings = await docSettings.getSettings({ uri: vscode_uri_1.URI.file(__filename).toString() });\n        expect(settings).toHaveProperty('name');\n        expect(settings.enabled).toBeUndefined();\n        expect(settings.language).toBe('en-gb');\n    });\n    it('test isExcluded', async () => {\n        const mockFolders = [workspaceFolder];\n        mockGetWorkspaceFolders.mockReturnValue(mockFolders);\n        mockGetConfiguration.mockReturnValue([{}, {}]);\n        const docSettings = newDocumentSettings();\n        const configFile = Path.resolve(Path.join(__dirname, '..', 'sampleSourceFiles', 'cSpell.json'));\n        docSettings.registerConfigurationFile(configFile);\n        const result = await docSettings.isExcluded(vscode_uri_1.URI.file(__filename).toString());\n        expect(result).toBe(false);\n    });\n    test('resolvePath', () => {\n        expect(documentSettings_1.debugExports.resolvePath(__dirname)).toBe(__dirname);\n        expect(documentSettings_1.debugExports.resolvePath('~')).toBe(os.homedir());\n    });\n    function newDocumentSettings() {\n        return new documentSettings_1.DocumentSettings({}, {});\n    }\n});\ndescribe('Validate RegExp corrections', () => {\n    test('fixRegEx', () => {\n        var _a, _b;\n        const defaultSettings = cspell.getDefaultSettings();\n        // Make sure it doesn't change the defaults.\n        expect((_a = defaultSettings.patterns) === null || _a === void 0 ? void 0 : _a.map(p => p.pattern).map(documentSettings_1.debugExports.fixRegEx))\n            .toEqual((_b = defaultSettings.patterns) === null || _b === void 0 ? void 0 : _b.map(p => p.pattern));\n        const sampleRegEx = [\n            '/#.*/',\n            '/\"\"\"(.*?\\\\n?)+?\"\"\"/g',\n            '/\\'\\'\\'(.*?\\\\n?)+?\\'\\'\\'/g',\n            'strings',\n        ];\n        const expectedRegEx = [\n            '/#.*/',\n            '/(\"\"\")[^\\\\1]*?\\\\1/g',\n            \"/(''')[^\\\\1]*?\\\\1/g\",\n            'strings',\n        ];\n        expect(sampleRegEx.map(documentSettings_1.debugExports.fixRegEx)).toEqual(expectedRegEx);\n    });\n    test('fixPattern', () => {\n        var _a;\n        const defaultSettings = cspell.getDefaultSettings();\n        // Make sure it doesn't change the defaults.\n        expect((_a = defaultSettings.patterns) === null || _a === void 0 ? void 0 : _a.map(documentSettings_1.debugExports.fixPattern))\n            .toEqual(defaultSettings.patterns);\n    });\n    test('fixPattern', () => {\n        const defaultSettings = cspell.getDefaultSettings();\n        // Make sure it doesn't change the defaults.\n        expect(documentSettings_1.correctBadSettings(defaultSettings))\n            .toEqual(defaultSettings);\n        const settings = {\n            patterns: [\n                {\n                    name: 'strings',\n                    pattern: '/\"\"\"(.*?\\\\n?)+?\"\"\"/g',\n                }\n            ]\n        };\n        const expectedSettings = {\n            patterns: [\n                {\n                    name: 'strings',\n                    pattern: '/(\"\"\")[^\\\\1]*?\\\\1/g',\n                }\n            ]\n        };\n        expect(documentSettings_1.correctBadSettings(settings)).toEqual(expectedSettings);\n        expect(documentSettings_1.correctBadSettings(settings)).not.toEqual(settings);\n    });\n});\n//# sourceMappingURL=documentSettings.test.js.map"
  },
  {
    "path": "server/index.d.ts",
    "content": "export * from './api';\nexport * from './cspellConfig';\n"
  },
  {
    "path": "server/index.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=index.js.map"
  },
  {
    "path": "server/logger.d.ts",
    "content": "export declare enum LogLevel {\n    NONE = 0,\n    ERROR = 1,\n    WARNING = 2,\n    INFO = 3,\n    DEBUG = 4\n}\ndeclare type LoggerFunction = (msg: string) => void;\nexport interface LoggerConnection {\n    console: {\n        error: LoggerFunction;\n        warn: LoggerFunction;\n        info: LoggerFunction;\n        log: LoggerFunction;\n    };\n    onExit: (handler: () => void) => void;\n}\nexport interface LogEntry {\n    seq: number;\n    level: LogLevel;\n    ts: Date;\n    msg: string;\n}\nexport declare class Logger {\n    private logLevel;\n    private connection;\n    private seq;\n    private logs;\n    private loggers;\n    constructor(logLevel?: LogLevel, connection?: LoggerConnection);\n    private writeLog;\n    logMessage(level: LogLevel, msg: string): void;\n    set level(level: LogLevel | string);\n    get level(): LogLevel | string;\n    setConnection(connection: LoggerConnection): void;\n    error(msg: string): void;\n    warn(msg: string): void;\n    info(msg: string): void;\n    debug(msg: string): void;\n    log(msg: string): void;\n    getPendingEntries(): LogEntry[];\n}\nexport {};\n"
  },
  {
    "path": "server/logger.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nvar LogLevel;\n(function (LogLevel) {\n    LogLevel[LogLevel[\"NONE\"] = 0] = \"NONE\";\n    LogLevel[LogLevel[\"ERROR\"] = 1] = \"ERROR\";\n    LogLevel[LogLevel[\"WARNING\"] = 2] = \"WARNING\";\n    LogLevel[LogLevel[\"INFO\"] = 3] = \"INFO\";\n    LogLevel[LogLevel[\"DEBUG\"] = 4] = \"DEBUG\";\n})(LogLevel = exports.LogLevel || (exports.LogLevel = {}));\nconst logLevels = [\n    [LogLevel[LogLevel.NONE], LogLevel.NONE],\n    [LogLevel[LogLevel.ERROR], LogLevel.ERROR],\n    [LogLevel[LogLevel.WARNING], LogLevel.WARNING],\n    [LogLevel[LogLevel.INFO], LogLevel.INFO],\n    [LogLevel[LogLevel.DEBUG], LogLevel.DEBUG],\n    ['INFORMATION', LogLevel.INFO],\n];\nconst levelMap = new Map(logLevels);\nconst stub = () => { };\nclass Logger {\n    constructor(logLevel = LogLevel.DEBUG, connection) {\n        this.logLevel = logLevel;\n        this.seq = 0;\n        this.logs = [];\n        this.loggers = {\n            [LogLevel.NONE]: stub,\n            [LogLevel.ERROR]: stub,\n            [LogLevel.WARNING]: stub,\n            [LogLevel.INFO]: stub,\n            [LogLevel.DEBUG]: stub,\n        };\n        if (connection) {\n            this.setConnection(connection);\n        }\n    }\n    writeLog(entry) {\n        if (!this.connection) {\n            this.logs.push(entry);\n        }\n        else {\n            if (entry.level > this.logLevel) {\n                return;\n            }\n            const message = `${entry.seq}\\t${entry.ts.toISOString()}\\t${entry.msg}`;\n            const logger = this.loggers[entry.level];\n            if (logger) {\n                // console.log(message);\n                logger(message);\n            }\n            else {\n                console.error(`Unknown log level: ${entry.level}; msg: ${entry.msg}`);\n            }\n        }\n    }\n    logMessage(level, msg) {\n        const seq = ++this.seq;\n        const entry = {\n            seq,\n            level,\n            ts: new Date(),\n            msg\n        };\n        this.writeLog(entry);\n    }\n    set level(level) {\n        this.logLevel = toLogLevel(level);\n    }\n    get level() {\n        return this.logLevel;\n    }\n    setConnection(connection) {\n        this.connection = connection;\n        this.connection.onExit(() => {\n            this.connection = undefined;\n            this.loggers[LogLevel.ERROR] = stub;\n            this.loggers[LogLevel.WARNING] = stub;\n            this.loggers[LogLevel.INFO] = stub;\n            this.loggers[LogLevel.DEBUG] = stub;\n        });\n        this.loggers[LogLevel.ERROR] = (msg) => { connection.console.error(msg); };\n        this.loggers[LogLevel.WARNING] = (msg) => { connection.console.warn(msg); };\n        this.loggers[LogLevel.INFO] = (msg) => { connection.console.info(msg); };\n        this.loggers[LogLevel.DEBUG] = (msg) => { connection.console.log(msg); };\n        this.logs.forEach(log => this.writeLog(log));\n        this.logs.length = 0;\n    }\n    error(msg) {\n        this.logMessage(LogLevel.ERROR, msg);\n    }\n    warn(msg) {\n        this.logMessage(LogLevel.WARNING, msg);\n    }\n    info(msg) {\n        this.logMessage(LogLevel.INFO, msg);\n    }\n    debug(msg) {\n        this.logMessage(LogLevel.DEBUG, msg);\n    }\n    log(msg) {\n        this.debug(msg);\n    }\n    getPendingEntries() {\n        return this.logs;\n    }\n}\nexports.Logger = Logger;\nfunction toLogLevel(level) {\n    const lvl = typeof level === 'string'\n        ? levelMap.get(level.toUpperCase()) || LogLevel.NONE\n        : level;\n    return typeof lvl !== 'number' || lvl < LogLevel.NONE || lvl > LogLevel.DEBUG\n        ? LogLevel.DEBUG\n        : lvl;\n}\n//# sourceMappingURL=logger.js.map"
  },
  {
    "path": "server/logger.test.d.ts",
    "content": "export {};\n"
  },
  {
    "path": "server/logger.test.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst logger_1 = require(\"./logger\");\ndescribe('Validate Logger', () => {\n    test('Logger Late Binding', () => {\n        const logger = new logger_1.Logger();\n        logger.log('log');\n        logger.debug('debug');\n        logger.info('info');\n        logger.warn('warn');\n        logger.error('error');\n        // late binding\n        const connection = makeConnection();\n        logger.setConnection(connection);\n        expect(connection.exit).not.toEqual(exit);\n        // test logging\n        expect(connection.console.error.mock.calls.map(a => a[0])).toEqual([expect.stringContaining('error')]);\n        expect(connection.console.warn.mock.calls.map(a => a[0])).toEqual([expect.stringContaining('warn')]);\n        expect(connection.console.info.mock.calls.map(a => a[0])).toEqual([expect.stringContaining('info')]);\n        expect(connection.console.log.mock.calls.map(a => a[0])).toEqual([\n            expect.stringContaining('log'),\n            expect.stringContaining('debug'),\n        ]);\n        // test sequence\n        expect(connection.console.error.mock.calls.map(a => a[0])).toEqual([expect.stringMatching(/^5\\b/)]);\n        expect(connection.console.warn.mock.calls.map(a => a[0])).toEqual([expect.stringMatching(/^4\\b/)]);\n        expect(connection.console.info.mock.calls.map(a => a[0])).toEqual([expect.stringMatching(/^3\\b/)]);\n        expect(connection.console.log.mock.calls.map(a => a[0])).toEqual([\n            expect.stringMatching(/^1\\b/),\n            expect.stringMatching(/^2\\b/),\n        ]);\n    });\n    test('Logger Early Binding', () => {\n        // late binding\n        const connection = makeConnection();\n        const logger = new logger_1.Logger(logger_1.LogLevel.DEBUG, connection);\n        logger.log('log');\n        logger.debug('debug');\n        logger.info('info');\n        logger.warn('warn');\n        logger.error('error');\n        expect(connection.exit).not.toEqual(exit);\n        // test logging\n        expect(connection.console.error.mock.calls.map(a => a[0])).toEqual([expect.stringContaining('error')]);\n        expect(connection.console.warn.mock.calls.map(a => a[0])).toEqual([expect.stringContaining('warn')]);\n        expect(connection.console.info.mock.calls.map(a => a[0])).toEqual([expect.stringContaining('info')]);\n        expect(connection.console.log.mock.calls.map(a => a[0])).toEqual([\n            expect.stringContaining('log'),\n            expect.stringContaining('debug'),\n        ]);\n        // test sequence\n        expect(connection.console.error.mock.calls.map(a => a[0])).toEqual([expect.stringMatching(/^5\\b/)]);\n        expect(connection.console.warn.mock.calls.map(a => a[0])).toEqual([expect.stringMatching(/^4\\b/)]);\n        expect(connection.console.info.mock.calls.map(a => a[0])).toEqual([expect.stringMatching(/^3\\b/)]);\n        expect(connection.console.log.mock.calls.map(a => a[0])).toEqual([\n            expect.stringMatching(/^1\\b/),\n            expect.stringMatching(/^2\\b/),\n        ]);\n    });\n    test('Logger onExit', () => {\n        // late binding\n        const connection = makeConnection();\n        const logger = new logger_1.Logger(logger_1.LogLevel.DEBUG, connection);\n        expect(connection.exit).not.toEqual(exit);\n        logger.log('log');\n        logger.debug('debug');\n        logger.info('info');\n        logger.warn('warn');\n        // exit before the last log.\n        connection.exit();\n        logger.error('error');\n        // test logging\n        expect(connection.console.error.mock.calls.length).toEqual(0);\n        expect(connection.console.warn.mock.calls.length).toEqual(1);\n        expect(connection.console.info.mock.calls.length).toEqual(1);\n        expect(connection.console.log.mock.calls.length).toEqual(2);\n        // re-attach\n        logger.setConnection(connection);\n        expect(connection.console.error.mock.calls.length).toEqual(1);\n        expect(connection.console.warn.mock.calls.length).toEqual(1);\n        expect(connection.console.info.mock.calls.length).toEqual(1);\n        expect(connection.console.log.mock.calls.length).toEqual(2);\n    });\n    test('Logger log level', () => {\n        // late binding\n        const connection = makeConnection();\n        const logger = new logger_1.Logger(logger_1.LogLevel.WARNING, connection);\n        expect(connection.exit).not.toEqual(exit);\n        logger.log('log');\n        logger.debug('debug');\n        logger.info('info');\n        logger.warn('warn');\n        logger.error('error');\n        // test logging\n        expect(connection.console.error.mock.calls.length).toEqual(1);\n        expect(connection.console.warn.mock.calls.length).toEqual(1);\n        expect(connection.console.info.mock.calls.length).toEqual(0);\n        expect(connection.console.log.mock.calls.length).toEqual(0);\n        expect(logger.level).toBe(logger_1.LogLevel.WARNING);\n        logger.level = 'error';\n        expect(logger.level).toBe(logger_1.LogLevel.ERROR);\n        logger.level = 'unknown';\n        expect(logger.level).toBe(logger_1.LogLevel.NONE);\n        logger.level = logger_1.LogLevel.DEBUG;\n        logger.log('message');\n        expect(connection.console.log.mock.calls.length).toEqual(1);\n    });\n    test('Logger get pending entries', () => {\n        const logger = new logger_1.Logger();\n        logger.log('log');\n        logger.debug('debug');\n        logger.info('info');\n        logger.warn('warn');\n        logger.error('error');\n        const entries = logger.getPendingEntries();\n        expect(entries.map(e => e.msg)).toEqual([\n            'log', 'debug', 'info', 'warn', 'error'\n        ]);\n    });\n});\nfunction exit() { }\nfunction makeConnection() {\n    const connection = {\n        console: {\n            log: jest.fn(),\n            error: jest.fn(),\n            warn: jest.fn(),\n            info: jest.fn(),\n        },\n        onExit: (fn) => connection.exit = fn,\n        exit,\n    };\n    return connection;\n}\n//# sourceMappingURL=logger.test.js.map"
  },
  {
    "path": "server/server.d.ts",
    "content": "export {};\n"
  },
  {
    "path": "server/server.js",
    "content": "\"use strict\";\n// cSpell:ignore pycache\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst vscode_languageserver_1 = require(\"vscode-languageserver\");\nconst vscode = require(\"vscode-languageserver\");\nconst Validator = require(\"./validator\");\nconst rxjs_1 = require(\"rxjs\");\nconst operators_1 = require(\"rxjs/operators\");\nconst codeActions_1 = require(\"./codeActions\");\nconst cspell_lib_1 = require(\"cspell-lib\");\nconst CSpell = require(\"cspell-lib\");\nconst cspell_lib_2 = require(\"cspell-lib\");\nconst documentSettings_1 = require(\"./documentSettings\");\nconst util_1 = require(\"./util\");\nutil_1.log('Starting Spell Checker Server');\nconst notifyMethodNames = {\n    onConfigChange: 'onConfigChange',\n    registerConfigurationFile: 'registerConfigurationFile',\n};\nconst tds = CSpell;\nconst defaultCheckLimit = Validator.defaultCheckLimit;\n// Turn off the spell checker by default. The setting files should have it set.\n// This prevents the spell checker from running too soon.\nconst defaultSettings = Object.assign(Object.assign({}, CSpell.mergeSettings(cspell_lib_2.getDefaultSettings(), CSpell.getGlobalSettings())), { checkLimit: defaultCheckLimit, enabled: false });\nconst defaultDebounce = 50;\nfunction run() {\n    // debounce buffer\n    const validationRequestStream = new rxjs_1.ReplaySubject(1);\n    const triggerUpdateConfig = new rxjs_1.ReplaySubject(1);\n    const triggerValidateAll = new rxjs_1.ReplaySubject(1);\n    const validationByDoc = new Map();\n    const blockValidation = new Map();\n    let isValidationBusy = false;\n    const disposables = [];\n    const requestMethodApi = {\n        isSpellCheckEnabled: handleIsSpellCheckEnabled,\n        getConfigurationForDocument: handleGetConfigurationForDocument,\n        splitTextIntoWords: handleSplitTextIntoWords,\n        spellingSuggestions: handleSpellingSuggestions,\n    };\n    // Create a connection for the server. The connection uses Node's IPC as a transport\n    util_1.log('Create Connection');\n    const connection = vscode_languageserver_1.createConnection(vscode.ProposedFeatures.all);\n    const documentSettings = new documentSettings_1.DocumentSettings(connection, defaultSettings);\n    // Create a simple text document manager. The text document manager\n    // supports full document sync only\n    const documents = new vscode_languageserver_1.TextDocuments();\n    connection.onInitialize((params) => {\n        // Hook up the logger to the connection.\n        util_1.log('onInitialize');\n        util_1.setWorkspaceBase(params.rootUri ? params.rootUri : '');\n        const capabilities = {\n            // Tell the client that the server works in FULL text document sync mode\n            textDocumentSync: {\n                openClose: true,\n                change: documents.syncKind,\n                willSave: true,\n                save: { includeText: true },\n            },\n            codeActionProvider: {\n                codeActionKinds: [\n                    vscode_languageserver_1.CodeActionKind.QuickFix\n                ],\n            },\n        };\n        return { capabilities };\n    });\n    // The settings have changed. Is sent on server activation as well.\n    connection.onDidChangeConfiguration(onConfigChange);\n    function onConfigChange(_change) {\n        util_1.logInfo('Configuration Change');\n        triggerUpdateConfig.next(undefined);\n        updateLogLevel();\n    }\n    function updateActiveSettings() {\n        util_1.log('updateActiveSettings');\n        documentSettings.resetSettings();\n        triggerValidateAll.next(undefined);\n    }\n    function getActiveSettings(doc) {\n        return getActiveUriSettings(doc.uri);\n    }\n    function getActiveUriSettings(uri) {\n        return documentSettings.getUriSettings(uri);\n    }\n    function registerConfigurationFile(path) {\n        documentSettings.registerConfigurationFile(path);\n        util_1.logInfo('Register Configuration File', path);\n        triggerUpdateConfig.next(undefined);\n    }\n    // Listen for event messages from the client.\n    connection.onNotification(notifyMethodNames.onConfigChange, onConfigChange);\n    connection.onNotification(notifyMethodNames.registerConfigurationFile, registerConfigurationFile);\n    async function handleIsSpellCheckEnabled(params) {\n        const { uri, languageId } = params;\n        const fileEnabled = uri ? !await isUriExcluded(uri) : undefined;\n        const settings = await getActiveUriSettings(uri);\n        return {\n            languageEnabled: languageId && uri ? await isLanguageEnabled({ uri, languageId }, settings) : undefined,\n            fileEnabled,\n        };\n    }\n    async function handleGetConfigurationForDocument(params) {\n        const { uri, languageId } = params;\n        const doc = uri && documents.get(uri);\n        const docSettings = doc && (await getSettingsToUseForDocument(doc)) || undefined;\n        const settings = await getActiveUriSettings(uri);\n        return {\n            languageEnabled: languageId && doc ? await isLanguageEnabled(doc, settings) : undefined,\n            fileEnabled: uri ? !await isUriExcluded(uri) : undefined,\n            settings,\n            docSettings,\n        };\n    }\n    function textToWords(text) {\n        const setOfWords = new Set(cspell_lib_1.Text.extractWordsFromCode(text)\n            .map(t => t.text)\n            .map(t => t.toLowerCase()));\n        return [...setOfWords];\n    }\n    function handleSplitTextIntoWords(text) {\n        return {\n            words: textToWords(text),\n        };\n    }\n    async function handleSpellingSuggestions(_params) {\n        return {};\n    }\n    // Register API Handlers\n    Object.entries(requestMethodApi).forEach(([name, fn]) => {\n        connection.onRequest(name, fn);\n    });\n    // validate documents\n    const disposableValidate = validationRequestStream\n        .pipe(operators_1.filter(doc => !validationByDoc.has(doc.uri)))\n        .subscribe(doc => {\n        if (!validationByDoc.has(doc.uri)) {\n            const uri = doc.uri;\n            if (documentSettings_1.isUriBlackListed(uri)) {\n                validationByDoc.set(doc.uri, validationRequestStream.pipe(operators_1.filter(doc => uri === doc.uri), operators_1.take(1), operators_1.tap(doc => util_1.log('Ignoring:', doc.uri))).subscribe());\n            }\n            else {\n                validationByDoc.set(doc.uri, validationRequestStream.pipe(operators_1.filter(doc => uri === doc.uri), operators_1.tap(doc => util_1.log(`Request Validate: v${doc.version}`, doc.uri)), operators_1.flatMap(async (doc) => ({ doc, settings: await getActiveSettings(doc) })), operators_1.debounce(dsp => rxjs_1.timer(dsp.settings.spellCheckDelayMs || defaultDebounce)\n                    .pipe(operators_1.filter(() => !isValidationBusy))), operators_1.tap(dsp => util_1.log(`blocked? ${blockValidation.has(dsp.doc.uri)}`, dsp.doc.uri)), operators_1.filter(dsp => !blockValidation.has(dsp.doc.uri)), operators_1.flatMap(validateTextDocument)).subscribe(diag => connection.sendDiagnostics(diag)));\n            }\n        }\n    });\n    const disposableTriggerUpdateConfigStream = triggerUpdateConfig.pipe(operators_1.tap(() => util_1.log('Trigger Update Config')), operators_1.debounceTime(100)).subscribe(() => {\n        updateActiveSettings();\n    });\n    const disposableTriggerValidateAll = triggerValidateAll\n        .pipe(operators_1.debounceTime(250))\n        .subscribe(() => {\n        util_1.log('Validate all documents');\n        documents.all().forEach(doc => validationRequestStream.next(doc));\n    });\n    async function shouldValidateDocument(textDocument, settings) {\n        const { uri } = textDocument;\n        return !!settings.enabled && isLanguageEnabled(textDocument, settings)\n            && !await isUriExcluded(uri);\n    }\n    function isLanguageEnabled(textDocument, settings) {\n        const { enabledLanguageIds = [] } = settings;\n        return enabledLanguageIds.indexOf(textDocument.languageId) >= 0;\n    }\n    async function isUriExcluded(uri) {\n        return documentSettings.isExcluded(uri);\n    }\n    async function getBaseSettings(doc) {\n        const settings = await getActiveSettings(doc);\n        return Object.assign(Object.assign({}, CSpell.mergeSettings(defaultSettings, settings)), { enabledLanguageIds: settings.enabledLanguageIds });\n    }\n    async function getSettingsToUseForDocument(doc) {\n        return tds.constructSettingsForText(await getBaseSettings(doc), doc.getText(), doc.languageId);\n    }\n    async function validateTextDocument(dsp) {\n        async function validate() {\n            const { doc, settings } = dsp;\n            const uri = doc.uri;\n            try {\n                if (!documentSettings_1.isUriAllowed(uri, settings.allowedSchemas)) {\n                    const schema = uri.split(':')[0];\n                    util_1.log(`Schema not allowed (${schema}), skipping:`, uri);\n                    return { uri, diagnostics: [] };\n                }\n                const shouldCheck = await shouldValidateDocument(doc, settings);\n                if (!shouldCheck) {\n                    util_1.log('validateTextDocument skip:', uri);\n                    return { uri, diagnostics: [] };\n                }\n                const settingsToUse = await getSettingsToUseForDocument(doc);\n                if (settingsToUse.enabled) {\n                    util_1.logInfo('Validate File', uri);\n                    util_1.log(`validateTextDocument start: v${doc.version}`, uri);\n                    const settings = documentSettings_1.correctBadSettings(settingsToUse);\n                    const diagnostics = await Validator.validateTextDocument(doc, settings);\n                    util_1.log(`validateTextDocument done: v${doc.version}`, uri);\n                    return { uri, diagnostics };\n                }\n            }\n            catch (e) {\n                util_1.logError(`validateTextDocument: ${JSON.stringify(e)}`);\n            }\n            return { uri, diagnostics: [] };\n        }\n        isValidationBusy = true;\n        const r = await validate();\n        isValidationBusy = false;\n        return r;\n    }\n    // Make the text document manager listen on the connection\n    // for open, change and close text document events\n    documents.listen(connection);\n    disposables.push(\n    // The content of a text document has changed. This event is emitted\n    // when the text document first opened or when its content has changed.\n    documents.onDidChangeContent(event => {\n        validationRequestStream.next(event.document);\n    }), \n    // We want to block validation during saving.\n    documents.onWillSave(event => {\n        const { uri, version } = event.document;\n        util_1.log(`onWillSave: v${version}`, uri);\n        blockValidation.set(uri, version);\n    }), \n    // Enable validation once it is saved.\n    documents.onDidSave(event => {\n        const { uri, version } = event.document;\n        util_1.log(`onDidSave: v${version}`, uri);\n        blockValidation.delete(uri);\n        validationRequestStream.next(event.document);\n    }), \n    // Remove subscriptions when a document closes.\n    documents.onDidClose(event => {\n        const uri = event.document.uri;\n        const sub = validationByDoc.get(uri);\n        if (sub) {\n            validationByDoc.delete(uri);\n            sub.unsubscribe();\n        }\n        // A text document was closed we clear the diagnostics\n        connection.sendDiagnostics({ uri, diagnostics: [] });\n    }));\n    connection.onCodeAction(codeActions_1.onCodeActionHandler(documents, getBaseSettings, () => documentSettings.version, documentSettings));\n    // Listen on the connection\n    connection.listen();\n    // Free up the validation streams on shutdown.\n    connection.onShutdown(() => {\n        disposables.forEach(d => d.dispose());\n        disposables.length = 0;\n        disposableValidate.unsubscribe();\n        disposableTriggerUpdateConfigStream.unsubscribe();\n        disposableTriggerValidateAll.unsubscribe();\n        const toDispose = [...validationByDoc.values()];\n        validationByDoc.clear();\n        toDispose.forEach(sub => sub.unsubscribe());\n    });\n    function updateLogLevel() {\n        connection.workspace.getConfiguration({ section: 'cSpell.logLevel' }).then((result) => {\n            fetchFolders();\n            util_1.logger.level = result;\n            util_1.logger.setConnection(connection);\n        }, (reject) => {\n            fetchFolders();\n            util_1.logger.level = util_1.LogLevel.DEBUG;\n            util_1.logger.error(`Failed to get config: ${JSON.stringify(reject)}`);\n            util_1.logger.setConnection(connection);\n        });\n    }\n    async function fetchFolders() {\n        const folders = await connection.workspace.getWorkspaceFolders();\n        if (folders) {\n            util_1.setWorkspaceFolders(folders.map(f => f.uri));\n        }\n        else {\n            util_1.setWorkspaceFolders([]);\n        }\n    }\n}\nrun();\n//# sourceMappingURL=server.js.map"
  },
  {
    "path": "server/util.d.ts",
    "content": "import { Logger } from './logger';\nexport { LogLevel } from './logger';\nexport declare const logger: Logger;\nexport declare function log(msg: string, uri?: string | string[]): void;\nexport declare function logError(msg: string, uri?: string | string[]): void;\nexport declare function logInfo(msg: string, uri?: string | string[]): void;\nexport declare function logDebug(msg: string, uri?: string | string[]): void;\nexport declare function setWorkspaceBase(uri: string): void;\nexport declare function setWorkspaceFolders(folders: string[]): void;\nexport declare function uniqueFilter<T>(): (v: T) => boolean;\nexport declare function uniqueFilter<T, U>(extractFn: (v: T) => U): (v: T) => boolean;\n"
  },
  {
    "path": "server/util.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst logger_1 = require(\"./logger\");\nvar logger_2 = require(\"./logger\");\nexports.LogLevel = logger_2.LogLevel;\nlet workspaceBase = '';\nlet workspaceFolders = [];\nexports.logger = new logger_1.Logger();\nfunction log(msg, uri) {\n    exports.logger.log(formatMessage(msg, uri));\n}\nexports.log = log;\nfunction logError(msg, uri) {\n    exports.logger.error(formatMessage(msg, uri));\n}\nexports.logError = logError;\nfunction logInfo(msg, uri) {\n    exports.logger.info(formatMessage(msg, uri));\n}\nexports.logInfo = logInfo;\nfunction logDebug(msg, uri) {\n    exports.logger.debug(formatMessage(msg, uri));\n}\nexports.logDebug = logDebug;\nfunction setWorkspaceBase(uri) {\n    log(`setWorkspaceBase URI: ${uri}`);\n    workspaceBase = uri;\n}\nexports.setWorkspaceBase = setWorkspaceBase;\nfunction setWorkspaceFolders(folders) {\n    log(`setWorkspaceFolders folders URI: [${folders.join('\\n')}]`);\n    workspaceFolders = folders;\n    setWorkspaceBase(findCommonBasis(workspaceFolders));\n}\nexports.setWorkspaceFolders = setWorkspaceFolders;\nfunction formatMessage(msg, uri) {\n    const uris = Array.isArray(uri) ? uri : [uri];\n    return msg + '\\t' + uris.map(normalizeUri).join('\\n\\t\\t\\t');\n}\nfunction normalizeUri(uri) {\n    if (!uri) {\n        return '';\n    }\n    const base = findCommonBase(uri, workspaceBase);\n    return base ? uri.replace(base, '...') : uri;\n}\nfunction findCommonBasis(folders) {\n    return folders.reduce((a, b) => findCommonBase(a || b, b), '');\n}\nfunction findCommonBase(a, b) {\n    const limit = matchingUriLength(a, b);\n    return a.slice(0, limit);\n}\nfunction matchingUriLength(a, b) {\n    const sep = '/';\n    const aParts = a.split(sep);\n    const bParts = b.split(sep);\n    const limit = Math.min(aParts.length, bParts.length);\n    let i = 0;\n    for (i = 0; i < limit && aParts[i] === bParts[i]; i += 1) { }\n    return aParts.slice(0, i).join(sep).length;\n}\nfunction uniqueFilter(extractFn) {\n    const values = new Set();\n    const extractor = extractFn || (a => a);\n    return (v) => {\n        const vv = extractor(v);\n        const ret = !values.has(vv);\n        values.add(vv);\n        return ret;\n    };\n}\nexports.uniqueFilter = uniqueFilter;\n//# sourceMappingURL=util.js.map"
  },
  {
    "path": "server/util.test.d.ts",
    "content": "export {};\n"
  },
  {
    "path": "server/util.test.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst util_1 = require(\"./util\");\ndescribe('Validate Util Functions', () => {\n    test('Logging', () => {\n        util_1.setWorkspaceFolders([__dirname, __dirname]);\n        util_1.log('log', __filename);\n        util_1.logError('error');\n        util_1.logDebug('debug');\n        util_1.logInfo('info');\n        expect(util_1.logger.getPendingEntries().map(e => e.msg)).toEqual([\n            expect.stringContaining('setWorkspaceFolders'),\n            expect.stringContaining('setWorkspaceBase'),\n            expect.stringMatching(/log\\s+.*util.test.ts/),\n            expect.stringContaining('error'),\n            expect.stringContaining('debug'),\n            expect.stringContaining('info'),\n        ]);\n    });\n    test('Unique filter', () => {\n        expect([].filter(util_1.uniqueFilter())).toEqual([]);\n        expect([1, 2, 3].filter(util_1.uniqueFilter())).toEqual([1, 2, 3]);\n        expect([1, 2, 3, 3, 2, 1].filter(util_1.uniqueFilter())).toEqual([1, 2, 3]);\n        const a = { id: 'a', v: 1 };\n        const b = { id: 'b', v: 1 };\n        const aa = { id: 'a', v: 2 };\n        expect([a, a, b, aa, b].filter(util_1.uniqueFilter())).toEqual([a, b, aa]);\n        expect([a, a, b, aa, b, aa].filter(util_1.uniqueFilter(a => a.id))).toEqual([a, b]);\n    });\n});\n//# sourceMappingURL=util.test.js.map"
  },
  {
    "path": "server/validator.d.ts",
    "content": "import { TextDocument, Diagnostic } from 'vscode-languageserver';\nimport { CSpellUserSettings } from './cspellConfig';\nimport { Sequence } from 'gensequence';\nexport { validateText } from 'cspell-lib';\nexport declare const diagnosticCollectionName = \"cSpell\";\nexport declare const diagSource = \"cSpell\";\nexport declare const defaultCheckLimit = 500;\nexport declare function validateTextDocument(textDocument: TextDocument, options: CSpellUserSettings): Promise<Diagnostic[]>;\nexport declare function validateTextDocumentAsync(textDocument: TextDocument, options: CSpellUserSettings): Promise<Sequence<Diagnostic>>;\n"
  },
  {
    "path": "server/validator.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst vscode_languageserver_1 = require(\"vscode-languageserver\");\nconst cspell_lib_1 = require(\"cspell-lib\");\nconst gensequence_1 = require(\"gensequence\");\nvar cspell_lib_2 = require(\"cspell-lib\");\nexports.validateText = cspell_lib_2.validateText;\nexports.diagnosticCollectionName = 'cSpell';\nexports.diagSource = exports.diagnosticCollectionName;\nexports.defaultCheckLimit = 500;\nconst diagSeverityMap = new Map([\n    ['error', vscode_languageserver_1.DiagnosticSeverity.Error],\n    ['warning', vscode_languageserver_1.DiagnosticSeverity.Warning],\n    ['information', vscode_languageserver_1.DiagnosticSeverity.Information],\n    ['hint', vscode_languageserver_1.DiagnosticSeverity.Hint],\n]);\nasync function validateTextDocument(textDocument, options) {\n    return (await validateTextDocumentAsync(textDocument, options)).toArray();\n}\nexports.validateTextDocument = validateTextDocument;\nasync function validateTextDocumentAsync(textDocument, options) {\n    const { diagnosticLevel = vscode_languageserver_1.DiagnosticSeverity.Information.toString() } = options;\n    const severity = diagSeverityMap.get(diagnosticLevel.toLowerCase()) || vscode_languageserver_1.DiagnosticSeverity.Information;\n    const limit = (options.checkLimit || exports.defaultCheckLimit) * 1024;\n    const text = textDocument.getText().slice(0, limit);\n    const diags = gensequence_1.genSequence(await cspell_lib_1.validateText(text, options))\n        // Convert the offset into a position\n        .map(offsetWord => (Object.assign(Object.assign({}, offsetWord), { position: textDocument.positionAt(offsetWord.offset) })))\n        // Calculate the range\n        .map(word => (Object.assign(Object.assign({}, word), { range: {\n            start: word.position,\n            end: (Object.assign(Object.assign({}, word.position), { character: word.position.character + word.text.length }))\n        } })))\n        // Convert it to a Diagnostic\n        .map(({ text, range }) => ({\n        severity,\n        range: range,\n        message: `\"${text}\": Unknown word.`,\n        source: exports.diagSource\n    }));\n    return diags;\n}\nexports.validateTextDocumentAsync = validateTextDocumentAsync;\n//# sourceMappingURL=validator.js.map"
  },
  {
    "path": "server/validator.test.d.ts",
    "content": "export {};\n"
  },
  {
    "path": "server/validator.test.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst Validator = require(\"./validator\");\nconst loremIpsum = require(\"lorem-ipsum\");\nconst cspell = require(\"cspell-lib\");\nconst vscode_uri_1 = require(\"vscode-uri\");\nconst cspell_lib_1 = require(\"cspell-lib\");\nconst vscode_languageserver_1 = require(\"vscode-languageserver\");\n// cSpell:ignore brouwn jumpped lazzy wrongg mispelled ctrip nmove mischecked\nconst defaultSettings = Object.assign(Object.assign({}, cspell_lib_1.getDefaultSettings()), { enabledLanguageIds: ['plaintext', 'javascript'] });\nfunction getSettings(text, languageId) {\n    return cspell.constructSettingsForText(defaultSettings, text, languageId);\n}\ndescribe('Validator', () => {\n    test('validates the validator', () => {\n        const text = 'The quick brouwn fox jumpped over the lazzy dog.';\n        const languageId = 'plaintext';\n        const settings = getSettings(text, languageId);\n        const results = Validator.validateText(text, settings);\n        return results.then(results => {\n            const words = results.map(({ text }) => text);\n            expect(words).toEqual(['brouwn', 'jumpped', 'lazzy']);\n        });\n    });\n    test('validates ignore Case', () => {\n        const text = 'The Quick brown fox Jumped over the lazy dog.';\n        const languageId = 'plaintext';\n        const settings = getSettings(text, languageId);\n        const results = Validator.validateText(text, settings);\n        return results.then(results => {\n            const words = results.map(({ text }) => text);\n            expect(words).toEqual([]);\n        });\n    });\n    test('validate limit', () => {\n        const text = loremIpsum({ count: 5, units: 'paragraphs' });\n        const languageId = 'plaintext';\n        const settings = Object.assign(Object.assign({}, getSettings(text, languageId)), { maxNumberOfProblems: 10 });\n        const results = Validator.validateText(text, settings);\n        return results.then(results => expect(results).toHaveLength(10));\n    });\n    test('validates reserved words', () => {\n        const text = 'constructor const prototype type typeof null undefined';\n        const languageId = 'javascript';\n        const settings = Object.assign(Object.assign({}, getSettings(text, languageId)), { maxNumberOfProblems: 10 });\n        const results = Validator.validateText(text, settings);\n        return results.then(results => expect(results).toHaveLength(0));\n    });\n    test('validates regex inclusions/exclusions', async () => {\n        const text = sampleCode;\n        const languageId = 'plaintext';\n        const settings = Object.assign(Object.assign({}, getSettings(text, languageId)), { maxNumberOfProblems: 10 });\n        const results = await Validator.validateText(text, settings);\n        const words = results.map(wo => wo.text);\n        expect(words).toEqual(expect.arrayContaining(['wrongg']));\n        expect(words).toEqual(expect.arrayContaining(['mispelled']));\n        expect(words).toEqual(expect.not.arrayContaining(['xaccd']));\n        expect(words).toEqual(expect.not.arrayContaining(['ctrip']));\n        expect(words).toEqual(expect.not.arrayContaining(['FFEE']));\n        expect(words).toEqual(expect.not.arrayContaining(['nmove']));\n    });\n    test('validates ignoreRegExpList', () => {\n        const text = sampleCode;\n        const languageId = 'plaintext';\n        const settings = Object.assign(Object.assign({}, getSettings(text, languageId)), { maxNumberOfProblems: 10, ignoreRegExpList: ['^const [wy]RON[g]+', 'mis.*led'] });\n        const results = Validator.validateText(text, settings);\n        return results.then(results => {\n            const words = results.map(wo => wo.text);\n            expect(words).toEqual(expect.not.arrayContaining(['wrongg']));\n            expect(words).toEqual(expect.not.arrayContaining(['mispelled']));\n            expect(words).toEqual(expect.arrayContaining(['mischecked']));\n        });\n    });\n    test('validates ignoreRegExpList 2', () => {\n        const results = Validator.validateText(sampleCode, { ignoreRegExpList: ['/^const [wy]ron[g]+/gim', '/MIS...LED/g', '/mischecked'] });\n        return results.then(results => {\n            const words = results.map(wo => wo.text);\n            expect(words).toEqual(expect.not.arrayContaining(['wrongg']));\n            expect(words).toEqual(expect.arrayContaining(['mispelled']));\n            expect(words).toEqual(expect.arrayContaining(['mischecked']));\n        });\n    });\n    test('validates malformed ignoreRegExpList', () => {\n        const results = Validator.validateText(sampleCode, { ignoreRegExpList: ['/wrong[/gim', 'mis.*led'] });\n        return results.then(results => {\n            const words = results.map(wo => wo.text);\n            expect(words).toEqual(expect.arrayContaining(['wrongg']));\n            expect(words).toEqual(expect.not.arrayContaining(['mispelled']));\n            expect(words).toEqual(expect.arrayContaining(['mischecked']));\n        });\n    });\n    test('validateTextDocument', async () => {\n        const text = sampleCode;\n        const languageId = 'plaintext';\n        const settings = Object.assign(Object.assign({}, getSettings(text, languageId)), { maxNumberOfProblems: 10 });\n        const uri = vscode_uri_1.URI.file(__filename).toString();\n        const textDoc = vscode_languageserver_1.TextDocument.create(uri, languageId, 1, text);\n        const results = await Validator.validateTextDocument(textDoc, settings);\n        const words = results.map(diag => diag.message);\n        expect(words).toEqual(expect.arrayContaining([expect.stringContaining('wrongg')]));\n        expect(words).toEqual(expect.arrayContaining([expect.stringContaining('mispelled')]));\n        expect(words).toEqual(expect.not.arrayContaining([expect.stringContaining('xaccd')]));\n        expect(words).toEqual(expect.not.arrayContaining([expect.stringContaining('ctrip')]));\n        expect(words).toEqual(expect.not.arrayContaining([expect.stringContaining('FFEE')]));\n        expect(words).toEqual(expect.not.arrayContaining([expect.stringContaining('nmove')]));\n    });\n});\nconst sampleCode = `\n\n// Verify urls do not get checked.\nconst url = 'http://ctrip.com?q=words';\n\n// Verify hex values.\nconst value = 0xaccd;\n\n/* spell-checker:disable */\n\nconst weirdWords = ['ctrip', 'xebia', 'zando', 'zooloo'];\n\n/* spell-checker:enable */\n\nconst wrongg = 'mispelled';\nconst check = 'mischecked';\nconst message = \"\\\\nmove to next line\";\n\nconst hex = 0xBADC0FFEE;\n\n`;\n//# sourceMappingURL=validator.test.js.map"
  },
  {
    "path": "server/vscode.config.d.ts",
    "content": "import * as vscode from 'vscode-languageserver';\nexport interface TextDocumentUri {\n    uri: string;\n}\nexport interface TextDocumentUriLangId extends TextDocumentUri {\n    languageId: string;\n}\nexport declare type Connection = vscode.Connection;\nexport declare type GetConfigurationParams = string | vscode.ConfigurationItem | vscode.ConfigurationItem[];\nexport declare function getConfiguration(connection: Connection): Thenable<any>;\nexport declare function getConfiguration(connection: Connection, section: string): Thenable<any>;\nexport declare function getConfiguration(connection: Connection, item: vscode.ConfigurationItem): Thenable<any>;\nexport declare function getConfiguration(connection: Connection, items: vscode.ConfigurationItem[]): Thenable<any[]>;\n/**\n * Just a pass through function to `connection.workspace.getWorkspaceFolders`\n * Useful for mocking.\n * @param connection\n */\nexport declare function getWorkspaceFolders(connection: Connection): Thenable<vscode.WorkspaceFolder[] | null>;\n"
  },
  {
    "path": "server/vscode.config.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst util_1 = require(\"./util\");\nfunction getConfiguration(connection, params) {\n    if (typeof params === 'string') {\n        util_1.log(`getConfiguration\\t${params}`);\n        return connection.workspace.getConfiguration(params);\n    }\n    if (Array.isArray(params)) {\n        const uris = params\n            .map(p => {\n            if (!p) {\n                return '';\n            }\n            if (typeof p === 'string') {\n                return p;\n            }\n            return p.scopeUri || '';\n        })\n            .filter(p => !!p);\n        util_1.log('getConfiguration', uris);\n        return connection.workspace.getConfiguration(params);\n    }\n    if (params) {\n        util_1.log('getConfiguration', params.scopeUri);\n        return connection.workspace.getConfiguration(params);\n    }\n    return connection.workspace.getConfiguration();\n}\nexports.getConfiguration = getConfiguration;\n/**\n * Just a pass through function to `connection.workspace.getWorkspaceFolders`\n * Useful for mocking.\n * @param connection\n */\nfunction getWorkspaceFolders(connection) {\n    return connection.workspace.getWorkspaceFolders();\n}\nexports.getWorkspaceFolders = getWorkspaceFolders;\n//# sourceMappingURL=vscode.config.js.map"
  },
  {
    "path": "src/client/client.ts",
    "content": "import * as coc from 'coc.nvim';\nimport { TextDocument } from 'vscode-languageserver-protocol';\n\nimport {\n  GetConfigurationForDocumentResult,\n  NotifyServerMethods,\n  ServerRequestMethodResults,\n  ServerRequestMethodConstants,\n  SplitTextIntoWordsResult,\n  ServerRequestMethodRequests,\n} from '../server';\nimport * as Settings from '../settings';\n\nimport * as LanguageIds from '../settings/languageIds';\nimport { Maybe, supportedSchemes, setOfSupportedSchemes } from '../util';\n\n// The debug options for the server\nconst debugExecArgv = ['--nolazy', '--inspect=60048'];\n\nconst diagnosticCollectionName = 'cSpell';\n\nexport interface ServerResponseIsSpellCheckEnabled {\n  languageEnabled?: boolean;\n  fileEnabled?: boolean;\n}\n\nconst methodNames: ServerRequestMethodConstants = {\n  isSpellCheckEnabled: 'isSpellCheckEnabled',\n  getConfigurationForDocument: 'getConfigurationForDocument',\n  splitTextIntoWords: 'splitTextIntoWords',\n  spellingSuggestions: 'spellingSuggestions',\n};\n\nconst defaultGetConfigurationForDocumentResult: GetConfigurationForDocumentResult = {\n  languageEnabled: undefined,\n  fileEnabled: undefined,\n  settings: undefined,\n  docSettings: undefined,\n};\n\nexport class CSpellClient {\n\n  readonly client: coc.LanguageClient;\n  readonly import: Set<string> = new Set();\n  readonly languageIds: Set<string>;\n  readonly allowedSchemas: Set<string>;\n\n  /**\n   * @param: {string} module -- absolute path to the server module.\n   */\n  constructor(module: string, languageIds: string[]) {\n    const enabledLanguageIds = Settings.getScopedSettingFromVSConfig('enabledLanguageIds', Settings.Scopes.Workspace);\n    this.allowedSchemas = new Set(\n      Settings.getScopedSettingFromVSConfig('allowedSchemas', Settings.Scopes.Workspace) || supportedSchemes\n    );\n    setOfSupportedSchemes.clear();\n    this.allowedSchemas.forEach(schema => setOfSupportedSchemes.add(schema));\n\n    this.languageIds = new Set(\n      languageIds\n      .concat(enabledLanguageIds || [])\n      .concat(LanguageIds.languageIds)\n    );\n    const uniqueLangIds = [...this.languageIds];\n    const documentSelector = [...this.allowedSchemas]\n      .map(scheme => uniqueLangIds.map(language => ({ language, scheme })))\n      .reduce( (a, b) => a.concat(b));\n    // Options to control the language client\n    const clientOptions: coc.LanguageClientOptions = {\n      documentSelector,\n      diagnosticCollectionName,\n      synchronize: {\n        // Synchronize the setting section 'spellChecker' to the server\n        configurationSection: ['cSpell', 'search']\n      }\n    };\n\n    const execArgv = this.calcServerArgs();\n    const options: coc.ForkOptions = { execArgv };\n    // The debug options for the server\n    const debugOptions: coc.ForkOptions = { execArgv: [...execArgv, ...debugExecArgv] };\n\n    // If the extension is launched in debug mode the debug server options are use\n    // Otherwise the run options are used\n    const serverOptions: coc.ServerOptions = {\n      run : { module, transport: coc.TransportKind.ipc, options },\n      debug: { module, transport: coc.TransportKind.ipc, options: debugOptions }\n    };\n\n    // Create the language client and start the client.\n    this.client = new coc.LanguageClient('cSpell', 'Code Spell Checker', serverOptions, clientOptions);\n    this.client.registerProposedFeatures();\n  }\n\n  public needsStart() {\n    return this.client.needsStart();\n  }\n\n  public needsStop() {\n    return this.client.needsStop();\n  }\n\n  public start() {\n    return this.client.start();\n  }\n\n  public async isSpellCheckEnabled(document: TextDocument): Promise<ServerResponseIsSpellCheckEnabled> {\n    const { uri, languageId = '' } = document;\n\n    if (!uri || !languageId) {\n      return {};\n    }\n    const response = (await this.sendRequest(\n      methodNames.isSpellCheckEnabled,\n      { uri: uri.toString(), languageId }\n    )) as ServerResponseIsSpellCheckEnabled;\n    return response;\n  }\n\n  public async getConfigurationForDocument(document: TextDocument | undefined): Promise<GetConfigurationForDocumentResult> {\n    if (!document) {\n      return (await this.sendRequest(methodNames.getConfigurationForDocument, {}));\n    }\n\n    const { uri, languageId = '' } = document;\n\n    if (!uri || !languageId) {\n      return (await this.sendRequest(methodNames.getConfigurationForDocument, {}));\n    }\n\n    const result = await this.sendRequest(\n      methodNames.getConfigurationForDocument,\n      { uri: uri.toString(), languageId }\n    );\n\n    return result;\n  }\n\n  public splitTextIntoDictionaryWords(text: string): Thenable<SplitTextIntoWordsResult> {\n    return this.sendRequest(\n      methodNames.splitTextIntoWords,\n      text\n    );\n  }\n\n  public async fetchSpellingSuggestions(text: string, languageId: string | undefined, document: TextDocument | undefined) {\n    await this.client.onReady();\n    return; //  this.sendRequest();\n  }\n\n  public notifySettingsChanged() {\n    return this.client.onReady().then(() => this.sendNotification('onConfigChange'));\n  }\n\n  public registerConfiguration(path: string) {\n    return this.client.onReady().then(() => this.sendNotification('registerConfigurationFile', path));\n  }\n\n  get diagnostics(): Maybe<coc.DiagnosticCollection> {\n    return (this.client && this.client.diagnostics) || undefined;\n  }\n\n  public triggerSettingsRefresh() {\n    return this.notifySettingsChanged();\n  }\n\n  private async sendRequest<K extends keyof ServerRequestMethodRequests>(\n    method: K,\n    param: ServerRequestMethodRequests[K]\n  ): Promise<ServerRequestMethodResults[K]> {\n    await this.client.onReady();\n    return this.client.sendRequest(method, param);\n  }\n\n  private sendNotification(method: NotifyServerMethods, params?: any): void {\n    this.client.sendNotification(method, params);\n  }\n\n  public static create(module: string) {\n    return coc.workspace.nvim.eval(`sort(map(split(globpath(&rtp, 'syntax/*.vim'), '\\n'),'fnamemodify(v:val, \":t:r\")'))`)\n      .then(langIds => new CSpellClient(module, langIds as string[]));\n  }\n\n  public isLookBackSupported(): boolean {\n    try {\n      return /(?<=\\s)x/.test(' x');\n    } catch (_) {}\n    return false;\n  }\n\n  private calcServerArgs(): string[] {\n    const args: string[] = [];\n    if (!this.isLookBackSupported()) {\n      args.push('--harmony_regexp_lookbehind');\n    }\n    return args;\n  }\n}\n"
  },
  {
    "path": "src/client/index.ts",
    "content": "export * from './client';"
  },
  {
    "path": "src/commands.ts",
    "content": "import * as coc from 'coc.nvim';\nimport { TextEdit, TextDocument, Range } from 'vscode-languageserver-protocol';\n\nimport * as CSpellSettings from './settings/CSpellSettings';\nimport * as Settings from './settings';\nexport { toggleEnableSpellChecker, enableCurrentLanguage, disableCurrentLanguage } from './settings';\n\nconst rangeContain = (origin: Range, target: Range): boolean => {\n  return origin.start.line <= target.start.line\n    && origin.start.character <= target.start.character\n    && origin.end.line >= target.end.line\n    && origin.end.character >= target.end.character;\n};\n\nexport function handlerApplyTextEdits(_client: coc.LanguageClient) {\n  return async function applyTextEdits(uri: string, documentVersion: number, edits: TextEdit[]) {\n    const doc = await coc.workspace.document;\n    const activeDoc = doc && doc.textDocument;\n    if (activeDoc && activeDoc.uri === uri) {\n      if (activeDoc.version !== documentVersion) {\n        return coc.workspace.showMessage(`Spelling changes are outdated and cannot be applied to the document.`);\n      }\n      const cfg = coc.workspace.getConfiguration(CSpellSettings.sectionCSpell);\n      if (cfg.get('fixSpellingWithRenameProvider') && edits.length === 1) {\n        const edit = edits[0];\n        if (await attemptRename(activeDoc, edit.range, edit.newText)) {\n          return;\n        }\n      }\n\n      coc.workspace.applyEdit({\n        changes: {\n          [uri]: edits\n        }\n      });\n    }\n  };\n}\n\nasync function attemptRename(document: TextDocument, range: Range, text: string): Promise<boolean | undefined> {\n  if (!coc.languages.hasProvider('rename', document)) {\n    return false;\n  }\n  if (range.start.line !== range.end.line) {\n    return false;\n  }\n  const doc = await coc.workspace.getDocument(document.uri);\n  const wordRange = doc.getWordRangeAtPosition(range.start);\n  if (!wordRange || !rangeContain(wordRange, range)) {\n    return false;\n  }\n  try {\n    const prepareRename = await coc.languages.prepareRename(document, range.start);\n    if (prepareRename === false) {\n      return false;\n    }\n  } catch (error) {\n    return false;\n  }\n  const orig = wordRange.start.character;\n  const a = range.start.character - orig;\n  const b = range.end.character - orig;\n  const docText = document.getText(wordRange);\n  const newText = [docText.slice(0, a), text, docText.slice(b)].join('');\n  const workspaceEdit = await coc.languages.provideRenameEdits(document, range.start, newText);\n  return workspaceEdit && await coc.workspace.applyEdit(workspaceEdit);\n}\n\nexport function addWordToWorkspaceDictionary(word: string, uri: string | null | coc.Uri | undefined): Thenable<void> {\n  return addWordToTarget(word, Settings.Target.Workspace, uri);\n}\n\nexport function addWordToUserDictionary(word: string): Thenable<void> {\n  return addWordToTarget(word, Settings.Target.Global, undefined);\n}\n\nasync function addWordToTarget(word: string, target: Settings.Target, uri: string | null | coc.Uri | undefined) {\n  const actualTarget = resolveTarget(target, uri);\n  await Settings.addWordToSettings(actualTarget, word);\n  const path = await determineSettingsPath(actualTarget, uri);\n  if (path) {\n    await CSpellSettings.addWordToSettingsAndUpdate(path, word);\n  }\n}\n\nexport async function addIgnoreWordToTarget(word: string, target: Settings.Target, uri: string | null | coc.Uri | undefined) {\n  const actualTarget = resolveTarget(target, uri);\n  await Settings.addIgnoreWordToSettings(actualTarget, word);\n  const path = await determineSettingsPath(actualTarget, uri);\n  if (path) {\n    await CSpellSettings.addIgnoreWordToSettingsAndUpdate(path, word);\n  }\n}\n\nexport function removeWordFromWorkspaceDictionary(word: string, uri: string | null | coc.Uri | undefined): Thenable<void> {\n  return removeWordFromTarget(word, Settings.Target.Workspace, uri);\n}\n\nexport function removeWordFromUserDictionary(word: string): Thenable<void> {\n  return removeWordFromTarget(word, Settings.Target.Global, undefined);\n}\n\nasync function removeWordFromTarget(word: string, target: Settings.Target, uri: string | null | coc.Uri | undefined) {\n  const actualTarget = resolveTarget(target, uri);\n  await Settings.removeWordFromSettings(actualTarget, word);\n  const path = await determineSettingsPath(actualTarget, uri);\n  if (path) {\n    await CSpellSettings.removeWordFromSettingsAndUpdate(path, word);\n  }\n}\n\nasync function determineSettingsPath(\n  target: Settings.ConfigTarget,\n  uri: string | null | coc.Uri | undefined\n): Promise<string | undefined> {\n  if (target !== Settings.Target.Global) {\n    const useUri = uri ? pathToUri(uri) : undefined;\n    return Settings.findExistingSettingsFileLocation(useUri);\n  }\n  return undefined;\n}\n\nfunction resolveTarget(target: Settings.Target, uri?: string | null | coc.Uri): Settings.ConfigTarget {\n  if (target === Settings.Target.Global || !Settings.hasWorkspaceLocation()) {\n    return Settings.Target.Global;\n  }\n\n  if (!uri) {\n    return Settings.Target.Workspace;\n  }\n\n  const resolvedUri = pathToUri(uri);\n  return Settings.createTargetForUri(target, resolvedUri);\n}\n\nexport async function enableLanguageId(languageId: string): Promise<void> {\n  if (!languageId) {\n    languageId = await coc.workspace.requestInput('Input enable language Id', '');\n    if (!languageId) {\n      return;\n    }\n  }\n  const doc = await coc.workspace.document;\n  const uri = doc && doc.textDocument.uri;\n  return Settings.enableLanguageIdForClosestTarget(languageId, true, uri ? coc.Uri.parse(uri) : undefined);\n}\n\nexport async function disableLanguageId(languageId: string): Promise<void> {\n  if (!languageId) {\n    languageId = await coc.workspace.requestInput('Input disable language Id', '');\n    if (!languageId) {\n      return;\n    }\n  }\n  const doc = await coc.workspace.document;\n  const uri = doc && doc.textDocument.uri;\n  return Settings.enableLanguageIdForClosestTarget(languageId, false, uri ? coc.Uri.parse(uri) : undefined);\n}\n\nexport function userCommandOnCurrentSelectionOrPrompt(\n  prompt: string,\n  fnAction: (text: string, uri: coc.Uri | undefined) => Thenable<void>\n): () => Thenable<void> {\n  return async function () {\n    const document = await coc.workspace.document;\n    const mode = await coc.workspace.nvim.call('visualmode') as string;\n    let range = mode ? await coc.workspace.getSelectedRange(mode, document) : null;\n    let value = range ? document.textDocument.getText(range) : '';\n    if (range && !(range.start.line !== range.end.line || range.start.character !== range.end.character)) {\n      fnAction(value, coc.Uri.parse(document.textDocument.uri));\n    } else {\n      const position = await coc.workspace.getCursorPosition();\n      if (position && document && document.textDocument) {\n        range = document.getWordRangeAtPosition(position);\n        value = range ? document.textDocument.getText(range) : '';\n      }\n      const word = await coc.workspace.requestInput(prompt, value);\n      word && fnAction(word, coc.Uri.parse(document.textDocument.uri));\n    }\n  };\n}\n\nfunction pathToUri(uri: string | coc.Uri): coc.Uri {\n  if (uri instanceof coc.Uri) {\n    return uri;\n  }\n  return coc.Uri.parse(uri);\n}\n"
  },
  {
    "path": "src/dict.ts",
    "content": "import * as vim from 'cspell-dict-vimlang';\n\nimport {ExtensionApi} from './extensionApi';\n\n// enable default dict\nconst dicts  = [\n  vim\n];\n\nexport function activateDict(api: ExtensionApi) {\n  dicts.forEach(dict => {\n    const path = dict.getConfigLocation();\n    // We need to register the dictionary configuration with the Code Spell Checker Extension\n    api && api.registerConfig && api.registerConfig(path);\n  });\n}\n"
  },
  {
    "path": "src/extensionApi.ts",
    "content": "import * as coc from 'coc.nvim';\nimport {CSpellClient} from './client';\nimport {ConfigTarget} from './settings';\n\nexport interface ExtensionApi {\n    registerConfig(path: string): void;\n    triggerGetSettings(): void;\n    enableLanguageId(languageId: string, uri?: string): Thenable<void>;\n    disableLanguageId(languageId: string, uri?: string): Thenable<void>;\n    enableCurrentLanguage(): Thenable<void>;\n    disableCurrentLanguage(): Thenable<void>;\n    addWordToUserDictionary(word: string): Thenable<void>;\n    addWordToWorkspaceDictionary(word: string, uri?: string | null | coc.Uri): Thenable<void>;\n    enableLocal(target: ConfigTarget, local: string): Thenable<void>;\n    disableLocal(target: ConfigTarget, local: string): Thenable<void>;\n    updateSettings(): boolean;\n    cSpellClient(): CSpellClient;\n}\n"
  },
  {
    "path": "src/fileTypes/fileTypeMap.json",
    "content": "{\n  \"fileTypeNames\": [\n    \"1C (BSL).bsl\",\n    \"1C (MDO).mdo\",\n    \"Adobe Illustrator.ai\",\n    \"Adobe Photoshop.psd\",\n    \"ApexComponent.component\",\n    \"archive.zip\",\n    \"Assembly.asm\",\n    \"Assembly.s\",\n    \"Audio File.wav\",\n    \"Batch.bat\",\n    \"Bower.json\",\n    \"C Sharp.cs\",\n    \"C.c\",\n    \"C++.cpp\",\n    \"Cake Build.cake\",\n    \"Cake PHP.ctp\",\n    \"cert.cert\",\n    \"Closure.clj\",\n    \"Cmd.cmd\",\n    \"CoffeScript.coffee\",\n    \"ColdFusion.cfm\",\n    \"crystal_embedded.ecr\",\n    \"crystal_embedded.slang\",\n    \"crystal.cr\",\n    \"CSS.css\",\n    \"CSV.csv\",\n    \"D.d\",\n    \"docker-compose.yml\",\n    \"docker-healthcheck\",\n    \"Dockerfile\",\n    \"EcmaScript.es6\",\n    \"EJS.ejs\",\n    \"elixir_script.exs\",\n    \"elixir.ex\",\n    \"Elm.elm\",\n    \"Excell.xlsx\",\n    \"F Sharp Script.fsx\",\n    \"F Sharp.fs\",\n    \"Favicon.ico\",\n    \"firebase.json\",\n    \"geckodriver\",\n    \"Go.go\",\n    \"Gradle.gradle\",\n    \"Grails.groovy\",\n    \"Gruntfile.js\",\n    \"gulpfile.babel.js\",\n    \"Gulpfile.js\",\n    \"Hacklang.hh\",\n    \"Haml.haml\",\n    \"Handlebars.hbs\",\n    \"Haskell.hs\",\n    \"Haxe make.hxml\",\n    \"Haxe module.hx\",\n    \"Haxe project.hxp\",\n    \"Haxe script.hxs\",\n    \"HTML.erb\",\n    \"HTML.html\",\n    \"Image.ai\",\n    \"ionic.config.json\",\n    \"ionic.project\",\n    \"Jade.jade\",\n    \"Jar.jar\",\n    \"Java.java\",\n    \"JavaScript.js\",\n    \"JavaScript.spec.js\",\n    \"Jenkinsfile\",\n    \"Jinja.jinja2\",\n    \"JSON.json\",\n    \"Julia.jl\",\n    \"karma.conf.js\",\n    \"keyfile.key\",\n    \"Kotlin Script.kts\",\n    \"Kotlin.kt\",\n    \"Latex.tex\",\n    \"Less.less\",\n    \"LICENSE\",\n    \"LiterateHaskell.lhs\",\n    \"LiveScript.ls\",\n    \"Lua.lua\",\n    \"Makefile\",\n    \"Markdown.md\",\n    \"mime.types\",\n    \"Mustache.mustache\",\n    \"mvnw\",\n    \"nginx.conf\",\n    \"Nunjucks.njk\",\n    \"Objective C.h\",\n    \"Objective C.m\",\n    \"oCaml.ml\",\n    \"Odata.odata\",\n    \"PDF.pdf\",\n    \"Perl.pl\",\n    \"PHP.php.inc\",\n    \"PHP.php\",\n    \"Powershell.manifest.psd1\",\n    \"Powershell.module.psm1\",\n    \"Powershell.ps1\",\n    \"Procfile\",\n    \"Pug.pug\",\n    \"Puppet.pp\",\n    \"Python.py\",\n    \"R.R\",\n    \"Raml.raml\",\n    \"React Coffee.cjsx\",\n    \"React Typescript.tsx\",\n    \"React.jsx\",\n    \"rollup.config.js\",\n    \"Ruby.rb\",\n    \"Rust.rs\",\n    \"Sass.scss\",\n    \"Sbt.sbt\",\n    \"Scala.scala\",\n    \"Settings.config\",\n    \"Shell.sh\",\n    \"Shopify.liquid\",\n    \"Slim.slim\",\n    \"Smarty.smarty.tpl\",\n    \"Solidity.sol\",\n    \"Spring.springBeans\",\n    \"SQL.sql\",\n    \"Stache.stache\",\n    \"Stylus.styl\",\n    \"Sublime.sublime-project\",\n    \"Sugarss.sss\",\n    \"SVGX.svgx\",\n    \"Swift.swift\",\n    \"Temp.tmp\",\n    \"Terraform.tf.json\",\n    \"Terraform.tf\",\n    \"Text.txt\",\n    \"TODO\",\n    \"TOML.toml\",\n    \"Twig.twig\",\n    \"Typescript.ts\",\n    \"Vala.vala\",\n    \"Video File.mov\",\n    \"Vue.vue\",\n    \"WebAssembly Text.wat\",\n    \"WebAssembly.wasm\",\n    \"webpack.config.js\",\n    \"Widget.wgt\",\n    \"Word.docx\",\n    \"XML.xml\",\n    \"yarn.lock\",\n    \"YML.yml\"\n    ]\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "import * as coc from 'coc.nvim';\n\nimport * as path from 'path';\nimport * as settings from './settings';\nimport {CSpellClient} from './client';\nimport { initStatusBar } from './statusbar';\nimport {userCommandOnCurrentSelectionOrPrompt, handlerApplyTextEdits} from './commands';\nimport * as commands from './commands';\nimport { ExtensionApi } from './extensionApi';\nimport {activateDict} from './dict';\n\nexport async function activate(context: coc.ExtensionContext): Promise<ExtensionApi> {\n  // The server is implemented in node\n  const serverModule = context.asAbsolutePath(path.join('server', 'server.js'));\n\n  // Get the cSpell Client\n  const client = await CSpellClient.create(serverModule);\n  // Start the client.\n  const clientDispose = client.start();\n\n  function triggerGetSettings() {\n    client.triggerSettingsRefresh();\n  }\n\n  function registerConfig(path: string) {\n    client.registerConfiguration(path);\n  }\n\n  function splitTextFn(\n    apply: (word: string, uri: string | coc.Uri | null | undefined) => Thenable<void>\n  ): (word: string, uri: string | coc.Uri | null | undefined) => Thenable<void> {\n    return async (word: string, uri: string | coc.Uri | null | undefined) => {\n      const doc = await coc.workspace.document;\n      const document = doc && doc.textDocument;\n      const uriToUse = uri || document && document.uri || null;\n      return client.splitTextIntoDictionaryWords(word)\n        .then(result => result.words)\n        .then(words => apply(words.join(' '), uriToUse));\n    };\n  }\n\n  const actionAddWordToWorkspace = userCommandOnCurrentSelectionOrPrompt(\n    'Add Word to Workspace Dictionary',\n    splitTextFn(commands.addWordToWorkspaceDictionary)\n  );\n  const actionAddWordToDictionary = userCommandOnCurrentSelectionOrPrompt(\n    'Add Word to User Dictionary',\n    splitTextFn(commands.addWordToUserDictionary)\n  );\n\n  const actionAddIgnoreWord = userCommandOnCurrentSelectionOrPrompt(\n    'Ignore Word',\n    splitTextFn((word, uri) => commands.addIgnoreWordToTarget(word, settings.Target.Workspace, uri))\n  );\n  const actionAddIgnoreWordToWorkspace = userCommandOnCurrentSelectionOrPrompt(\n    'Ignore Word in Workspace Settings',\n    splitTextFn((word, uri) => commands.addIgnoreWordToTarget(word, settings.Target.Workspace, uri))\n  );\n  const actionAddIgnoreWordToUser = userCommandOnCurrentSelectionOrPrompt(\n    'Ignore Word in User Settings',\n    splitTextFn((word, uri) => commands.addIgnoreWordToTarget(word, settings.Target.Global, uri))\n  );\n\n  const actionRemoveWordFromWorkspaceDictionary = userCommandOnCurrentSelectionOrPrompt(\n    'Remove Word from Dictionary',\n    splitTextFn(commands.removeWordFromWorkspaceDictionary)\n  );\n  const actionRemoveWordFromDictionary = userCommandOnCurrentSelectionOrPrompt(\n    'Remove Word from Dictionary',\n    splitTextFn(commands.removeWordFromUserDictionary)\n  );\n\n  initStatusBar(context, client);\n\n  // Push the disposable to the context's subscriptions so that the\n  // client can be deactivated on extension deactivation\n  context.subscriptions.push(\n    clientDispose,\n    // internal commands that server uses\n    coc.commands.registerCommand('cSpell.editText', handlerApplyTextEdits(client.client), null, true),\n    coc.commands.registerCommand('cSpell.addWordToDictionarySilent', commands.addWordToWorkspaceDictionary, null, true),\n    coc.commands.registerCommand('cSpell.addWordToWorkspaceDictionarySilent', commands.addWordToWorkspaceDictionary, null, true),\n    coc.commands.registerCommand('cSpell.addWordToUserDictionarySilent', commands.addWordToUserDictionary, null, true),\n\n    coc.commands.registerCommand('cSpell.addWordToDictionary', actionAddWordToWorkspace),\n    coc.commands.registerCommand('cSpell.addWordToWorkspaceDictionary', actionAddWordToWorkspace),\n    coc.commands.registerCommand('cSpell.addWordToUserDictionary', actionAddWordToDictionary),\n\n    coc.commands.registerCommand('cSpell.addIgnoreWord', actionAddIgnoreWord),\n    coc.commands.registerCommand('cSpell.addIgnoreWordToFolder', actionAddIgnoreWordToWorkspace),\n    coc.commands.registerCommand('cSpell.addIgnoreWordToWorkspace', actionAddIgnoreWordToWorkspace),\n    coc.commands.registerCommand('cSpell.addIgnoreWordToUser', actionAddIgnoreWordToUser),\n\n    coc.commands.registerCommand('cSpell.removeWordFromFolderDictionary', actionRemoveWordFromWorkspaceDictionary),\n    coc.commands.registerCommand('cSpell.removeWordFromWorkspaceDictionary', actionRemoveWordFromWorkspaceDictionary),\n    coc.commands.registerCommand('cSpell.removeWordFromUserDictionary', actionRemoveWordFromDictionary),\n\n    coc.commands.registerCommand('cSpell.enableLanguage', commands.enableLanguageId),\n    coc.commands.registerCommand('cSpell.disableLanguage', commands.disableLanguageId),\n    coc.commands.registerCommand('cSpell.enableForWorkspace', () => settings.setEnableSpellChecking(settings.Target.Workspace, false)),\n    coc.commands.registerCommand('cSpell.disableForWorkspace', () => settings.setEnableSpellChecking(settings.Target.Workspace, false)),\n    coc.commands.registerCommand('cSpell.toggleEnableSpellChecker', commands.toggleEnableSpellChecker),\n    coc.commands.registerCommand('cSpell.enableCurrentLanguage', commands.enableCurrentLanguage),\n    coc.commands.registerCommand('cSpell.disableCurrentLanguage', commands.disableCurrentLanguage),\n    settings.watchSettingsFiles(triggerGetSettings),\n  );\n\n  const server = {\n    registerConfig,\n    triggerGetSettings,\n    enableLanguageId: commands.enableLanguageId,\n    disableLanguageId: commands.disableLanguageId,\n    enableCurrentLanguage: commands.enableCurrentLanguage,\n    disableCurrentLanguage: commands.disableCurrentLanguage,\n    addWordToUserDictionary: commands.addWordToUserDictionary,\n    addWordToWorkspaceDictionary: commands.addWordToWorkspaceDictionary,\n    enableLocal: settings.enableLocal,\n    disableLocal: settings.disableLocal,\n    updateSettings: () => false,\n    cSpellClient: () => client,\n  };\n\n  // activate default dicts\n  activateDict(server);\n\n  return server;\n}\n"
  },
  {
    "path": "src/iso639-1/index.ts",
    "content": "import { codes } from './languageCodes';\n\nexport interface LangCountryPair {\n    lang: string;\n    country: string;\n}\n\nconst langCodes = new Map<string, LangCountryPair>(\n    codes\n        .map((parts) => {\n            const [code, lang, country = ''] = parts;\n            return [code, { lang, country }] as [string, LangCountryPair];\n        })\n);\n\nconst regExReplace = /^([a-z]{2})[-_]?([a-z]{0,2})$/i;\n// const regExValidate = /^([a-z]{2})(-[A-Z]{2})?$/;\n\nexport function normalizeCode(code: string) {\n    return code.replace(regExReplace, (match: string, p1: string, p2: string) => {\n        const lang = p1.toLowerCase();\n        const local = p2.toUpperCase();\n        return local ? `${lang}-${local}` : lang;\n    });\n}\n\nexport function isValidCode(code: string) {\n    return langCodes.has(code);\n}\n\nexport function lookupCode(code: string) {\n    return langCodes.get(code);\n}\n"
  },
  {
    "path": "src/iso639-1/languageCodes.ts",
    "content": "export const codes: string[][] = [\n    // ['code', 'language'[', ''local']],\n    ['af', 'Afrikaans'],\n    ['af-NA', 'Afrikaans', 'Namibia'],\n    ['af-ZA', 'Afrikaans', 'South Africa'],\n    ['ak', 'Akan'],\n    ['ak-GH', 'Akan', 'Ghana'],\n    ['am', 'Amharic'],\n    ['am-ET', 'Amharic', 'Ethiopia'],\n    ['ar', 'Arabic'],\n    ['ar-1', 'Arabic'],\n    ['ar-AE', 'Arabic', 'United Arab Emirates'],\n    ['ar-BH', 'Arabic', 'Bahrain'],\n    ['ar-DJ', 'Arabic', 'Djibouti'],\n    ['ar-DZ', 'Arabic', 'Algeria'],\n    ['ar-EG', 'Arabic', 'Egypt'],\n    ['ar-EH', 'Arabic'],\n    ['ar-ER', 'Arabic', 'Eritrea'],\n    ['ar-IL', 'Arabic', 'Israel'],\n    ['ar-IQ', 'Arabic', 'Iraq'],\n    ['ar-JO', 'Arabic', 'Jordan'],\n    ['ar-KM', 'Arabic', 'Comoros'],\n    ['ar-KW', 'Arabic', 'Kuwait'],\n    ['ar-LB', 'Arabic', 'Lebanon'],\n    ['ar-LY', 'Arabic', 'Libya'],\n    ['ar-MA', 'Arabic', 'Morocco'],\n    ['ar-MR', 'Arabic', 'Mauritania'],\n    ['ar-OM', 'Arabic', 'Oman'],\n    ['ar-PS', 'Arabic'],\n    ['ar-QA', 'Arabic', 'Qatar'],\n    ['ar-SA', 'Arabic', 'Saudi Arabia'],\n    ['ar-SD', 'Arabic', 'Sudan'],\n    ['ar-SO', 'Arabic', 'Somalia'],\n    ['ar-SS', 'Arabic'],\n    ['ar-SY', 'Arabic', 'Syria'],\n    ['ar-TD', 'Arabic', 'Chad'],\n    ['ar-TN', 'Arabic', 'Tunisia'],\n    ['ar-YE', 'Arabic', 'Yemen'],\n    ['as', 'Assamese'],\n    ['as-IN', 'Assamese', 'India'],\n    ['az', 'Azerbaijani'],\n    ['az-AZ', 'Azerbaijani', 'Azerbaijan'],\n    ['be', 'Belarusian'],\n    ['be-BY', 'Belarusian', 'Belarus'],\n    ['bg', 'Bulgarian'],\n    ['bg-BG', 'Bulgarian', 'Bulgaria'],\n    ['bm', 'Bambara'],\n    ['bm-ML', 'Bambara', 'Mali'],\n    ['bn', 'Bengali'],\n    ['bn-BD', 'Bengali', 'Bangladesh'],\n    ['bn-IN', 'Bengali', 'India'],\n    ['bo', 'Tibetan'],\n    ['bo-CN', 'Tibetan', 'China'],\n    ['bo-IN', 'Tibetan', 'India'],\n    ['br', 'Breton'],\n    ['br-FR', 'Breton', 'France'],\n    ['bs', 'Bosnian'],\n    ['bs-BA', 'Bosnian', 'Bosnia and Herzegovina'],\n    ['ca', 'Catalan'],\n    ['ca-AD', 'Catalan', 'Andorra'],\n    ['ca-ES', 'Catalan', 'Spain'],\n    ['ca-FR', 'Catalan', 'France'],\n    ['ca-IT', 'Catalan', 'Italy'],\n    ['ce', 'Chechen'],\n    ['ce-RU', 'Chechen', 'Russia'],\n    ['cs', 'Czech'],\n    ['cs-CZ', 'Czech', 'Czech Republic'],\n    ['cu', 'Old Slavonic'],\n    ['cu-RU', 'Old Slavonic', 'Russia'],\n    ['cy', 'Welsh'],\n    ['cy-GB', 'Welsh', 'United Kingdom'],\n    ['da', 'Danish'],\n    ['da-DK', 'Danish', 'Denmark'],\n    ['da-GL', 'Danish', 'Greenland'],\n    ['de', 'German'],\n    ['de-AT', 'German', 'Austria'],\n    ['de-BE', 'German', 'Belgium'],\n    ['de-CH', 'German', 'Switzerland'],\n    ['de-DE', 'German', 'Germany'],\n    ['de-IT', 'German', 'Italy'],\n    ['de-LI', 'German', 'Liechtenstein'],\n    ['de-LU', 'German', 'Luxembourg'],\n    ['dz', 'Dzongkha'],\n    ['dz-BT', 'Dzongkha', 'Bhutan'],\n    ['ee', 'Ewe'],\n    ['ee-GH', 'Ewe', 'Ghana'],\n    ['ee-TG', 'Ewe', 'Togo'],\n    ['el', 'Greek', 'Modern (1453-)'],\n    ['el-CY', 'Greek', 'Cyprus'],\n    ['el-GR', 'Greek', 'Greece'],\n    ['en', 'English'],\n    ['en-AG', 'English', 'Antigua and Barbuda'],\n    ['en-AI', 'English', 'Anguilla'],\n    ['en-AS', 'English', 'American Samoa'],\n    ['en-AT', 'English', 'Austria'],\n    ['en-AU', 'English', 'Australia'],\n    ['en-BB', 'English', 'Barbados'],\n    ['en-BE', 'English', 'Belgium'],\n    ['en-BI', 'English', 'Burundi'],\n    ['en-BM', 'English', 'Bermuda'],\n    ['en-BS', 'English', 'Bahamas'],\n    ['en-BW', 'English', 'Botswana'],\n    ['en-BZ', 'English', 'Belize'],\n    ['en-CA', 'English', 'Canada'],\n    ['en-CC', 'English', 'Cocos (Keeling) Islands'],\n    ['en-CH', 'English', 'Switzerland'],\n    ['en-CK', 'English', 'Cook Islands'],\n    ['en-CM', 'English', 'Cameroon'],\n    ['en-CX', 'English', 'Christmas Island'],\n    ['en-CY', 'English', 'Cyprus'],\n    ['en-DE', 'English', 'Germany'],\n    ['en-DG', 'English'],\n    ['en-DK', 'English', 'Denmark'],\n    ['en-DM', 'English', 'Dominica'],\n    ['en-ER', 'English', 'Eritrea'],\n    ['en-FI', 'English', 'Finland'],\n    ['en-FJ', 'English', 'Fiji'],\n    ['en-FK', 'English', 'Falkland Islands (Islas Malvinas)'],\n    ['en-FM', 'English', 'Micronesia'],\n    ['en-GB', 'English', 'United Kingdom'],\n    ['en-GD', 'English', 'Grenada'],\n    ['en-GG', 'English', 'Guernsey'],\n    ['en-GH', 'English', 'Ghana'],\n    ['en-GI', 'English', 'Gibraltar'],\n    ['en-GM', 'English', 'Gambia'],\n    ['en-GU', 'English', 'Guam'],\n    ['en-GY', 'English', 'Guyana'],\n    ['en-HK', 'English', 'Hong Kong'],\n    ['en-IE', 'English', 'Ireland'],\n    ['en-IL', 'English', 'Israel'],\n    ['en-IM', 'English', 'Isle of Man'],\n    ['en-IN', 'English', 'India'],\n    ['en-IO', 'English', 'British Indian Ocean Territory'],\n    ['en-JE', 'English', 'Jersey'],\n    ['en-JM', 'English', 'Jamaica'],\n    ['en-KE', 'English', 'Kenya'],\n    ['en-KI', 'English', 'Kiribati'],\n    ['en-KN', 'English', 'Saint Kitts and Nevis'],\n    ['en-KY', 'English', 'Cayman Islands'],\n    ['en-LC', 'English', 'Saint Lucia'],\n    ['en-LR', 'English', 'Liberia'],\n    ['en-LS', 'English', 'Lesotho'],\n    ['en-MG', 'English', 'Madagascar'],\n    ['en-MH', 'English', 'Marshall Islands'],\n    ['en-MO', 'English', 'Macau'],\n    ['en-MP', 'English', 'Northern Mariana Islands'],\n    ['en-MS', 'English', 'Montserrat'],\n    ['en-MT', 'English', 'Malta'],\n    ['en-MU', 'English', 'Mauritius'],\n    ['en-MW', 'English', 'Malawi'],\n    ['en-MY', 'English', 'Malaysia'],\n    ['en-NA', 'English', 'Namibia'],\n    ['en-NF', 'English', 'Norfolk Island'],\n    ['en-NG', 'English', 'Nigeria'],\n    ['en-NL', 'English', 'Netherlands'],\n    ['en-NR', 'English', 'Nauru'],\n    ['en-NU', 'English', 'Niue'],\n    ['en-NZ', 'English', 'New Zealand'],\n    ['en-PG', 'English', 'Papua New Guinea'],\n    ['en-PH', 'English', 'Philippines'],\n    ['en-PK', 'English', 'Pakistan'],\n    ['en-PN', 'English', 'Pitcairn Islands'],\n    ['en-PR', 'English', 'Puerto Rico'],\n    ['en-PW', 'English', 'Palau'],\n    ['en-RW', 'English', 'Rwanda'],\n    ['en-SB', 'English', 'Solomon Islands'],\n    ['en-SC', 'English', 'Seychelles'],\n    ['en-SD', 'English', 'Sudan'],\n    ['en-SE', 'English', 'Sweden'],\n    ['en-SG', 'English', 'Singapore'],\n    ['en-SH', 'English', 'Saint Helena'],\n    ['en-SI', 'English', 'Slovenia'],\n    ['en-SL', 'English', 'Sierra Leone'],\n    ['en-SS', 'English'],\n    ['en-SX', 'English'],\n    ['en-SZ', 'English', 'Swaziland'],\n    ['en-TC', 'English', 'Turks and Caicos Islands'],\n    ['en-TK', 'English', 'Tokelau'],\n    ['en-TO', 'English', 'Tonga'],\n    ['en-TT', 'English', 'Trinidad and Tobago'],\n    ['en-TV', 'English', 'Tuvalu'],\n    ['en-TZ', 'English', 'Tanzania'],\n    ['en-UG', 'English', 'Uganda'],\n    ['en-UM', 'English', 'Baker Island'],\n    ['en-US', 'English', 'United States'],\n    ['en-VC', 'English', 'Saint Vincent and the Grenadines'],\n    ['en-VG', 'English', 'British Virgin Islands'],\n    ['en-VI', 'English', 'U.S. Virgin Islands'],\n    ['en-VU', 'English', 'Vanuatu'],\n    ['en-WS', 'English', 'Samoa'],\n    ['en-ZA', 'English', 'South Africa'],\n    ['en-ZM', 'English', 'Zambia'],\n    ['en-ZW', 'English', 'Zimbabwe'],\n    ['eo', 'Esperanto'],\n    ['es', 'Spanish'],\n    ['es-AR', 'Spanish', 'Argentina'],\n    ['es-BO', 'Spanish', 'Bolivia'],\n    ['es-BR', 'Spanish', 'Brazil'],\n    ['es-BZ', 'Spanish', 'Belize'],\n    ['es-CL', 'Spanish', 'Chile'],\n    ['es-CO', 'Spanish', 'Colombia'],\n    ['es-CR', 'Spanish', 'Costa Rica'],\n    ['es-CU', 'Spanish', 'Cuba'],\n    ['es-DO', 'Spanish', 'Dominican Republic'],\n    ['es-EA', 'Spanish'],\n    ['es-EC', 'Spanish', 'Ecuador'],\n    ['es-ES', 'Spanish', 'Spain'],\n    ['es-GQ', 'Spanish', 'Equatorial Guinea'],\n    ['es-GT', 'Spanish', 'Guatemala'],\n    ['es-HN', 'Spanish', 'Honduras'],\n    ['es-IC', 'Spanish'],\n    ['es-MX', 'Spanish', 'Mexico'],\n    ['es-NI', 'Spanish', 'Nicaragua'],\n    ['es-PA', 'Spanish', 'Panama'],\n    ['es-PE', 'Spanish', 'Peru'],\n    ['es-PH', 'Spanish', 'Philippines'],\n    ['es-PR', 'Spanish', 'Puerto Rico'],\n    ['es-PY', 'Spanish', 'Paraguay'],\n    ['es-SV', 'Spanish', 'El Salvador'],\n    ['es-US', 'Spanish', 'United States'],\n    ['es-UY', 'Spanish', 'Uruguay'],\n    ['es-VE', 'Spanish', 'Venezuela'],\n    ['et', 'Estonian'],\n    ['et-EE', 'Estonian', 'Estonia'],\n    ['eu', 'Basque'],\n    ['eu-ES', 'Basque', 'Spain'],\n    ['fa', 'Persian'],\n    ['fa-AF', 'Persian', 'Afghanistan'],\n    ['fa-IR', 'Persian', 'Iran'],\n    ['ff', 'Fulah'],\n    ['ff-CM', 'Fulah', 'Cameroon'],\n    ['ff-GN', 'Fulah', 'Guinea'],\n    ['ff-MR', 'Fulah', 'Mauritania'],\n    ['ff-SN', 'Fulah', 'Senegal'],\n    ['fi', 'Finnish'],\n    ['fi-FI', 'Finnish', 'Finland'],\n    ['fo', 'Faroese'],\n    ['fo-DK', 'Faroese', 'Denmark'],\n    ['fo-FO', 'Faroese', 'Faroe Islands'],\n    ['fr', 'French'],\n    ['fr-BE', 'French', 'Belgium'],\n    ['fr-BF', 'French', 'Burkina Faso'],\n    ['fr-BI', 'French', 'Burundi'],\n    ['fr-BJ', 'French', 'Benin'],\n    ['fr-BL', 'French'],\n    ['fr-CA', 'French', 'Canada'],\n    ['fr-CD', 'French', 'Congo'],\n    ['fr-CF', 'French', 'Central African Republic'],\n    ['fr-CG', 'French', 'Congo'],\n    ['fr-CH', 'French', 'Switzerland'],\n    ['fr-CI', \"French, Cote d'Ivoire (Ivory Coast)\"],\n    ['fr-CM', 'French', 'Cameroon'],\n    ['fr-DJ', 'French', 'Djibouti'],\n    ['fr-DZ', 'French', 'Algeria'],\n    ['fr-FR', 'French', 'France'],\n    ['fr-GA', 'French', 'Gabon'],\n    ['fr-GF', 'French', 'French Guiana'],\n    ['fr-GN', 'French', 'Guinea'],\n    ['fr-GP', 'French', 'Saint Barthelemy'],\n    ['fr-GQ', 'French', 'Equatorial Guinea'],\n    ['fr-HT', 'French', 'Haiti'],\n    ['fr-KM', 'French', 'Comoros'],\n    ['fr-LU', 'French', 'Luxembourg'],\n    ['fr-MA', 'French', 'Morocco'],\n    ['fr-MC', 'French', 'Monaco'],\n    ['fr-MF', 'French'],\n    ['fr-MG', 'French', 'Madagascar'],\n    ['fr-ML', 'French', 'Mali'],\n    ['fr-MQ', 'French', 'Martinique'],\n    ['fr-MR', 'French', 'Mauritania'],\n    ['fr-MU', 'French', 'Mauritius'],\n    ['fr-NC', 'French', 'New Caledonia'],\n    ['fr-NE', 'French', 'Niger'],\n    ['fr-PF', 'French', 'French Polynesia'],\n    ['fr-PM', 'French', 'Saint Pierre and Miquelon'],\n    ['fr-RE', 'French', 'Reunion'],\n    ['fr-RW', 'French', 'Rwanda'],\n    ['fr-SC', 'French', 'Seychelles'],\n    ['fr-SN', 'French', 'Senegal'],\n    ['fr-SY', 'French', 'Syria'],\n    ['fr-TD', 'French', 'Chad'],\n    ['fr-TG', 'French', 'Togo'],\n    ['fr-TN', 'French', 'Tunisia'],\n    ['fr-VU', 'French', 'Vanuatu'],\n    ['fr-WF', 'French', 'Wallis and Futuna'],\n    ['fr-YT', 'French', 'Mayotte'],\n    ['fy', 'Western Frisian'],\n    ['fy-NL', 'Western Frisian', 'Netherlands'],\n    ['ga', 'Irish'],\n    ['ga-IE', 'Irish', 'Ireland'],\n    ['gd', 'Gaelic'],\n    ['gd-GB', 'Gaelic', 'United Kingdom'],\n    ['gl', 'Galician'],\n    ['gl-ES', 'Galician', 'Spain'],\n    ['gu', 'Gujarati'],\n    ['gu-IN', 'Gujarati', 'India'],\n    ['gv', 'Manx'],\n    ['gv-IM', 'Manx', 'Isle of Man'],\n    ['ha', 'Hausa'],\n    ['ha-GH', 'Hausa', 'Ghana'],\n    ['ha-NE', 'Hausa', 'Niger'],\n    ['ha-NG', 'Hausa', 'Nigeria'],\n    ['he', 'Hebrew'],\n    ['he-IL', 'Hebrew', 'Israel'],\n    ['hi', 'Hindi'],\n    ['hi-IN', 'Hindi', 'India'],\n    ['hr', 'Croatian'],\n    ['hr-BA', 'Croatian', 'Bosnia and Herzegovina'],\n    ['hr-HR', 'Croatian', 'Croatia'],\n    ['hu', 'Hungarian'],\n    ['hu-HU', 'Hungarian', 'Hungary'],\n    ['hy', 'Armenian'],\n    ['hy-AM', 'Armenian', 'Armenia'],\n    ['id', 'Indonesian'],\n    ['id-ID', 'Indonesian', 'Indonesia'],\n    ['ig', 'Igbo'],\n    ['ig-NG', 'Igbo', 'Nigeria'],\n    ['ii', 'Sichuan Yi'],\n    ['ii-CN', 'Sichuan Yi', 'China'],\n    ['is', 'Icelandic'],\n    ['is-IS', 'Icelandic', 'Iceland'],\n    ['it', 'Italian'],\n    ['it-CH', 'Italian', 'Switzerland'],\n    ['it-IT', 'Italian', 'Italy'],\n    ['it-SM', 'Italian', 'San Marino'],\n    ['it-VA', 'Italian', 'Vatican City'],\n    ['ja', 'Japanese'],\n    ['ja-JP', 'Japanese', 'Japan'],\n    ['ka', 'Georgian'],\n    ['ka-GE', 'Georgian', 'Georgia'],\n    ['ki', 'Kikuyu'],\n    ['ki-KE', 'Kikuyu', 'Kenya'],\n    ['kk', 'Kazakh'],\n    ['kk-KZ', 'Kazakh', 'Kazakhstan'],\n    ['kl', 'Kalaallisut'],\n    ['kl-GL', 'Kalaallisut', 'Greenland'],\n    ['km', 'Central Khmer'],\n    ['km-KH', 'Central Khmer', 'Cambodia'],\n    ['kn', 'Kannada'],\n    ['kn-IN', 'Kannada', 'India'],\n    ['ko', 'Korean'],\n    ['ko-KP', 'Korean', 'Korea'],\n    ['ko-KR', 'Korean', 'Korea'],\n    ['ks', 'Kashmiri'],\n    ['ks-IN', 'Kashmiri', 'India'],\n    ['kw', 'Cornish'],\n    ['kw-GB', 'Cornish', 'United Kingdom'],\n    ['ky', 'Kirghiz'],\n    ['ky-KG', 'Kirghiz', 'Kyrgyzstan'],\n    ['lb', 'Luxembourgish'],\n    ['lb-LU', 'Luxembourgish', 'Luxembourg'],\n    ['lg', 'Ganda'],\n    ['lg-UG', 'Ganda', 'Uganda'],\n    ['ln', 'Lingala'],\n    ['ln-AO', 'Lingala', 'Angola'],\n    ['ln-CD', 'Lingala', 'Congo'],\n    ['ln-CF', 'Lingala', 'Central African Republic'],\n    ['ln-CG', 'Lingala', 'Congo'],\n    ['lo', 'Lao'],\n    ['lo-LA', 'Lao', 'Laos'],\n    ['lt', 'Lithuanian'],\n    ['lt-LT', 'Lithuanian', 'Lithuania'],\n    ['lu', 'Luba-Katanga'],\n    ['lu-CD', 'Luba-Katanga', 'Congo'],\n    ['lv', 'Latvian'],\n    ['lv-LV', 'Latvian', 'Latvia'],\n    ['mg', 'Malagasy'],\n    ['mg-MG', 'Malagasy', 'Madagascar'],\n    ['mk', 'Macedonian'],\n    ['mk-MK', 'Macedonian', 'Macedonia'],\n    ['ml', 'Malayalam'],\n    ['ml-IN', 'Malayalam', 'India'],\n    ['mn', 'Mongolian'],\n    ['mn-MN', 'Mongolian', 'Mongolia'],\n    ['mr', 'Marathi'],\n    ['mr-IN', 'Marathi', 'India'],\n    ['ms', 'Malay'],\n    ['ms-BN', 'Malay', 'Brunei'],\n    ['ms-MY', 'Malay', 'Malaysia'],\n    ['ms-SG', 'Malay', 'Singapore'],\n    ['mt', 'Maltese'],\n    ['mt-MT', 'Maltese', 'Malta'],\n    ['my', 'Burmese'],\n    ['my-MM', 'Burmese', 'Myanmar (Burma)'],\n    ['nb', 'Bokmål Norwegian'],\n    ['nb-NO', 'Bokmål Norwegian', 'Norway'],\n    ['nb-SJ', 'Bokmål Norwegian', 'Svalbard'],\n    ['nd', 'Ndebele, North'],\n    ['nd-ZW', 'Ndebele, North', 'Zimbabwe'],\n    ['ne', 'Nepali'],\n    ['ne-IN', 'Nepali', 'India'],\n    ['ne-NP', 'Nepali', 'Nepal'],\n    ['nl', 'Dutch'],\n    ['nl-AW', 'Dutch', 'Aruba'],\n    ['nl-BE', 'Dutch', 'Belgium'],\n    ['nl-BQ', 'Dutch'],\n    ['nl-CW', 'Dutch'],\n    ['nl-NL', 'Dutch', 'Netherlands'],\n    ['nl-SR', 'Dutch', 'Suriname'],\n    ['nl-SX', 'Dutch'],\n    ['nn', 'Norwegian Nynorsk'],\n    ['nn-NO', 'Norwegian Nynorsk', 'Norway'],\n    ['om', 'Oromo'],\n    ['om-ET', 'Oromo', 'Ethiopia'],\n    ['om-KE', 'Oromo', 'Kenya'],\n    ['or', 'Oriya'],\n    ['or-IN', 'Oriya', 'India'],\n    ['os', 'Ossetian'],\n    ['os-GE', 'Ossetian', 'Georgia'],\n    ['os-RU', 'Ossetian', 'Russia'],\n    ['pa', 'Panjabi'],\n    ['pa-IN', 'Panjabi', 'India'],\n    ['pa-PK', 'Panjabi', 'Pakistan'],\n    ['pl', 'Polish'],\n    ['pl-PL', 'Polish', 'Poland'],\n    ['ps', 'Pushto'],\n    ['ps-AF', 'Pushto', 'Afghanistan'],\n    ['pt', 'Portuguese'],\n    ['pt-AO', 'Portuguese', 'Angola'],\n    ['pt-BR', 'Portuguese', 'Brazil'],\n    ['pt-CH', 'Portuguese', 'Switzerland'],\n    ['pt-CV', 'Portuguese', 'Cape Verde'],\n    ['pt-GQ', 'Portuguese', 'Equatorial Guinea'],\n    ['pt-GW', 'Portuguese', 'Guinea-Bissau'],\n    ['pt-LU', 'Portuguese', 'Luxembourg'],\n    ['pt-MO', 'Portuguese', 'Macau'],\n    ['pt-MZ', 'Portuguese', 'Mozambique'],\n    ['pt-PT', 'Portuguese', 'Portugal'],\n    ['pt-ST', 'Portuguese', 'Sao Tome and Principe'],\n    ['pt-TL', 'Portuguese', 'Timor-Leste (East Timor)'],\n    ['qu', 'Quechua'],\n    ['qu-BO', 'Quechua', 'Bolivia'],\n    ['qu-EC', 'Quechua', 'Ecuador'],\n    ['qu-PE', 'Quechua', 'Peru'],\n    ['rm', 'Romansh'],\n    ['rm-CH', 'Romansh', 'Switzerland'],\n    ['rn', 'Rundi'],\n    ['rn-BI', 'Rundi', 'Burundi'],\n    ['ro', 'Romanian'],\n    ['ro-MD', 'Romanian', 'Moldova'],\n    ['ro-RO', 'Romanian', 'Romania'],\n    ['ru', 'Russian'],\n    ['ru-BY', 'Russian', 'Belarus'],\n    ['ru-KG', 'Russian', 'Kyrgyzstan'],\n    ['ru-KZ', 'Russian', 'Kazakhstan'],\n    ['ru-MD', 'Russian', 'Moldova'],\n    ['ru-RU', 'Russian', 'Russia'],\n    ['ru-UA', 'Russian', 'Ukraine'],\n    ['rw', 'Kinyarwanda'],\n    ['rw-RW', 'Kinyarwanda', 'Rwanda'],\n    ['se', 'Northern Sami'],\n    ['se-FI', 'Northern Sami', 'Finland'],\n    ['se-NO', 'Northern Sami', 'Norway'],\n    ['se-SE', 'Northern Sami', 'Sweden'],\n    ['sg', 'Sango'],\n    ['sg-CF', 'Sango', 'Central African Republic'],\n    ['si', 'Sinhala'],\n    ['si-LK', 'Sinhala', 'Sri Lanka'],\n    ['sk', 'Slovak'],\n    ['sk-SK', 'Slovak', 'Slovakia'],\n    ['sl', 'Slovenian'],\n    ['sl-SI', 'Slovenian', 'Slovenia'],\n    ['sn', 'Shona'],\n    ['sn-ZW', 'Shona', 'Zimbabwe'],\n    ['so', 'Somali'],\n    ['so-DJ', 'Somali', 'Djibouti'],\n    ['so-ET', 'Somali', 'Ethiopia'],\n    ['so-KE', 'Somali', 'Kenya'],\n    ['so-SO', 'Somali', 'Somalia'],\n    ['sq', 'Albanian'],\n    ['sq-AL', 'Albanian', 'Albania'],\n    ['sq-MK', 'Albanian', 'Macedonia'],\n    ['sq-XK', 'Albanian'],\n    ['sr', 'Serbian'],\n    ['sr-BA', 'Serbian', 'Bosnia and Herzegovina'],\n    ['sr-ME', 'Serbian', 'Montenegro'],\n    ['sr-RS', 'Serbian', 'Serbia'],\n    ['sr-XK', 'Serbian'],\n    ['sv', 'Swedish'],\n    ['sv-AX', 'Swedish', 'Aland'],\n    ['sv-FI', 'Swedish', 'Finland'],\n    ['sv-SE', 'Swedish', 'Sweden'],\n    ['sw', 'Swahili'],\n    ['sw-CD', 'Swahili', 'Congo'],\n    ['sw-KE', 'Swahili', 'Kenya'],\n    ['sw-TZ', 'Swahili', 'Tanzania'],\n    ['sw-UG', 'Swahili', 'Uganda'],\n    ['ta', 'Tamil'],\n    ['ta-IN', 'Tamil', 'India'],\n    ['ta-LK', 'Tamil', 'Sri Lanka'],\n    ['ta-MY', 'Tamil', 'Malaysia'],\n    ['ta-SG', 'Tamil', 'Singapore'],\n    ['te', 'Telugu'],\n    ['te-IN', 'Telugu', 'India'],\n    ['th', 'Thai'],\n    ['th-TH', 'Thai', 'Thailand'],\n    ['ti', 'Tigrinya'],\n    ['ti-ER', 'Tigrinya', 'Eritrea'],\n    ['ti-ET', 'Tigrinya', 'Ethiopia'],\n    ['tk', 'Turkmen'],\n    ['tk-TM', 'Turkmen', 'Turkmenistan'],\n    ['to', 'Tonga (Tonga Islands)'],\n    ['to-TO', 'Tonga (Tonga Islands)', 'Tonga'],\n    ['tr', 'Turkish'],\n    ['tr-CY', 'Turkish', 'Cyprus'],\n    ['tr-TR', 'Turkish', 'Turkey'],\n    ['ug', 'Uighur'],\n    ['ug-CN', 'Uighur', 'China'],\n    ['uk', 'Ukrainian'],\n    ['uk-UA', 'Ukrainian', 'Ukraine'],\n    ['ur', 'Urdu'],\n    ['ur-IN', 'Urdu', 'India'],\n    ['ur-PK', 'Urdu', 'Pakistan'],\n    ['uz', 'Uzbek'],\n    ['uz-AF', 'Uzbek', 'Afghanistan'],\n    ['uz-UZ', 'Uzbek', 'Uzbekistan'],\n    ['vi', 'Vietnamese'],\n    ['vi-VN', 'Vietnamese', 'Vietnam'],\n    ['vo', 'Volapük'],\n    ['yi', 'Yiddish'],\n    ['yi-1', 'Yiddish'],\n    ['yo', 'Yoruba'],\n    ['yo-BJ', 'Yoruba', 'Benin'],\n    ['yo-NG', 'Yoruba', 'Nigeria'],\n    ['zh', 'Chinese'],\n    ['zh-CN', 'Chinese', 'China'],\n    ['zh-HK', 'Chinese', 'Hong Kong'],\n    ['zh-MO', 'Chinese', 'Macau'],\n    ['zh-SG', 'Chinese', 'Singapore'],\n    ['zh-TW', 'Chinese', 'China'],\n    ['zu', 'Zulu'],\n    ['zu-ZA', 'Zulu', 'South Africa'],\n];\n\n"
  },
  {
    "path": "src/server/index.ts",
    "content": "export * from './server';\nexport * from './serverSettings';\n"
  },
  {
    "path": "src/server/server.ts",
    "content": "\nexport * from '../../server';\n"
  },
  {
    "path": "src/server/serverSettings.ts",
    "content": "\nimport * as server from './server';\nimport { normalizeCode } from '../iso639-1';\nimport * as util from '../util';\n\nexport function extractLanguage(config?: server.CSpellUserSettings): string[] | undefined {\n    return (\n        config &&\n        config.language &&\n        normalizeToLocals(config.language)\n    ) || undefined;\n}\n\nexport function extractLocals(config: server.CSpellUserSettings = {}): string[] {\n    return extractLocalsFromLanguageSettings(config.languageSettings);\n}\n\nexport function extractLocalsFromLanguageSettings(langSettings: server.LanguageSetting[] = []): string[] {\n    const locals = langSettings\n        .map(s => s.local || '')\n        .map(normalizeLocal)\n        .join(',');\n    return normalizeToLocals(locals);\n}\n\nexport function extractDictionariesByLocal(config: server.CSpellUserSettings = {}): Map<string, string[]> {\n    return extractDictionariesByLocalLanguageSettings(config.languageSettings);\n}\n\nexport function extractDictionariesByLocalLanguageSettings(langSettings: server.LanguageSetting[] = []): Map<string, string[]> {\n    const mapOfDict = new Map<string, string[]>();\n    langSettings\n        .map(({local, dictionaries = []}) => ({ local: normalizeLocal(local), dictionaries }))\n        .filter(s => !!s.local)\n        .filter(s => s.dictionaries.length > 0)\n        .forEach(s => {\n            s.local.split(',')\n                .forEach(local => {\n                    mapOfDict.set(\n                        local,\n                        (mapOfDict.get(local) || []).concat(s.dictionaries).filter(util.uniqueFilter())\n                    );\n                });\n        });\n    return mapOfDict;\n}\n\nexport function normalizeLocal(local: string | string[] = ''): string {\n    if(Array.isArray(local)) {\n        local = local.join(',');\n    }\n    return normalizeToLocals(local).join(',');\n}\n\nexport function normalizeToLocals(local: string = '') {\n    return local\n        .replace(/[|]/g, ',')\n        .replace(/[*]/g, '')\n        .split(',')\n        .map(normalizeCode)\n        .map(s => s.trim())\n        .filter(a => !!a)\n        .filter(util.uniqueFilter());\n}\n"
  },
  {
    "path": "src/settings/CSpellSettings.ts",
    "content": "import * as fs from 'fs-extra';\nimport * as json from 'comment-json';\nimport path = require('path');\nimport {CSpellUserSettingsWithComments} from '../server';\nimport { unique, uniqueFilter } from '../util';\n\nconst currentSettingsFileVersion = '0.1';\n\nexport const sectionCSpell = 'cSpell';\n\nexport const defaultFileName = 'cSpell.json';\n\nexport interface CSpellSettings extends CSpellUserSettingsWithComments {\n}\n\n// cSpell:ignore hte\nconst defaultSettings: CSpellUserSettingsWithComments = {\n    version: currentSettingsFileVersion,\n};\n\n// cSpell:ignore hte\nconst defaultSettingsWithComments: CSpellSettings = {\n    ...defaultSettings,\n};\n\nexport function getDefaultSettings(): CSpellSettings {\n    return Object.freeze(defaultSettings);\n}\n\nexport function readSettings(filename: string): Promise<CSpellSettings> {\n    return fs.readFile(filename)\n        .then(\n            buffer => buffer.toString(),\n            () => json.stringify(defaultSettingsWithComments, null, 4)\n        )\n        .then(cfgJson => (json.parse(cfgJson) as CSpellSettings))\n        // covert parse errors into the defaultSettings\n        .then(a => a, error => defaultSettingsWithComments)\n        .then(settings => ({...defaultSettings, ...settings}));\n}\n\nexport function updateSettings(filename: string, settings: CSpellSettings) {\n    return fs.mkdirp(path.dirname(filename))\n        .then(() => fs.writeFile(filename, json.stringify(settings, null, 4)))\n        .then(() => settings);\n}\n\nexport function addWordToSettingsAndUpdate(filename: string, word: string) {\n    return readApplyUpdateSettingsFile(\n        filename,\n        settings => addWordsToSettings(settings, word.split(' '))\n    );\n}\n\nexport function addWordsToSettings(settings: CSpellSettings, wordsToAdd: string[]) {\n    const words = mergeWords(settings.words, wordsToAdd);\n    return {...settings, words};\n}\n\nexport function addIgnoreWordToSettingsAndUpdate(filename: string, word: string) {\n    return readApplyUpdateSettingsFile(\n        filename,\n        settings => addIgnoreWordsToSettings(settings, word.split(' '))\n    );\n}\n\nexport function addIgnoreWordsToSettings(settings: CSpellSettings, wordsToAdd: string[]) {\n    const ignoreWords = mergeWords(settings.ignoreWords, wordsToAdd);\n    return {...settings, ignoreWords};\n}\n\nfunction mergeWords(wordsLeft: string[] | undefined, wordsRight: string[]): string[] {\n    return (wordsLeft || [])\n        .concat(wordsRight)\n        .map(a => a.trim())\n        .filter(a => !!a)\n        .filter(uniqueFilter())\n        .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n}\n\nexport function removeWordsFromSettings(settings: CSpellSettings, wordsToRemove: string[]) {\n    const words = filterOutWords(settings.words || [], wordsToRemove);\n    return {...settings, words};\n}\n\nexport function filterOutWords(words: string[], wordsToRemove: string[]): string[] {\n    const toRemove = new Set(wordsToRemove.map(w => w.toLowerCase()));\n    return words.filter(w => !toRemove.has(w.toLowerCase()));\n}\n\nexport function removeWordFromSettingsAndUpdate(filename: string, word: string) {\n    return readApplyUpdateSettingsFile(\n        filename,\n        settings => removeWordsFromSettings(settings, word.split(' '))\n    );\n}\n\nexport function addLanguageIdsToSettings(settings: CSpellSettings, languageIds: string[], onlyIfExits: boolean) {\n    if (settings.enabledLanguageIds || !onlyIfExits) {\n        const enabledLanguageIds = unique((settings.enabledLanguageIds || []).concat(languageIds));\n        return { ...settings, enabledLanguageIds };\n    }\n    return settings;\n}\n\nexport function removeLanguageIdsFromSettings(settings: CSpellSettings, languageIds: string[]) {\n    if (settings.enabledLanguageIds) {\n        const excludeLangIds = new Set(languageIds);\n        const enabledLanguageIds = settings.enabledLanguageIds.filter(a => !excludeLangIds.has(a));\n        const newSettings = {...settings, enabledLanguageIds};\n        if (!newSettings.enabledLanguageIds.length) {\n            delete newSettings.enabledLanguageIds;\n        }\n        return newSettings;\n    }\n    return settings;\n}\n\nexport function writeAddLanguageIdsToSettings(filename: string, languageIds: string[], onlyIfExits: boolean) {\n    return readApplyUpdateSettingsFile(\n        filename,\n        settings => addLanguageIdsToSettings(settings, languageIds, onlyIfExits)\n    );\n}\n\nexport function removeLanguageIdsFromSettingsAndUpdate(filename: string, languageIds: string[]) {\n    return readApplyUpdateSettingsFile(\n        filename,\n        settings => removeLanguageIdsFromSettings(settings, languageIds)\n    );\n}\n\nexport async function readApplyUpdateSettingsFile(filename: string, action: (settings: CSpellSettings) => CSpellSettings) {\n    const settings = await readSettings(filename);\n    const newSettings = action(settings);\n    return updateSettings(filename, newSettings);\n}\n"
  },
  {
    "path": "src/settings/config.ts",
    "content": "import { workspace, Uri, ConfigurationTarget as Target } from 'coc.nvim';\nimport { TextDocument } from 'vscode-languageserver-protocol';\nimport { CSpellUserSettings } from '../server';\n\nexport { CSpellUserSettings } from '../server';\nexport { ConfigurationTarget, ConfigurationTarget as Target } from 'coc.nvim';\n\nexport const sectionCSpell = 'cSpell';\n\nexport interface InspectValues<T> {\n    defaultValue?: T | undefined;\n    globalValue?: T | undefined;\n    workspaceValue?: T | undefined;\n    workspaceFolderValue?: T | undefined;\n}\n\nexport const GlobalTarget = Target.Global;\nexport const WorkspaceTarget = Target.Workspace;\n\nexport interface ConfigTargetWithOptionalResource {\n    target: Target;\n    uri?: Uri;\n}\n\nexport interface ConfigTargetWithResource extends ConfigTargetWithOptionalResource {\n    uri: Uri;\n}\n\nexport type ConfigTargetResourceFree = Target.Global | Target.Workspace;\nexport type ConfigTarget = ConfigTargetResourceFree | ConfigTargetWithResource | ConfigTargetWithOptionalResource;\n\nexport interface Inspect<T> extends InspectValues<T> {\n    key: string;\n}\n\nexport type Scope = keyof InspectValues<CSpellUserSettings>;\nexport type ScopeResourceFree = 'defaultValue' | 'globalValue' | 'workspaceValue';\n\nexport interface ScopeValues {\n    Default: 'defaultValue';\n    Global: 'globalValue';\n    Workspace: 'workspaceValue';\n    Folder: 'workspaceFolderValue';\n}\n\nexport const Scopes: ScopeValues = {\n    Default: 'defaultValue',\n    Global: 'globalValue',\n    Workspace: 'workspaceValue',\n    Folder: 'workspaceFolderValue',\n};\n\nexport interface FullInspectScope {\n    scope: Scope;\n    resource: Uri | null;\n}\n\nexport type InspectScope = FullInspectScope | ScopeResourceFree;\n\n/**\n * ScopeOrder from general to specific.\n */\nconst scopeOrder: Scope[] = [\n    'defaultValue',\n    'globalValue',\n    'workspaceValue',\n    'workspaceFolderValue',\n];\n\nconst scopeToOrderIndex = new Map<string, number>(\n    scopeOrder.map((s, i) => [s, i] as [string, number])\n);\n\nexport type InspectResult<T> = Inspect<T> | undefined;\n\nexport function getSectionName(\n    subSection?: keyof CSpellUserSettings\n): string {\n    return [sectionCSpell, subSection].filter(a => !!a).join('.');\n}\n\nexport function getSettingsFromVSConfig(\n    resource: Uri | null\n): CSpellUserSettings {\n    const config = getConfiguration(resource);\n    return config.get<CSpellUserSettings>(sectionCSpell, {});\n}\n\nexport function getSettingFromVSConfig<K extends keyof CSpellUserSettings>(\n    subSection: K,\n    resource: Uri | null\n): CSpellUserSettings[K] | undefined {\n    const config = getConfiguration(resource);\n    const settings = config.get<CSpellUserSettings>(sectionCSpell, {});\n    return settings[subSection];\n}\n\n/**\n * Inspect a scoped setting. It will not merge values.\n * @param subSection the cspell section\n * @param scope the scope of the value. A resource is needed to get folder level settings.\n */\nexport function inspectScopedSettingFromVSConfig<K extends keyof CSpellUserSettings>(\n    subSection: K,\n    scope: InspectScope,\n): CSpellUserSettings[K] | undefined {\n    scope = normalizeScope(scope);\n    const ins = inspectSettingFromVSConfig(subSection, scope.resource);\n    return ins && ins[scope.scope];\n}\n\n/**\n * Inspect a scoped setting. It will not merge values.\n * @param subSection the cspell section\n * @param scope the scope of the value. A resource is needed to get folder level settings.\n */\nexport function getScopedSettingFromVSConfig<K extends keyof CSpellUserSettings>(\n    subSection: K,\n    scope: InspectScope,\n): CSpellUserSettings[K] | undefined {\n    return findScopedSettingFromVSConfig(subSection, scope).value;\n}\n\n/**\n * Inspect a scoped setting. It will not merge values.\n * @param subSection the cspell section\n * @param scope the scope of the value. A resource is needed to get folder level settings.\n */\nexport function findScopedSettingFromVSConfig<K extends keyof CSpellUserSettings>(\n    subSection: K,\n    scope: InspectScope,\n): FindBestConfigResult<K> {\n    scope = normalizeScope(scope);\n    const ins = inspectSettingFromVSConfig(subSection, scope.resource);\n    return findBestConfig(ins, scope.scope);\n}\n\nexport function inspectSettingFromVSConfig<K extends keyof CSpellUserSettings>(\n    subSection: K,\n    resource: Uri | null,\n): Inspect<CSpellUserSettings[K]> {\n    const config = inspectConfig(resource);\n    const { defaultValue = {}, globalValue = {}, workspaceValue, workspaceFolderValue  } = config;\n    return {\n        key: config.key + '.' + subSection,\n        defaultValue: defaultValue[subSection],\n        globalValue: globalValue[subSection],\n        workspaceValue: workspaceValue\n          ? workspaceValue[subSection]\n          : workspaceFolderValue\n          ? workspaceFolderValue[subSection]\n          : undefined,\n        workspaceFolderValue: workspaceFolderValue\n          ? workspaceFolderValue[subSection]\n          : workspaceValue\n          ? workspaceValue[subSection]\n          : undefined,\n    };\n}\n\nexport function setSettingInVSConfig<K extends keyof CSpellUserSettings>(\n    subSection: K,\n    value: CSpellUserSettings[K],\n    configTarget: ConfigTarget,\n): void {\n    const target = extractTarget(configTarget);\n    const uri = extractTargetUri(configTarget);\n    const section = getSectionName(subSection);\n    const config = getConfiguration(uri);\n    return config.update(section, value, target === Target.Global);\n}\n\nexport function inspectConfig(\n    resource: Uri | null\n): Inspect<CSpellUserSettings> {\n  const config = getConfiguration(resource);\n  const settings = config.inspect<CSpellUserSettings>(sectionCSpell) || { key: sectionCSpell };\n  return settings;\n}\n\nfunction toAny(value: any): any {\n    return value;\n}\n\nexport function isGlobalLevelTarget(target: ConfigTarget) {\n    return isConfigTargetWithOptionalResource(target) && target.target === Target.Global || target === Target.Global;\n}\n\nexport function isFolderLevelTarget(target: ConfigTarget) {\n    return isConfigTargetWithResource(target) && target.target === Target.Workspace;\n}\n\nexport function isConfigTargetWithResource(target: ConfigTarget): target is ConfigTargetWithResource {\n    return isConfigTargetWithOptionalResource(target) && target.uri !== undefined;\n}\n\nexport function isConfigTargetWithOptionalResource(target: ConfigTarget): target is ConfigTargetWithOptionalResource {\n    return typeof target === 'object' && target.target !== undefined;\n}\n\ntype TargetToScope = {\n    [Target.Global]: 'globalValue';\n    [Target.User]: 'globalValue';\n    [Target.Workspace]: 'workspaceValue';\n};\n\nconst targetToScope: TargetToScope = {\n    0: 'globalValue',\n    1: 'globalValue',\n    2: 'workspaceValue',\n};\n\nexport function configTargetToScope(target: ConfigTarget): InspectScope {\n    if (isConfigTargetWithOptionalResource(target)) {\n        return {\n            scope: toScope(target.target),\n            resource: target.uri || null,\n        };\n    }\n    return targetToScope[target];\n}\n\nexport function toScope(target: Target): Scope {\n    return targetToScope[target];\n}\n\nexport function extractScope(inspectScope: InspectScope): Scope {\n    if (isFullInspectScope(inspectScope)) {\n        return inspectScope.scope;\n    }\n    return inspectScope;\n}\n\nfunction isFullInspectScope(scope: InspectScope): scope is FullInspectScope {\n    return typeof scope === 'object';\n}\n\nfunction normalizeScope(scope: InspectScope): FullInspectScope {\n    if (isFullInspectScope(scope)) {\n        return {\n            scope: scope.scope,\n            resource: scope.scope === Scopes.Folder || scope.scope === Scopes.Workspace ? normalizeResourceUri(scope.resource) : null,\n        };\n    }\n    return { scope, resource: null };\n}\n\nfunction normalizeResourceUri(uri: Uri | null | undefined): Uri | null {\n    if (uri) {\n        const folder = workspace.getWorkspaceFolder(uri.toString());\n        return folder && Uri.parse(folder.uri) || null;\n    }\n    return null;\n}\n\nexport interface FindBestConfigResult<K extends keyof CSpellUserSettings> {\n    scope: Scope;\n    value: CSpellUserSettings[K];\n}\n\nfunction findBestConfig<K extends keyof CSpellUserSettings>(\n    config: Inspect<CSpellUserSettings[K]>,\n    scope: Scope,\n): FindBestConfigResult<K> {\n    for (let p = scopeToOrderIndex.get(scope)!; p >= 0; p -= 1) {\n        const k = scopeOrder[p];\n        const v = config[k];\n        if (v !== undefined) {\n            return { scope: k, value: v };\n        }\n    }\n    return { scope: 'defaultValue', value: undefined };\n}\n\nexport function isGlobalTarget(target: ConfigTarget): boolean {\n    return extractTarget(target) === Target.Global;\n}\n\nexport function createTargetForUri(target: Target, uri: Uri): ConfigTargetWithResource {\n    return {\n        target, uri\n    };\n}\n\nexport function createTargetForDocument(target: Target, doc: TextDocument): ConfigTargetWithResource {\n    return createTargetForUri(target, Uri.parse(doc.uri));\n}\n\nexport function extractTarget(target: ConfigTarget): Target {\n    return isConfigTargetWithOptionalResource(target)\n        ? target.target\n        : target;\n}\n\nexport function extractTargetUri(target: ConfigTarget): Uri | null {\n    return isConfigTargetWithResource(target)\n        ? target.uri\n        : null;\n}\n\nexport function getConfiguration(uri?: Uri | null) {\n   return fetchConfiguration(uri);\n}\n\nfunction fetchConfiguration(uri?: Uri | null) {\n    return workspace.getConfiguration(undefined, toAny(uri));\n}\n"
  },
  {
    "path": "src/settings/index.ts",
    "content": "export * from './settings';\nexport * from './config';\nexport {CSpellSettings} from './CSpellSettings';\n"
  },
  {
    "path": "src/settings/languageIds.ts",
    "content": "export const languageIds: string[] = [\n    'asciidoc',\n    'bat',\n    'c',\n    'clojure',\n    'coffeescript',\n    'cpp',\n    'csharp',\n    'css',\n    'diff',\n    'dockerfile',\n    'fsharp',\n    'git-commit',\n    'git-rebase',\n    'go',\n    'groovy',\n    'handlebars',\n    'html',\n    'ini',\n    'jade',\n    'java',\n    'javascript',\n    'javascriptreact',\n    'json',\n    'less',\n    'lua',\n    'makefile',\n    'markdown',\n    'objective-c',\n    'perl',\n    'perl6',\n    'php',\n    'plaintext',\n    'powershell',\n    'properties',\n    'pug',\n    'python',\n    'r',\n    'razor',\n    'ruby',\n    'rust',\n    'scss',\n    'shaderlab',\n    'shellscript',\n    'sql',\n    'swift',\n    'typescript',\n    'typescriptreact',\n    'vb',\n    'xml',\n    'xsl',\n    'yaml',\n];"
  },
  {
    "path": "src/settings/settings.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { Uri, Disposable, workspace, ConfigurationTarget } from 'coc.nvim';\n\nimport { CSpellUserSettings, normalizeLocal } from '../server';\nimport * as CSpellSettings from './CSpellSettings';\nimport { unique } from '../util';\nimport * as watcher from '../util/watcher';\nimport * as config from './config';\nimport { InspectScope } from './config';\n\nexport { ConfigTarget, InspectScope, Scope } from './config';\n\nexport const baseConfigName        = CSpellSettings.defaultFileName;\nexport const configFileLocations = [\n  baseConfigName,\n  baseConfigName.toLowerCase(),\n  `.${baseConfigName.toLowerCase()}`,\n  `.vim/${baseConfigName}`,\n  `.vim/${baseConfigName.toLowerCase()}`,\n  `.vscode/${baseConfigName}`,\n  `.vscode/${baseConfigName.toLowerCase()}`,\n];\n\nexport interface SettingsInfo {\n  path: string;\n  settings: CSpellUserSettings;\n}\n\nexport function watchSettingsFiles(callback: () => void): Disposable {\n  // Every 10 seconds see if we have new files to watch.\n  let busy = false;\n  const intervalObj = setInterval(async () => {\n    if (busy) {\n      return;\n    }\n    busy = true;\n    const settingsFiles = await findSettingsFiles();\n    settingsFiles\n      .map(uri => uri.fsPath)\n      .filter(file => !watcher.isWatching(file))\n      .forEach(file => watcher.add(file, callback));\n    busy = false;\n  }, 10000);\n\n  return {\n    dispose: () => {\n      watcher.dispose();\n      clearInterval(intervalObj);\n    }\n  };\n}\n\nexport function getDefaultWorkspaceConfigLocation() {\n  const { workspaceFolders } = workspace;\n  const root = workspaceFolders\n    && workspaceFolders[0]\n    && Uri.parse(workspaceFolders[0].uri).fsPath;\n  return root\n    ? path.join(root, baseConfigName)\n    : undefined;\n}\n\nexport function hasWorkspaceLocation() {\n  const { workspaceFolders } = workspace;\n  return !!(workspaceFolders && workspaceFolders[0]);\n}\n\nexport function findSettingsFiles(uri?: Uri): Promise<Uri[]> {\n  const { workspaceFolders } = workspace;\n  if (!workspaceFolders || !hasWorkspaceLocation()) {\n    return Promise.resolve([]);\n  }\n\n  const folders = uri\n  ? [workspace.getWorkspaceFolder(uri.toString())!].filter(a => !!a)\n  : workspaceFolders;\n\n  const possibleLocations = folders\n  .map(folder => Uri.parse(folder.uri).fsPath)\n  .map(root => configFileLocations.map(rel => path.join(root, rel)))\n  .reduce((a, b) => a.concat(b));\n\n  const found = possibleLocations\n  .map(filename => fs.pathExists(filename)\n    .then(exists => ({ filename, exists })));\n\n  return Promise.all(found).then(found => found\n    .filter(found => found.exists)\n    .map(found => found.filename)\n    .map(filename => Uri.file(filename))\n  );\n}\n\nexport function findExistingSettingsFileLocation(uri?: Uri): Promise<string | undefined> {\n  return findSettingsFiles(uri)\n  .then(uris => uris.map(uri => uri.fsPath))\n  .then(paths => paths[0]);\n}\n\nexport function findSettingsFileLocation(): Promise<string | undefined> {\n  return findExistingSettingsFileLocation()\n  .then(path => path || getDefaultWorkspaceConfigLocation());\n}\n\nexport function loadTheSettingsFile(): Promise<SettingsInfo | undefined> {\n  return findSettingsFileLocation()\n  .then(loadSettingsFile);\n}\n\nexport function loadSettingsFile(path: string): Promise<SettingsInfo | undefined> {\n  return path\n  ? CSpellSettings.readSettings(path).then(settings => (path ? { path, settings } : undefined))\n  : Promise.resolve(undefined);\n}\n\nexport function setEnableSpellChecking(target: config.ConfigTarget, enabled: boolean): void {\n  return config.setSettingInVSConfig('enabled', enabled, target);\n}\n\nexport function getEnabledLanguagesFromConfig(scope: InspectScope) {\n  return config.getScopedSettingFromVSConfig('enabledLanguageIds', scope) || [];\n}\n\n/**\n * @description Enable a programming language\n * @param target - which level of setting to set\n * @param languageId - the language id, e.g. 'typescript'\n */\nexport async function enableLanguage(target: config.ConfigTarget, languageId: string): Promise<void> {\n  await enableLanguageIdForTarget(languageId, true, target, true);\n}\n\nexport async function disableLanguage(target: config.ConfigTarget, languageId: string): Promise<void> {\n  await enableLanguageIdForTarget(languageId, false, target, true);\n}\n\nexport function addWordToSettings(target: config.ConfigTarget, word: string) {\n  const useGlobal = config.isGlobalTarget(target) || !hasWorkspaceLocation();\n  const addWords = word.split(' ');\n  const section: 'userWords' | 'words' = useGlobal ? 'userWords' : 'words';\n  return updateSettingInConfig(\n    section,\n    target,\n    words => unique(addWords.concat(words || []).sort()),\n    true\n  );\n}\n\nexport function addIgnoreWordToSettings(target: config.ConfigTarget, word: string) {\n  const addWords = word.split(' ');\n  return updateSettingInConfig(\n    'ignoreWords',\n    target,\n    words => unique(addWords.concat(words || []).sort()),\n    true\n  );\n}\n\nexport async function removeWordFromSettings(target: config.ConfigTarget, word: string) {\n  const useGlobal = config.isGlobalTarget(target);\n  const section: 'userWords' | 'words' = useGlobal ? 'userWords' : 'words';\n  const toRemove = word.split(' ');\n  return updateSettingInConfig(\n    section,\n    target,\n    words => CSpellSettings.filterOutWords(words || [], toRemove),\n    true\n  );\n}\n\n\n\nexport function toggleEnableSpellChecker(target: config.ConfigTarget): void {\n  const resource = config.isConfigTargetWithResource(target) ? target.uri : null;\n  const curr = config.getSettingFromVSConfig('enabled', resource);\n  return config.setSettingInVSConfig('enabled', !curr, target);\n}\n\n/**\n * Enables the current programming language of the active file in the editor.\n */\nexport async function enableCurrentLanguage(): Promise<void> {\n  const doc = await workspace.document;\n  if (doc && doc.textDocument && doc.textDocument.languageId) {\n    const target = config.createTargetForDocument(ConfigurationTarget.Workspace, doc.textDocument);\n    return enableLanguage(target, doc.textDocument.languageId);\n  }\n  return Promise.resolve();\n}\n\n/**\n * Disables the current programming language of the active file in the editor.\n */\nexport async function disableCurrentLanguage(): Promise<void> {\n  const doc = await workspace.document;\n  if (doc && doc.textDocument && doc.textDocument.languageId) {\n    const target = config.createTargetForDocument(ConfigurationTarget.Workspace, doc.textDocument);\n    return disableLanguage(target, doc.textDocument.languageId);\n  }\n  return Promise.resolve();\n}\n\n\nexport async function enableLocal(target: config.ConfigTarget, local: string) {\n  await enableLocalForTarget(local, true, target, true);\n}\n\nexport async function disableLocal(target: config.ConfigTarget, local: string) {\n  await enableLocalForTarget(local, false, target, true);\n}\n\nexport function enableLocalForTarget(\n  local: string,\n  enable: boolean,\n  target: config.ConfigTarget,\n  isCreateAllowed: boolean\n): Promise<boolean> {\n  const applyFn: (src: string | undefined) => string | undefined = enable\n  ? (currentLanguage) => unique(normalizeLocal(currentLanguage).split(',').concat(local.split(','))).join(',')\n  : (currentLanguage) => {\n    const value = unique(normalizeLocal(currentLanguage).split(',')).filter(lang => lang !== local).join(',');\n    return value || undefined;\n  };\n  return updateSettingInConfig(\n    'language',\n    target,\n    applyFn,\n    isCreateAllowed,\n    shouldUpdateCSpell(target)\n  );\n}\n\nexport function enableLanguageIdForTarget(\n  languageId: string,\n  enable: boolean,\n  target: config.ConfigTarget,\n  isCreateAllowed: boolean\n): Promise<boolean> {\n  const fn: (src: string[] | undefined) => string[] | undefined = enable\n  ? (src) => unique([languageId].concat(src || [])).sort()\n  : (src) => {\n    const v = src && unique(src.filter(v => v !== languageId)).sort();\n    return v && v.length > 0 && v || undefined;\n  };\n  return updateSettingInConfig(\n    'enabledLanguageIds',\n    target,\n    fn,\n    isCreateAllowed,\n    shouldUpdateCSpell(target)\n  );\n}\n\n/**\n * Try to enable / disable a programming language id starting at folder level going to global level, stopping when successful.\n * @param languageId\n * @param enable\n * @param uri\n */\nexport async function enableLanguageIdForClosestTarget(\n  languageId: string,\n  enable: boolean,\n  uri: Uri | undefined\n): Promise<void> {\n  if (languageId) {\n    if (uri) {\n      // Apply it to the workspace folder if it exists.\n      const target: config.ConfigTargetWithResource = {\n        target: ConfigurationTarget.Workspace,\n        uri,\n      };\n      if (await enableLanguageIdForTarget(languageId, enable, target, false)) return;\n    }\n\n    if (workspace.workspaceFolders\n      && workspace.workspaceFolders.length\n      && await enableLanguageIdForTarget(languageId, enable, config.Target.Workspace, false)\n    ) {\n      return;\n    }\n\n    // Apply it to User settings.\n    await enableLanguageIdForTarget(languageId, enable, config.Target.Global, true);\n  }\n  return;\n}\n\n/**\n * Determine if we should update the cspell file if it exists.\n * 1. Update is allowed for WorkspaceFolders\n * 1. Update is allowed for Workspace if there is only 1 folder.\n * 1. Update is not allowed for the Global target.\n * @param target\n */\nfunction shouldUpdateCSpell(target: config.ConfigTarget) {\n  const cfgTarget = config.extractTarget(target);\n  return cfgTarget !== config.Target.Global\n    && workspace.workspaceFolders\n    && (cfgTarget === config.Target.Workspace || workspace.workspaceFolders.length === 1);\n\n}\n\n/**\n * Update Config Settings.\n * Writes to both the VS Config and the `cspell.json` if it exists.\n * If a `cspell.json` exists, it will be preferred over the VS Code config setting.\n * @param section the configuration value to set/update.\n * @param target the configuration level (Global, Workspace, WorkspaceFolder)\n * @param applyFn the function to calculate the new value.\n * @param create if the setting does not exist, then create it.\n * @param updateCSpell update the cspell.json file if it exists.\n */\nexport async function updateSettingInConfig<K extends keyof CSpellUserSettings>(\n  section: K,\n  target: config.ConfigTarget,\n  applyFn: (origValue: CSpellUserSettings[K]) => CSpellUserSettings[K],\n  create: boolean,\n  updateCSpell: boolean = true\n): Promise<boolean> {\n  interface Result {\n    value: CSpellUserSettings[K] | undefined;\n  }\n\n  const scope = config.configTargetToScope(target);\n  const orig = config.findScopedSettingFromVSConfig(section, scope);\n  const uri = config.isConfigTargetWithOptionalResource(target) && target.uri || undefined;\n  const settingsFilename = updateCSpell && !config.isGlobalLevelTarget(target) && await findExistingSettingsFileLocation(uri) || undefined;\n\n  async function updateConfig(): Promise<false | Result> {\n    if (create || orig.value !== undefined && orig.scope === config.extractScope(scope)) {\n      const newValue = applyFn(orig.value);\n      await config.setSettingInVSConfig(section, newValue, target);\n      return { value: newValue };\n    }\n    return false;\n  }\n\n  async function updateCSpellFile(settingsFilename: string | undefined, defaultValue: CSpellUserSettings[K] | undefined): Promise<boolean> {\n    if (settingsFilename) {\n      await CSpellSettings.readApplyUpdateSettingsFile(settingsFilename, settings => {\n        const v = settings[section];\n        const newValue = v !== undefined ? applyFn(v) : applyFn(defaultValue);\n        const newSettings = {...settings };\n        if (newValue === undefined) {\n          delete newSettings[section];\n        } else {\n          newSettings[section] = newValue;\n        }\n        return newSettings;\n      });\n      return true;\n    }\n    return false;\n  }\n\n  const configResult = await updateConfig();\n  const cspellResult = await updateCSpellFile(settingsFilename, orig.value);\n\n  return [\n    !!configResult,\n    cspellResult\n  ].reduce((a, b) => a || b, false);\n}\n"
  },
  {
    "path": "src/statusbar.ts",
    "content": "import * as coc from 'coc.nvim';\nimport {TextDocument} from 'vscode-languageserver-protocol';\n\nimport {CSpellUserSettings} from './server';\nimport { CSpellClient } from './client';\nimport { isSupportedDoc } from './util';\n\nexport function initStatusBar(context: coc.ExtensionContext, client: CSpellClient) {\n  const statusText = coc.workspace.getConfiguration('cSpell').get('status-bar-text', 'cSpell');\n\n  const sbCheck = coc.workspace.createStatusBarItem(999, { progress: true });\n  sbCheck.text = statusText;\n  sbCheck.show();\n\n  function updateStatusBarWithSpellCheckStatus(document?: TextDocument) {\n    if (!document) return;\n\n    sbCheck.text = statusText;\n    sbCheck.isProgress = true;\n    sbCheck.show();\n\n    const { uri } = document;\n    client.isSpellCheckEnabled(document)\n      .then(async (response) => {\n        sbCheck.isProgress = false;\n        const doc = await coc.workspace.document;\n        const document = doc && doc.textDocument;\n        const docUri = document && document.uri;\n        if (docUri !== uri) {\n          return;\n        }\n        const { languageEnabled = false, fileEnabled = false } = response;\n        const isChecked = languageEnabled && fileEnabled;\n        if (isChecked) {\n          sbCheck.show();\n        } else {\n          sbCheck.hide();\n        }\n      });\n  }\n\n  function updateStatusBar(doc?: TextDocument) {\n    if (!isSupportedDoc(doc)) {\n      sbCheck.hide();\n      return;\n    }\n    const document = doc;\n    const settings: CSpellUserSettings = coc.workspace.getConfiguration().get('cSpell') as CSpellUserSettings;\n    const { enabled, showStatus = true } = settings;\n\n    if (!showStatus) {\n      sbCheck.hide();\n      return;\n    }\n\n    if (enabled) {\n      updateStatusBarWithSpellCheckStatus(document);\n    } else {\n      sbCheck.hide();\n    }\n  }\n\n  async function onDidChange() {\n    const doc = await coc.workspace.document;\n    updateStatusBar(doc && doc.textDocument);\n  }\n\n  context.subscriptions.push(\n    coc.workspace.registerAutocmd({\n      event: 'BufEnter',\n      request: false,\n      callback: onDidChange,\n    }),\n    coc.workspace.onDidChangeConfiguration(onDidChange),\n    sbCheck\n  );\n\n  onDidChange();\n}\n"
  },
  {
    "path": "src/util/commonPrefix.ts",
    "content": "\nexport function commonPrefix(values: string[]): string {\n    if (!values.length) return '';\n    const min = values.reduce((min, curr) => (min <= curr ? min : curr));\n    const max = values.reduce((max, curr) => (max >= curr ? max : curr));\n    return pfx(min, max);\n}\n\nfunction pfx(a: string, b: string): string {\n    const s = Math.min(a.length, b.length);\n    let i = 0;\n    while (i < s && a[i] === b[i]) {\n        i++;\n    }\n    return a.slice(0, i);\n}"
  },
  {
    "path": "src/util/index.ts",
    "content": "export * from './util';\nexport * from './uriHelper';\n"
  },
  {
    "path": "src/util/pipe.ts",
    "content": "\nexport function defaultTo<T>(value: T): (v: T | undefined) => T {\n    return (v: T | undefined) => v === undefined ? value : v;\n}\n\nexport type Nested<T, K extends keyof T> = Exclude<T[K], undefined>;\nexport type NestedKey<T, K extends keyof T> = keyof Nested<T, K>;\n\nexport function extract<T, K extends keyof T>(key: K): (t: T | undefined) => T[K] | undefined;\nexport function extract<T, K extends keyof T, K2 extends NestedKey<T, K>>(key: K, k2: K2): (t: T | undefined) => Nested<T, K>[K2] | undefined;\nexport function extract<T, K extends keyof T, K2 extends NestedKey<T, K>, K3 extends NestedKey<Nested<T, K>, K2>>(key: K, k2: K2, k3: K3): (t: T | undefined) => Nested<Nested<T, K>, K2>[K3] | undefined;\nexport function extract<T, K extends keyof T, K2 extends NestedKey<T, K>, K3 extends NestedKey<Nested<T, K>, K2>, K4 extends NestedKey<Nested<Nested<T, K>, K2>, K3>>(key: K, k2: K2, k3: K3, k4: K4): (t: T | undefined) => Nested<Nested<Nested<T, K>, K2>, K3>[K4] | undefined;\nexport function extract<T, K extends keyof T>(key: K): (t: T | undefined) => T[K] | undefined {\n    if (arguments.length > 1) {\n        const args = [...arguments];\n        return (t: T | undefined) => {\n            let v = t as any;\n            for (const k of args) {\n                v = v === undefined ? undefined : v[k];\n            }\n            return v;\n        };\n    }\n    return (t: T | undefined) => t === undefined ? undefined : t[key];\n}\n\nexport function map<T, R>(fn: (t: T) => R): (t: T | undefined) => R | undefined {\n    return (t: T | undefined) => t === undefined ? undefined : fn(t);\n}\n\nexport function pipe<T>(t: T): T;\nexport function pipe<T, R>(t: T, fn: (t: T) => R): R;\nexport function pipe<T, R, S>(t: T, fn: (t: T) => R, fn2: (t: R) => S): S;\nexport function pipe<T, R, S, A>(t: T, fn: (t: T) => R, fn2: (t: R) => S, fn3: (t: S) => A): A;\nexport function pipe<T, R, S, A, B>(t: T, fn: (t: T) => R, fn2: (t: R) => S, fn3: (t: S) => A, fn4: (t: A) => B): B;\nexport function pipe<T, R, S, A, B, C>(t: T, fn: (t: T) => R, fn2: (t: R) => S, fn3: (t: S) => A, fn4: (t: A) => B, fn5: (t: B) => C): C;\nexport function pipe<T>(t: T): T {\n    if (arguments.length > 1) {\n        const fns = [...arguments].slice(1) as ((v: any) => any)[];\n        let v = t as any;\n        for (const fn of fns) {\n            v = fn(v);\n        }\n        return v;\n    }\n    return t;\n}\n"
  },
  {
    "path": "src/util/uriHelper.ts",
    "content": "import { TextDocument } from 'vscode-languageserver-protocol';\nimport * as coc from 'coc.nvim';\n\nexport const supportedSchemes = ['file', 'untitled'];\nexport const setOfSupportedSchemes = new Set(supportedSchemes);\n\nexport function isSupportedUri(uri?: coc.Uri): boolean {\n    return !!uri && setOfSupportedSchemes.has(uri.scheme);\n}\n\nexport function isSupportedDoc(doc?: TextDocument): boolean {\n    return !!doc && isSupportedUri(coc.Uri.parse(doc.uri));\n}\n"
  },
  {
    "path": "src/util/util.ts",
    "content": "\nexport function unique<T>(values: T[]): T[] {\n    return [...(new Set<T>(values))];\n}\n\nexport function uniqueFilter<T>() {\n    const seen = new Set<T>();\n    return (v: T) => !!(!seen.has(v) && seen.add(v));\n}\n\nexport function freqCount<T>(values: T[]): [T, number][] {\n    const map = new Map<T, number>();\n    values.forEach(v => map.set(v, (map.get(v) || 0) + 1));\n    return [...map.entries()];\n}\n\nexport type Maybe<T> = T | undefined;\n"
  },
  {
    "path": "src/util/watcher.ts",
    "content": "const watch = require('node-watch');\n\nexport type Events = 'update' | 'remove' | 'error';\n\ninterface Watcher {\n  close: () => void;\n}\n\nexport type Callback = (name: string, event: Events) => void;\n\ninterface FileWatcher {\n  watcher: Watcher;\n  callbacks: Set<Callback>;\n}\n\nconst watchedFiles = new Map<string, FileWatcher>();\n\nfunction listener(event: Events, name: string) {\n  const watcher = watchedFiles.get(name);\n  if (watcher) {\n    watcher.callbacks.forEach(fn => fn(name, event));\n  }\n}\n\nexport function isWatching(fileName: string) {\n  return !!watchedFiles.get(fileName);\n}\n\nexport function stopWatching(fileName: string) {\n  const watcher = watchedFiles.get(fileName);\n  if (watcher) {\n    watchedFiles.delete(fileName);\n    watcher.watcher.close();\n  }\n}\n\nexport function add(fileName: string, callback: Callback) {\n  if (!watchedFiles.has(fileName)) {\n    watchedFiles.set(fileName, {\n      watcher: watch(fileName, listener) as Watcher,\n      callbacks: new Set<Callback>(),\n    });\n  }\n  const watcher = watchedFiles.get(fileName);\n  watcher!.callbacks.add(callback);\n}\n\nexport function dispose() {\n  for (const w of watchedFiles.values()) {\n    w.watcher.close();\n  }\n  watchedFiles.clear();\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2017\",\n    \"strictNullChecks\": true,\n    \"strict\": true,\n    \"strictFunctionTypes\": false,\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"outDir\": \"out\",\n    \"sourceMap\": false,\n    \"declaration\": false,\n    \"declarationMap\": false,\n    \"rootDir\": \"src\"\n  },\n  \"include\": [\n    \"src\"\n  ],\n  \"exclude\": [\n    \"./out\"\n  ]\n}\n"
  },
  {
    "path": "tslint.json",
    "content": "{\n  \"rules\": {\n    \"class-name\": true,\n    \"comment-format\": [\n      true,\n      \"check-space\"\n    ],\n    \"indent\": [\n      true,\n      \"spaces\"\n    ],\n    \"no-duplicate-variable\": true,\n    \"no-eval\": true,\n    \"no-internal-module\": true,\n    \"no-trailing-whitespace\": true,\n    \"no-var-keyword\": true,\n    \"one-line\": [\n      true,\n      \"check-open-brace\",\n      \"check-whitespace\"\n    ],\n    \"quotemark\": [\n      true,\n      \"single\",\n      \"jsx-double\",\n      \"avoid-escape\"\n    ],\n    \"semicolon\": [\n      true,\n      \"always\"\n    ],\n    \"triple-equals\": [\n      true,\n      \"allow-null-check\"\n    ],\n    \"typedef-whitespace\": [\n      true,\n      {\n        \"call-signature\": \"nospace\",\n        \"index-signature\": \"nospace\",\n        \"parameter\": \"nospace\",\n        \"property-declaration\": \"nospace\",\n        \"variable-declaration\": \"nospace\"\n      }\n    ],\n    \"variable-name\": [\n      true,\n      \"ban-keywords\"\n    ],\n    \"whitespace\": [\n      true,\n      \"check-branch\",\n      \"check-decl\",\n      \"check-operator\",\n      \"check-separator\",\n      \"check-type\"\n    ],\n    \"max-line-length\": [\n      true,\n      140\n    ],\n    \"no-unused-variable\": true\n  }\n}\n"
  },
  {
    "path": "webpack.config.js",
    "content": "const path = require('path');\n\n/** @type {import('webpack').Configuration} */\nmodule.exports = {\n  entry: {\n    index: './src/index.ts'\n  },\n  target: 'node',\n  mode: 'production',\n  resolve: {\n    mainFields: ['module', 'main'],\n    extensions: ['.js', '.ts'],\n  },\n  externals: {\n    'coc.nvim': 'commonjs coc.nvim',\n    'cspell-dict-vimlang': 'commonjs cspell-dict-vimlang',\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.ts$/,\n        exclude: /node_modules/,\n        use: [\n          {\n            loader: 'ts-loader',\n          },\n        ],\n      },\n    ],\n  },\n  output: {\n    path: path.join(__dirname, 'out'),\n    filename: '[name].js',\n    libraryTarget: 'commonjs',\n  },\n  plugins: [],\n  node: {\n    __dirname: false,\n    __filename: false,\n  },\n};\n"
  }
]